Version bump for last commit; now at v2.0.23.
[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-2020 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
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
170                         if (*AnEXVAL > 0xFFF && *AnEXVAL < -4096)
171                                 return error("immediate short addressing mode forced but address is bigger than $FFF");
172
173                         if ((int32_t)*AnEXVAL <= 0xFF && (int32_t)*AnEXVAL > -0x100)
174                         {
175                                 *am = M_DSPIM8;
176                                 return OK;
177                         }
178
179                         *am = M_DSPIM12;
180                         return OK;
181                 }
182                 else if (*tok == '>')
183                 {
184                         // Immediate Long Addressing Mode Force Operator
185                         tok++;
186
187                         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
188                                 return ERROR;
189
190                         if ((int32_t)*AnEXVAL > 0xFFFFFF || (int32_t)*AnEXVAL < -0xFFFFFF)
191                                 return error("long immediate is bigger than $FFFFFF");
192
193                         *am = M_DSPIM;
194                         return OK;
195                 }
196
197                 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
198                         return ERROR;
199
200                 if (*AnEXATTR & DEFINED)
201                 {
202                         if ((int32_t)*AnEXVAL < 0x100 && (int32_t)*AnEXVAL >= -0x100)
203                         {
204                                 *AnEXVAL &= 0xFF;
205                                 *am = M_DSPIM8;
206                         }
207                         else if (*AnEXVAL < 0x1000)
208                                 *am = M_DSPIM12;
209                         else
210                                 *am = M_DSPIM;
211                 }
212                 else
213                 {
214                         // We have no clue what size our immediate will be
215                         // so we have to assume the worst
216                         *am = M_DSPIM;
217                 }
218
219                 return OK;
220         }
221         else if (*tok >= KW_X0 && *tok <= KW_Y1)
222         {
223                 *am = M_ALU24;
224                 *areg = *tok++;
225                 return OK;
226         }
227         else if (*tok == KW_X && *(tok + 1) == ':')
228         {
229                 tok = tok + 2;
230
231                 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
232                 {
233                         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
234                                 return ERROR;
235
236                         if (*AnEXATTR & DEFINED)
237                         {
238                                 if (*AnEXVAL > 0xFFFFFF)
239                                         return error("long address is bigger than $FFFFFF");
240
241                                 *memspace = 0 << 6;     // Mark we're on X memory space
242
243                                 // Check if value is between $FFC0 and $FFFF, AKA X:pp
244                                 uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6));  // Sign extend 6 to 32 bits
245
246                                 if ((temp >= 0xFFFFFFC0                      /* Check for 32bit sign extended number */
247                                         && ((int32_t)*AnEXVAL < 0))              /* Check if 32bit signed number is negative*/
248                                         || (*AnEXVAL < 0xFFFF && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
249                                 {
250                                         *AnEXVAL = temp;
251                                         *am = M_DSPPP;
252                                         *memspace = 0 << 6;          // Mark we're on X memory space
253                                         *perspace = 0 << 16;         // Mark we're on X peripheral space
254                                         *areg = *AnEXVAL & 0x3F;     // Since this is only going to get used in dsp_ea_imm5...
255                                         return OK;
256                                 }
257
258                                 // If the symbol/expression is defined then check for valid range.
259                                 // Otherwise the value had better fit or Fixups will bark!
260                                 if (*AnEXVAL > 0x3F)
261                                 {
262                                         *am = M_DSPEA;
263                                         *areg = DSP_EA_ABS;
264                                 }
265                                 else
266                                 {
267                                         *am = M_DSPAA;
268                                 }
269                         }
270                         else
271                         {
272                                 // Assume the worst
273                                 *memspace = 0 << 6;     // Mark we're on X memory space
274                                 *am = M_DSPEA;
275                                 *areg = DSP_EA_ABS;
276                         }
277
278                         return OK;
279                 }
280                 else if (*tok == '<')
281                 {
282                         // X:aa
283                         // Short Addressing Mode Force Operator in the case of '<'
284                         tok++;
285
286                         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
287                                 return ERROR;
288
289                         // If the symbol/expression is defined then check for valid range.
290                         // Otherwise the value had better fit or Fixups will bark!
291                         if (*AnEXATTR & DEFINED)
292                         {
293                                 if (*AnEXVAL > 0x3F)
294                                         return error("short addressing mode forced but address is bigger than $3F");
295                         }
296                         else
297                         {
298                                 // Mark it as a fixup
299                                 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
300                         }
301
302                         *am = M_DSPAA;
303                         *memspace = 0 << 6;     // Mark we're on X memory space
304                         *areg = (int)*AnEXVAL;     // Since this is only going to get used in dsp_ea_imm5...
305                         return OK;
306                 }
307                 else if (*tok == '>')
308                 {
309                         // Long Addressing Mode Force Operator
310                         tok++;
311
312                         if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
313                         {
314                                 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
315                                         return ERROR;
316
317                                 if (*AnEXATTR&DEFINED)
318                                 {
319                                         if (*AnEXVAL > 0xFFFFFF)
320                                                 return error("long address is bigger than $FFFFFF");
321
322                                         *memspace = 0 << 6;     // Mark we're on X memory space
323                                         *am = M_DSPEA;
324                                         *areg = DSP_EA_ABS;
325                                 }
326                                 else
327                                 {
328                                         // Assume the worst
329                                         *memspace = 0 << 6;     // Mark we're on X memory space
330                                         *am = M_DSPEA;
331                                         *areg = DSP_EA_ABS;
332                                 }
333                                 return OK;
334                         }
335                 }
336                 else if (*tok == SHL)  // '<<'
337                 {
338                         // I/O Short Addressing Mode Force Operator
339                         // X:pp
340                         tok++;
341
342                         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
343                                 return ERROR;
344
345                         // If the symbol/expression is defined then check for valid range.
346                         // Otherwise the value had better fit or Fixups will bark!
347                         if (*AnEXATTR & DEFINED)
348                         {
349                                 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6));  // Sign extend 6 to 32 bits
350
351                                 if (*AnEXVAL < 0xFFFFFFC0)
352                                         return error("I/O Short Addressing Mode addresses must be between $FFC0 and $FFFF");
353                         }
354
355                         *am = M_DSPPP;
356                         *memspace = 0 << 6;          // Mark we're on X memory space
357                         *perspace = 0 << 16;         // Mark we're on X peripheral space
358                         *areg = *AnEXVAL & 0x3f;     // Since this is only going to get used in dsp_ea_imm5...
359                         return OK;
360                 }
361
362                 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
363                 {
364                         // TODO: what if we need M_DSPAA here????
365                         *memspace = 0 << 6;     // Mark we're on X memory space
366                         *am = M_DSPEA;
367                         return OK;
368                 }
369                 else
370                         return ERROR;
371         }
372         else if (*tok == KW_Y && *(tok + 1) == ':')
373         {
374                 tok = tok + 2;
375
376                 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
377                 {
378                         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
379                                 return ERROR;
380
381                         if (*AnEXVAL > 0xFFFFFF)
382                                 return error("long address is bigger than $FFFFFF");
383
384                         *memspace = 1 << 6;     // Mark we're on Y memory space
385
386                         // Check if value is between $ffc0 and $ffff, AKA Y:pp
387                         uint32_t temp = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6));  // Sign extend 6 to 32 bits
388
389                         if ((temp >= 0xFFFFFFC0                         /* Check for 32bit sign extended number */
390                                 && ((int32_t)*AnEXVAL < 0))                 /* Check if 32bit signed number is negative*/
391                                 || (*AnEXVAL < 0xFFFF && *AnEXVAL >= 0x8000)) /* Check if 16bit number is negative*/
392                         {
393                                 *AnEXVAL = temp;
394                                 *am = M_DSPPP;
395                                 *perspace = 1 << 16;         // Mark we're on X peripheral space
396                                 *areg = *AnEXVAL & 0x3F;     // Since this is only going to get used in dsp_ea_imm5...
397                                 return OK;
398                         }
399
400                         // If the symbol/expression is defined then check for valid range.
401                         // Otherwise the value had better fit or Fixups will bark!
402                         if (*AnEXATTR & DEFINED)
403                         {
404                                 if (*AnEXVAL > 0x3F)
405                                 {
406                                         *am = M_DSPEA;
407                                         *areg = DSP_EA_ABS;
408                                 }
409                                 else
410                                 {
411                                         *am = M_DSPAA;
412                                 }
413                         }
414                         else
415                         {
416                                 *am = M_DSPEA;
417                                 *areg = DSP_EA_ABS;
418                         }
419
420                         return OK;
421                 }
422                 else if (*tok == '<')
423                 {
424                         // Y:aa
425                         // Short Addressing Mode Force Operator in the case of '<'
426                         tok++;
427
428                         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
429                                 return ERROR;
430
431                         // If the symbol/expression is defined then check for valid range.
432                         // Otherwise the value had better fit or Fixups will bark!
433                         if (*AnEXATTR & DEFINED)
434                         {
435                                 if (*AnEXVAL > 0x3F)
436                                 {
437                                         warn("short addressing mode forced but address is bigger than $3F - switching to long");
438                                         *am = M_DSPEA;
439                                         *memspace = 1 << 6;     // Mark we're on Y memory space
440                                         *areg = DSP_EA_ABS;
441                                         return OK;
442                                 }
443                         }
444                         else
445                         {
446                                 // Mark it as a fixup
447                                 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
448                         }
449
450                         *am = M_DSPAA;
451                         *memspace = 1 << 6;     // Mark we're on Y memory space
452                         *areg = (int)*AnEXVAL;      // Since this is only going to get used in dsp_ea_imm5...
453                         return OK;
454                 }
455                 else if (*tok == '>')
456                 {
457                         // Long Addressing Mode Force Operator
458                         tok++;
459
460                         if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
461                         {
462                                 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
463                                         return ERROR;
464
465                                 if (*AnEXATTR&DEFINED)
466                                 {
467                                         if (*AnEXVAL > 0xFFFFFF)
468                                                 return error("long address is bigger than $FFFFFF");
469
470                                         *memspace = 1 << 6;     // Mark we're on Y memory space
471
472                                         *am = M_DSPEA;
473                                         *areg = DSP_EA_ABS;
474                                 }
475                                 else
476                                 {
477                                         // Assume the worst
478                                         *memspace = 1 << 6;     // Mark we're on Y memory space
479                                         *am = M_DSPEA;
480                                         *areg = DSP_EA_ABS;
481                                 }
482                                 return OK;
483                         }
484                 }
485                 else if (*tok == SHL)  // '<<'
486                 {
487                         // I/O Short Addressing Mode Force Operator
488                         // Y:pp
489                         tok++;
490
491                         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
492                                 return ERROR;
493
494                         // If the symbol/expression is defined then check for valid range.
495                         // Otherwise the value had better fit or Fixups will bark!
496                         if (*AnEXATTR & DEFINED)
497                         {
498                                 *AnEXVAL = (LONG)(((int32_t)(((uint32_t)*AnEXVAL) << (32 - 6))) >> (32 - 6));  // Sign extend 6 to 32 bits
499
500                                 if (*AnEXVAL < 0xFFFFFFC0)
501                                         return error("I/O Short Addressing Mode addresses must be between $FFE0 and $1F");
502                         }
503
504                         *am = M_DSPPP;
505                         *memspace = 1 << 6;          // Mark we're on Y memory space
506                         *perspace = 1 << 16;         // Mark we're on Y peripheral space
507                         *areg = *AnEXVAL & 0x3F;     // Since this is only going to get used in dsp_ea_imm5...
508                         return OK;
509                 }
510
511                 if ((*areg = checkea(0, X_ERRORS)) != ERROR)
512                 {
513                         *memspace = 1 << 6;     // Mark we're on Y memory space
514                         *am = M_DSPEA;
515                         return OK;
516                 }
517                 else
518                         return ERROR;
519                 // TODO: add absolute address checks
520         }
521         else if ((*tok >= KW_X) && (*tok <= KW_Y))
522         {
523                 *am = M_INP48;
524                 *areg = *tok++;
525                 return OK;
526         }
527         else if ((*tok >= KW_M0) && (*tok <= KW_M7))
528         {
529                 *am = M_DSPM;
530                 *areg = (*tok++) & 7;
531                 return OK;
532         }
533         else if ((*tok >= KW_R0) && (*tok <= KW_R7))
534         {
535                 *am = M_DSPR;
536                 *areg = (*tok++) - KW_R0;
537                 return OK;
538         }
539         else if ((*tok >= KW_N0) && (*tok <= KW_N7))
540         {
541                 *am = M_DSPN;
542                 *areg = (*tok++) & 7;
543                 return OK;
544         }
545         else if ((*tok == KW_A0) || (*tok == KW_A1) || (*tok == KW_B0)
546                 || (*tok == KW_B1))
547         {
548                 *am = M_ACC24;
549                 *areg = *tok++;
550                 return OK;
551         }
552         else if ((*tok == KW_A2) || (*tok == KW_B2))
553         {
554                 *am = M_ACC8;
555                 *areg = *tok++;
556                 return OK;
557         }
558         else if ((*tok == '-') && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
559         {
560                 // '-X0', '-Y0', '-X1' or '-Y1', used in multiplications
561                 tok++;
562
563                 // Check to see if this is the first operand
564                 if (operand != 0)
565                         return error("-x0/-x1/-y0/-y1 only allowed in the first operand");
566
567                 *am = M_ALU24;
568                 *areg = *tok++;
569                 dsp_k = 1 << 2;
570                 return OK;
571         }
572         else if (*tok == '+' && (*(tok + 1) == KW_X0 || *(tok + 1) == KW_X1 || *(tok + 1) == KW_Y0 || *(tok + 1) == KW_Y1))
573         {
574                 // '+X0', '+Y0', '+X1' or '+Y1', used in multiplications
575                 tok++;
576
577                 // Check to see if this is the first operand
578                 if (operand != 0)
579                         return error("+x0/+x1/+y0/+y1 only allowed in the first operand");
580
581                 *am = M_ALU24;
582                 *areg = *tok++;
583                 dsp_k = 0 << 2;
584                 return OK;
585         }
586         else if (*tok == '(' || *tok == '-')
587         {
588                 // Could be either an expression or ea mode
589                 if (*tok + 1 == SYMBOL)
590                 {
591                         tok++;
592
593                         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
594                                 return ERROR;
595
596                         *am = M_DSPIM;
597                         return OK;
598                 }
599
600                 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
601                 {
602                         *am = M_DSPEA;
603                         return OK;
604                 }
605                 else
606                         return ERROR;
607
608                 // TODO: add absolute address checks
609                 return error("internal assembler error: parmode checking for '(' and '-' does not have absolute address checks yet!");
610         }
611         else if (*tok == KW_P && *(tok + 1) == ':')
612         {
613                 tok = tok + 2;
614
615                 if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
616                 {
617                         // Address
618                         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
619                                 return ERROR;
620
621                         if (*AnEXVAL > 0xFFFFFF)
622                                 return error("long address is bigger than $FFFFFF");
623
624                         if (*AnEXVAL > 0x3F)
625                         {
626                                 *am = M_DSPEA;
627                                 *areg = DSP_EA_ABS;
628                         }
629                         else
630                         {
631                                 *areg = (int)*AnEXVAL;     // Lame, but what the hell
632                                 *am = M_DSPAA;
633                         }
634
635                         return OK;
636                 }
637                 else if (*tok == '<')
638                 {
639                         // X:aa
640                         // Short Addressing Mode Force Operator in the case of '<'
641                         tok++;
642
643                         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
644                                 return ERROR;
645
646                         if (*AnEXVAL > 0x3F)
647                                 return error("short addressing mode forced but address is bigger than $3F");
648
649                         *am = M_DSPAA;
650                         *areg = (int)*AnEXVAL;     // Since this is only going to get used in dsp_ea_imm5...
651                         return OK;
652                 }
653                 else if (*tok == '>')
654                 {
655                         // Long Addressing Mode Force Operator
656                         tok++;
657
658                         // Immediate Short Addressing Mode Force Operator
659                         if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
660                                 return ERROR;
661
662                         if (*AnEXATTR & DEFINED)
663                         {
664                                 if (*AnEXVAL > 0xFFFFFF)
665                                         return error("long address is bigger than $FFFFFF");
666                         }
667
668                         *am = M_DSPEA;
669                         *areg = DSP_EA_ABS;
670                         return OK;
671                 }
672
673                 if ((*areg = checkea(0, P_ERRORS)) != ERROR)
674                 {
675                         *am = M_DSPEA;
676                         return OK;
677                 }
678                 else
679                         return ERROR;
680         }
681         else if (*tok == SHL)
682         {
683                 // I/O Short Addressing Mode Force Operator
684                 tok++;
685
686                 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
687                         return ERROR;
688
689                 if (*AnEXVAL > 0xFFF)
690                         return error("I/O short addressing mode forced but address is bigger than $FFF");
691
692                 *am = M_DSPABS06;
693                 return OK;
694         }
695         else if (*tok == '<')
696         {
697                 // Short Addressing Mode Force Operator
698                 tok++;
699
700                 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
701                         return ERROR;
702
703                 if (*AnEXATTR & DEFINED)
704                 {
705                         if (*AnEXVAL > 0xFFF)
706                                 return error("short addressing mode forced but address is bigger than $FFF");
707                 }
708
709                 *am = M_DSPABS12;
710                 return OK;
711         }
712         else if (*tok == '>')
713         {
714                 // Long Addressing Mode Force Operator
715                 tok++;
716
717                 // Immediate Short Addressing Mode Force Operator
718                 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
719                         return ERROR;
720
721                 if (*AnEXATTR & DEFINED)
722                 {
723                         if (*AnEXVAL > 0xFFFFFF)
724                                 return error("long address is bigger than $FFFFFF");
725                 }
726
727                 *am = M_DSPEA;
728                 *areg = DSP_EA_ABS;
729                 return OK;
730         }
731         else if (*tok == KW_PC || *tok == KW_CCR || *tok == KW_SR || *tok == KW_SP || (*tok >= KW_MR&&*tok <= KW_SS))
732         {
733                 *areg = *tok++;
734                 *am = M_DSPPCU;
735                 return OK;
736         }
737         // expr
738         else
739         {
740                 if (expr(AnEXPR, AnEXVAL, AnEXATTR, AnESYM) != OK)
741                         return ERROR;
742
743                 // We'll store M_DSPEA_ABS in areg and if we have
744                 // any extra info, it'll go in am
745                 if (*AnEXATTR & DEFINED)
746                 {
747                         *areg = DSP_EA_ABS;
748
749                         if (*AnEXVAL < 0x1000)
750                                 *am = M_DSPABS12;
751                         else if (*AnEXVAL < 0x10000)
752                                 *am = M_DSPABS16;
753                         else if (*AnEXVAL < 0x1000000)
754                                 *am = M_DSPABS24;
755                         else
756                                 return error("address must be smaller than $1000000");
757
758                         return OK;
759                 }
760                 else
761                 {
762                         // Well, we have no opinion on the expression's size, so let's assume the worst
763                         *areg = DSP_EA_ABS;
764                         *am = M_DSPABS24;
765                         return OK;
766                 }
767         }
768
769         return error("internal assembler error: Please report this error message: 'reached the end of dsp_parmode' with the line of code that caused it. Thanks, and sorry for the inconvenience");   // Something bad happened
770 }
771
772
773 //
774 // Parse all addressing modes except parallel moves
775 //
776 int dsp_amode(int maxea)
777 {
778         LONG dummy;
779         // Initialize global return values
780         nmodes = dsp_a0reg = dsp_a1reg = 0;
781         dsp_am0 = dsp_am1 = M_AM_NONE;
782         dsp_a0expr[0] = dsp_a1expr[0] = ENDEXPR;
783         dsp_a0exval = 0;
784         dsp_a1exval = 0;
785         dsp_a0exattr = dsp_a1exattr = 0;
786         dsp_a0esym = dsp_a1esym = (SYM *)NULL;
787         dsp_a0memspace = dsp_a1memspace = -1;
788         dsp_a0perspace = dsp_a1perspace = -1;
789         dsp_k = 0;
790
791         // If at EOL, then no addr modes at all
792         if (*tok == EOL)
793                 return 0;
794
795         if (dsp_parmode(&dsp_am0, &dsp_a0reg, dsp_a0expr, &dsp_a0exval, &dsp_a0exattr, &dsp_a0esym, &dsp_a0memspace, &dsp_a0perspace, 0) == ERROR)
796                 return ERROR;
797
798
799         // If caller wants only one mode, return just one (ignore comma);
800         // If there is no second addressing mode (no comma), then return just one anyway.
801         nmodes = 1;
802
803         if (*tok != ',')
804         {
805                 if (dsp_k != 0)
806                         return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
807
808                 return 1;
809         }
810
811         // Eat the comma
812         tok++;
813
814         // Parse second addressing mode
815         if (dsp_parmode(&dsp_am1, &dsp_a1reg, dsp_a1expr, &dsp_a1exval, &dsp_a1exattr, &dsp_a1esym, &dsp_a1memspace, &dsp_a1perspace, 1) == ERROR)
816                 return ERROR;
817
818         if (maxea == 2 || *tok == EOL)
819         {
820                 if (dsp_k != 0)
821                         return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
822
823                 nmodes = 2;
824                 return 2;
825         }
826
827         if (*tok == ',')
828         {
829                 // Only MAC-like or jsset/clr/tst/chg instructions here
830                 tok++;
831                 if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
832                         return ERROR;
833                 if (maxea == 3)
834                         return 3;
835                 if (*tok != EOL)
836                         return error(extra_stuff);
837                 nmodes = 3;
838                 return 3;
839
840         }
841
842         // Only Tcc instructions here, and then only those that accept 4 operands
843
844         if (dsp_parmode(&dsp_am2, &dsp_a2reg, dsp_a2expr, &dsp_a2exval, &dsp_a2exattr, &dsp_a2esym, &dummy, &dummy, 2) == ERROR)
845                 return ERROR;
846
847         if (*tok++ != ',')
848                 return error("expected 4 parameters");
849
850         if (dsp_parmode(&dsp_am3, &dsp_a3reg, dsp_a3expr, &dsp_a3exval, &dsp_a3exattr, &dsp_a3esym, &dummy, &dummy, 3) == ERROR)
851                 return ERROR;
852
853         if (*tok == EOL)
854         {
855                 if (dsp_k != 0)
856                         return error("-x0/-x1/-y0/-y1 only allowed in multiply operations");
857
858                 nmodes = 4;
859                 return 4;
860         }
861         else
862         {
863                 // Tcc instructions do not support parallel moves, so any remaining tokens are garbage
864                 return error(extra_stuff);
865         }
866
867         return error("internal assembler error: Please report this error message: 'reached the end of dsp_amode' with the line of code that caused it. Thanks, and sorry for the inconvenience");   //Something bad happened
868 }
869
870
871 //
872 // Helper function which gives us the encoding of a DSP register
873 //
874 static inline int SDreg(int reg)
875 {
876         if (reg >= KW_X0 && reg <= KW_N7)
877                 return reg & 0xFF;
878         else if (reg >= KW_A0&&reg <= KW_A2)
879                 return (8 >> (reg & 7)) | 8;
880         else //if (reg>=KW_R0&&reg<=KW_R7)
881                 return reg - KW_R0 + 16;
882         // Handy map for the above:
883         // (values are of course taken from keytab)
884         // Register | Value | Return value
885         //      x0      | 260   | 4
886         //      x1      | 261   | 5
887         //      y0      | 262   | 6
888         //      y1      | 263   | 7
889         //      b0      | 265   | 8
890         //      b2      | 267   | 9
891         //      b1      | 269   | 10
892         //      a       | 270   | 14
893         //      b       | 271   | 15
894         //      n0      | 280   | 24
895         //      n1      | 281   | 25
896         //      n2      | 282   | 26
897         //      n3      | 283   | 27
898         //      n4      | 284   | 28
899         //      n5      | 285   | 29
900         //      n6      | 286   | 30
901         //      n7      | 287   | 31
902         //      a0          | 136   | 0
903         //      a1          | 137   | 1
904         //      a2      | 138   | 2
905         //      r0          | 151   | 16
906         //      r1          | 152   | 17
907         //      r2          | 153   | 18
908         //      r3          | 154   | 19
909         //      r4          | 155   | 20
910         //      r5          | 156   | 21
911         //      r6          | 157   | 22
912         //      r7          | 158   | 23
913 }
914
915
916 //
917 // Check for X:Y: parallel mode syntax
918 //
919 static inline LONG check_x_y(LONG ea1, LONG S1)
920 {
921         LONG inst;
922         LONG eax_temp, eay_temp;
923         LONG D1, D2, S2, ea2;
924         LONG K_D1, K_D2;
925         LONG w = 1 << 7;                // S1=0, D1=1<<14
926
927         if ((ea1 & 0x38) == DSP_EA_POSTINC || (ea1 & 0x38) == DSP_EA_POSTINC1 ||
928                 (ea1 & 0x38) == DSP_EA_POSTDEC1 || (ea1 & 0x38) == DSP_EA_NOUPD)
929         {
930                 switch (ea1 & 0x38)
931                 {
932                 case DSP_EA_POSTINC:  ea1 = (ea1 & (~0x38)) | 0x8; break;
933                 case DSP_EA_POSTINC1: ea1 = (ea1 & (~0x38)) | 0x18; break;
934                 case DSP_EA_POSTDEC1: ea1 = (ea1 & (~0x38)) | 0x10; break;
935                 case DSP_EA_NOUPD:    ea1 = (ea1 & (~0x38)) | 0x00; break;
936                 }
937
938                 if (S1 == 0)
939                 {
940                         // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay'
941                         // Check for D1
942                         switch (K_D1 = *tok++)
943                         {
944                         case KW_X0: D1 = 0 << 10; break;
945                         case KW_X1: D1 = 1 << 10; break;
946                         case KW_A:  D1 = 2 << 10; break;
947                         case KW_B:  D1 = 3 << 10; break;
948                         default:    return error("unrecognised X:Y: parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
949                         }
950                 }
951                 else
952                 {
953                         // 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
954                         w = 0;
955
956                         switch (S1)
957                         {
958                         case 4:  D1 = 0 << 10; break;
959                         case 5:  D1 = 1 << 10; break;
960                         case 14: D1 = 2 << 10; break;
961                         case 15: D1 = 3 << 10; break;
962                         default: return error("unrecognised X:Y: parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:eax'");
963                         }
964                 }
965
966                 if (*tok == KW_Y)
967                 {
968                         tok++;
969                         // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
970                         if (*tok++ != ':')
971                                 return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
972
973                         if (*tok++ == '(')
974                         {
975                                 if (*tok >= KW_R0 && *tok <= KW_R7)
976                                 {
977                                         ea2 = (*tok++ - KW_R0);
978
979                                         if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
980                                                 return error("unrecognised X:Y: parallel move syntax: eax and eay register banks must be different in 'X:ea,D1/S1,X:ea Y:eay,D2'");
981                                 }
982                                 else
983                                         return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea Y:('");
984
985                                 // If eax register is r0-r3 then eay register is r4-r7.
986                                 // Encode that to 2 bits (i.e. eay value is 0-3)
987                                 eax_temp = (ea2 & 3) << 5;  // Store register temporarily
988
989                                 if (*tok++ != ')')
990                                         return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea Y:(Rn'");
991
992                                 if (*tok == '+')
993                                 {
994                                         tok++;
995
996                                         if (*tok == ',')
997                                         {
998                                                 // (Rn)+
999                                                 ea2 = 3 << 12;
1000                                                 tok++;
1001                                         }
1002                                         else if (*tok >= KW_N0 && *tok <= KW_N7)
1003                                         {
1004                                                 // (Rn)+Nn
1005                                                 if ((*tok++ & 7) != ea2)
1006                                                         return error("unrecognised X:Y: parallel move syntax(Same register number expected for Rn, Nn in 'X:ea,D1/S1,X:ea Y:(Rn)+Nn,D')");
1007
1008                                                 ea2 = 1 << 12;
1009
1010                                                 if (*tok++ != ',')
1011                                                         return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)+Nn'");
1012                                         }
1013                                         else
1014                                                 return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea Y:(Rn)+'");
1015
1016                                 }
1017                                 else if (*tok == '-')
1018                                 {
1019                                         // (Rn)-
1020                                         ea2 = 2 << 12;
1021                                         tok++;
1022
1023                                         if (*tok++ != ',')
1024                                                 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:(Rn)-'");
1025                                 }
1026                                 else if (*tok++ == ',')
1027                                 {
1028                                         // (Rn)
1029                                         ea2 = 0 << 12;
1030                                 }
1031                                 else
1032                                         return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea Y:eay'");
1033
1034                                 ea2 |= eax_temp; // OR eay back from temp
1035
1036                                 switch (K_D2 = *tok++)
1037                                 {
1038                                 case KW_Y0: D2 = 0 << 8; break;
1039                                 case KW_Y1: D2 = 1 << 8; break;
1040                                 case KW_A:  D2 = 2 << 8; break;
1041                                 case KW_B:  D2 = 3 << 8; break;
1042                                 default:    return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
1043                                 }
1044
1045                                 if (*tok != EOL)
1046                                         return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea Y:eay,D'");
1047
1048                                 if (S1 == 0)
1049                                         if (K_D1 == K_D2)
1050                                                 return error("unrecognised X:Y: parallel move syntax: D1 and D2 cannot be the same in 'X:ea,D1 Y:eay,D2'");
1051
1052                                 inst = B16(11000000, 00000000) | w;
1053                                 inst |= ea1 | D1 | ea2 | D2;
1054                                 return inst;
1055                         }
1056                         else
1057                                 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1058                 }
1059                 else if (*tok == KW_Y0 || *tok == KW_Y1 || *tok == KW_A || *tok == KW_B)
1060                 {
1061                         // 'X:eax,D1 S2,Y:eay' 'S1,X:eax1 S2,Y:eay'
1062                         switch (*tok++)
1063                         {
1064                         case KW_Y0: S2 = 0 << 8; break;
1065                         case KW_Y1: S2 = 1 << 8; break;
1066                         case KW_A:  S2 = 2 << 8; break;
1067                         case KW_B:  S2 = 3 << 8; break;
1068                         default: return error("unrecognised X:Y: parallel move syntax: expected y0, y1, a or b after 'X:ea,D1/S1,X:ea Y:eay,'");
1069                         }
1070
1071                         if (*tok++ != ',')
1072                                 return error("unrecognised X:Y: parallel move syntax: expected ',' after 'X:ea,D1/S1,X:ea S2'");
1073
1074                         if (*tok++ == KW_Y)
1075                         {
1076                                 // 'X:eax,D1 Y:eay,D2' 'S1,X:eax Y:eay,D2'
1077                                 if (*tok++ != ':')
1078                                         return error("unrecognised X:Y: parallel move syntax: expected ':' after 'X:ea,D1/S1,X:ea Y'");
1079
1080                                 if (*tok++ == '(')
1081                                 {
1082                                         if (*tok >= KW_R0 && *tok <= KW_R7)
1083                                         {
1084                                                 ea2 = (*tok++ - KW_R0);
1085
1086                                                 if (((ea1 & 7) < 4 && ea2 < 4) || ((ea1 & 7) >= 4 && ea2 > 4))
1087                                                         return error("unrecognised X:Y: parallel move syntax: eax and eay register banks must be different in 'X:ea,D1/S1,X:ea S2,Y:eay'");
1088                                         }
1089                                         else
1090                                                 return error("unrecognised X:Y: parallel move syntax: expected 'Rn' after 'X:ea,D1/S1,X:ea S2,Y:('");
1091                                         // If eax register is r0-r3 then eay register is r4-r7.
1092                                         // Encode that to 2 bits (i.e. eay value is 0-3)
1093                                         eay_temp = (ea2 & 3) << 5; //Store register temporarily
1094
1095                                         if (*tok++ != ')')
1096                                                 return error("unrecognised X:Y: parallel move syntax: expected ')' after 'X:ea,D1/S1,X:ea S2,Y:(Rn'");
1097
1098                                         if (*tok == '+')
1099                                         {
1100                                                 tok++;
1101
1102                                                 if (*tok == EOL)
1103                                                         // (Rn)+
1104                                                         ea2 = 3 << 12;
1105                                                 else if (*tok >= KW_N0 && *tok <= KW_N7)
1106                                                 {
1107                                                         // (Rn)+Nn
1108                                                         if ((*tok++ & 7) != ea2)
1109                                                                 return error("unrecognised X:Y: parallel move syntax(Same register number expected for Rn, Nn in 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn')");
1110
1111                                                         ea2 = 1 << 12;
1112
1113                                                         if (*tok != EOL)
1114                                                                 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+Nn'");
1115                                                 }
1116                                                 else
1117                                                         return error("unrecognised X:Y: parallel move syntax: expected ',' or 'Nn' after 'X:ea,D1/S1,X:ea S2,Y:(Rn)+'");
1118
1119                                         }
1120                                         else if (*tok == '-')
1121                                         {
1122                                                 // (Rn)-
1123                                                 ea2 = 2 << 12;
1124                                                 tok++;
1125                                                 if (*tok != EOL)
1126                                                         return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:(Rn)-'");
1127                                         }
1128                                         else if (*tok == EOL)
1129                                         {
1130                                                 // (Rn)
1131                                                 ea2 = 0 << 12;
1132                                         }
1133                                         else
1134                                                 return error("unrecognised X:Y: parallel move syntax: expected end-of-line after 'X:ea,D1/S1,X:ea S2,Y:eay'");
1135
1136                                         ea2 |= eay_temp; //OR eay back from temp
1137
1138                                         inst = B16(10000000, 00000000) | w;
1139                                         inst |= (ea1 & 0x1f) | D1 | S2 | ea2;
1140                                         return inst;
1141                                 }
1142                                 else
1143                                         return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' after 'X:ea,D1/S1,X:ea Y:'");
1144                         }
1145                         else
1146                                 return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1147                 }
1148                 else
1149                         return error("unrecognised X:Y: or X:R parallel move syntax: expected Y:, A or B after 'X:ea,D1/S1,X:ea S2,'");
1150         }
1151
1152         return error("unrecognised X:Y: parallel move syntax: expected '(Rn)', '(Rn)+', '(Rn)-', '(Rn)+Nn' in 'X:ea,D1/S1,X:ea'");
1153 }
1154
1155 //
1156 // Parse X: addressing space parallel moves
1157 //
1158 static inline LONG parse_x(const int W, LONG inst, const LONG S1, const int check_for_x_y)
1159 {
1160         int immreg;                                     // Immediate register destination
1161         LONG S2, D1, D2;                        // Source and Destinations
1162         LONG ea1;                                       // ea bitfields
1163         uint32_t termchar = ',';        // Termination character for ea checks
1164         int force_imm = NUM_NORMAL;     // Holds forced immediate value (i.e. '<' or '>')
1165         ea1 = -1;                                       // initialise e1 (useful for some code paths)
1166
1167         if (W == 0)
1168                 termchar = EOL;
1169
1170         if (*tok == '-')
1171         {
1172                 if (tok[1] == CONST || tok[1] == FCONST)
1173                 {
1174                         tok++;
1175                         dspImmedEXVAL = *tok++;
1176                         goto x_check_immed;
1177                 }
1178
1179                 // This could be either -(Rn), -aa or -ea. Check for immediate first
1180                 if (tok[1] == SYMBOL)
1181                 {
1182                         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1183                         {
1184                                 if (S1 != 0)
1185                                 {
1186 x_checkea_right:
1187                                         // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B', 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1188                                         if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_A)
1189                                         {
1190                                                 // 'A,X:ea X0,A'
1191                                                 if (ea1 == DSP_EA_ABS)
1192                                                         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1193
1194                                                 if (S1 != 14)
1195                                                         return error("unrecognised X:R parallel move syntax: S1 can only be a in 'a,X:ea x0,a'");
1196
1197                                                 if (ea1 == -1)
1198                                                         return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'a,X:ea x0,a'");
1199
1200                                                 if (ea1 == B8(00110100))
1201                                                         return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'a,X:ea x0,a'");
1202
1203                                                 inst = B16(00001000, 00000000) | ea1 | (0 << 8);
1204                                                 return inst;
1205                                         }
1206                                         else if (*tok == KW_X0 && tok[1] == ',' && tok[2] == KW_B)
1207                                         {
1208                                                 // 'B,X:ea X0,B'
1209                                                 if (ea1 == DSP_EA_ABS)
1210                                                         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1211
1212                                                 if (S1 != 15)
1213                                                         return error("unrecognised X:R parallel move syntax: S1 can only be b in 'b,X:ea x0,b'");
1214
1215                                                 if (ea1 == -1)
1216                                                         return error("unrecognised X:R parallel move syntax: absolute address not allowed in 'b,X:ea x0,b'");
1217
1218                                                 if (ea1 == B8(00110100))
1219                                                         return error("unrecognised X:R parallel move syntax: immediate data not allowed in 'b,X:ea x0,b'");
1220
1221                                                 inst = B16(00001001, 00000000) | ea1 | (1 << 8);
1222                                                 return inst;
1223                                         }
1224                                         else if (*tok == KW_A || *tok == KW_B)
1225                                         {
1226                                                 // 'S1,X:ea S2,D2', 'S1,X:eax S2,Y:eay'
1227                                                 switch (S1)
1228                                                 {
1229                                                 case 4:  D1 = 0 << 10; break;
1230                                                 case 5:  D1 = 1 << 10; break;
1231                                                 case 14: D1 = 2 << 10; break;
1232                                                 case 15: D1 = 3 << 10; break;
1233                                                 default: return error("unrecognised X:R parallel move syntax: S1 can only be x0, x1, a or b in 'S1,X:ea S2,D2'");
1234                                                 }
1235
1236                                                 if (tok[1] == ',' && tok[2] == KW_Y)
1237                                                 {
1238                                                         // 'S1,X:eax S2,Y:eay'
1239                                                         return check_x_y(ea1, S1);
1240                                                 }
1241
1242                                                 // 'S1,X:ea S2,D2'
1243                                                 if (ea1 == DSP_EA_ABS)
1244                                                         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1245
1246                                                 switch (*tok++)
1247                                                 {
1248                                                 case KW_A: S2 = 0 << 9; break;
1249                                                 case KW_B: S2 = 1 << 9; break;
1250                                                 default:   return error("unrecognised X:R parallel move syntax: expected a or b after 'S1,X:eax'");
1251                                                 }
1252
1253                                                 if (*tok++ != ',')
1254                                                         return error("unrecognised X:R parallel move syntax: expected ',' after 'S1,X:eax S2'");
1255
1256                                                 if (*tok == KW_Y0 || *tok == KW_Y1)
1257                                                 {
1258                                                         if (*tok++ == KW_Y0)
1259                                                                 D2 = 0 << 8;
1260                                                         else
1261                                                                 D2 = 1 << 8;
1262
1263                                                         if (*tok != EOL)
1264                                                                 return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1265
1266                                                         inst = B16(00010000, 00000000) | (0 << 7);
1267                                                         inst |= ea1 | D1 | S2 | D2;
1268                                                         return inst;
1269                                                 }
1270                                                 else
1271                                                         return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1272                                         }
1273                                         else if (*tok == KW_Y)
1274                                         {
1275                                                 // 'S1,X:eax Y:eay,D2'
1276                                                 return check_x_y(ea1, S1);
1277                                         }
1278                                         else if (*tok == KW_Y0 || *tok == KW_Y1)
1279                                         {
1280                                                 // 'S1,X:eax S2,Y:eay'
1281                                                 return check_x_y(ea1, S1);
1282                                         }
1283                                         else
1284                                                 return error("unrecognised X:Y or X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1/X:ea,D1");
1285                                 }
1286                                 else
1287                                 {
1288                                         // Only check for aa if we have a defined number in our hands or we've
1289                                         // been asked to use a short number format. The former case we'll just test
1290                                         // it to see if it's small enough. The later - it's the programmer's call
1291                                         // so he'd better have a small address or the fixups will bite him/her in the arse!
1292                                         if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1293                                         {
1294
1295                                                 // It's an immediate, so ea or eax is probably an absolute address
1296                                                 // (unless it's aa if the immediate is small enough)
1297                                                 // 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay'
1298 x_check_immed:
1299                                                 // Check for aa (which is 6 bits zero extended)
1300                                                 if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1301                                                 {
1302                                                         if (W == 1)
1303                                                         {
1304                                                                 // It might be X:aa but we're not 100% sure yet.
1305                                                                 // If it is, the only possible syntax here is 'X:aa,D'.
1306                                                                 // So check ahead to see if EOL follows D, then we're good to go.
1307                                                                 if (*tok == ',' && ((*(tok + 1) >= KW_X0 && *(tok + 1) <= KW_N7) || (*(tok + 1) >= KW_R0 && *(tok + 1) <= KW_R7) || (*(tok + 1) >= KW_A0 && *(tok + 1) <= KW_A2)) && *(tok + 2) == EOL)
1308                                                                 {
1309                                                                         // Yup, we're good to go - 'X:aa,D' it is
1310                                                                         tok++;
1311                                                                         immreg = SDreg(*tok++);
1312                                                                         inst = inst | (uint32_t)dspImmedEXVAL;
1313                                                                         inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1314                                                                         inst |= 1 << 7; // W
1315                                                                         return inst;
1316                                                                 }
1317                                                         }
1318                                                         else
1319                                                         {
1320                                                                 if (*tok == EOL)
1321                                                                 {
1322                                                                         // 'S,X:aa'
1323                                                                         inst = inst | (uint32_t)dspImmedEXVAL;
1324                                                                         inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1325                                                                         return inst;
1326                                                                 }
1327                                                                 else
1328                                                                 {
1329                                                                         // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
1330                                                                         // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1331                                                                         ea1 = DSP_EA_ABS;
1332                                                                         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1333                                                                         goto x_checkea_right;
1334                                                                 }
1335                                                         }
1336                                                 }
1337                                         }
1338
1339                                         // Well, that settles it - we do have an ea in our hands
1340                                         if (W == 1)
1341                                         {
1342                                                 // 'X:ea,D' [... S2,d2]
1343                                                 if (*tok++ != ',')
1344                                                         return error("unrecognised X: parallel move syntax: expected ',' after 'X:ea'");
1345
1346                                                 if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1347                                                 {
1348                                                         D1 = SDreg(*tok++);
1349
1350                                                         if (*tok == EOL)
1351                                                         {
1352                                                                 // 'X:ea,D'
1353                                                                 inst = inst | B8(01000000) | (1 << 7);
1354                                                                 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1355                                                                 inst |= ea1;
1356
1357                                                                 if (ea1 == DSP_EA_ABS)
1358                                                                         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1359
1360                                                                 return inst;
1361                                                         }
1362                                                         else
1363                                                         {
1364                                                                 // 'X:ea,D1 S2,D2'
1365                                                                 if (*tok == KW_A || *tok == KW_B)
1366                                                                 {
1367                                                                         S2 = SDreg(*tok++);
1368
1369                                                                         if (*tok++ != ',')
1370                                                                                 return error("unrecognised X:R parallel move syntax: expected comma after X:ea,D1 S2");
1371
1372                                                                         if (*tok == KW_Y0 || *tok == KW_Y1)
1373                                                                         {
1374                                                                                 D2 = SDreg(*tok++);
1375
1376                                                                                 if (*tok != EOL)
1377                                                                                         return error("unrecognised X:R parallel move syntax: expected EOL after X:ea,D1 S2,D2");
1378
1379                                                                                 inst = B16(00010000, 00000000) | (1 << 7);
1380                                                                                 inst |= ((D1 & 0x8) << (12 - 4)) + ((D1 & 1) << 10);
1381                                                                                 inst |= (S2 & 1) << 9;
1382                                                                                 inst |= (D2 & 1) << 8;
1383                                                                                 inst |= ea1;
1384                                                                                 return inst;
1385                                                                         }
1386                                                                         else
1387                                                                                 return error("unrecognised X:R parallel move syntax: expected y0,y1 after X:ea,D1 S2,");
1388                                                                 }
1389                                                                 else
1390                                                                         return error("unrecognised X:R parallel move syntax: expected a,b after X:ea,D1");
1391                                                         }
1392                                                 }
1393                                                 else
1394                                                         return error("unrecognised X: parallel move syntax: expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after 'X:ea,'");
1395                                         }
1396                                         else
1397                                         {
1398                                                 if (*tok == EOL)
1399                                                 {
1400                                                         // 'S,X:ea'
1401                                                         inst = inst | B8(01000000) | (0 << 7);
1402                                                         inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1403                                                         inst |= ea1;
1404
1405                                                         if (ea1 == DSP_EA_ABS)
1406                                                                 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1407
1408                                                         return inst;
1409                                                 }
1410                                                 else
1411                                                 {
1412                                                         // 'S1,X:ea S2,D2', 'A,X:ea X0,A', 'B,X:ea X0,B',
1413                                                         // 'S1,X:eax Y:eay,D2', 'S1,X:eax S2,Y:eay'
1414                                                         goto x_checkea_right;
1415                                                 }
1416                                         }
1417
1418                                 }
1419                         }
1420                 }
1421                 else
1422                 {
1423                         // It's not an immediate, check for '-(Rn)'
1424                         ea1 = checkea(termchar, X_ERRORS);
1425
1426                         if (ea1 == ERROR)
1427                                 return ERROR;
1428
1429                         goto x_gotea1;
1430
1431                 }
1432         }
1433         else if (*tok == '#')
1434         {
1435                 tok++;
1436
1437                 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1438                         return ERROR;
1439
1440                 // Okay so we have immediate data - mark it down
1441                 ea1 = DSP_EA_IMM;
1442                 // Now, proceed to the main code for this branch
1443                 goto x_gotea1;
1444         }
1445         else if (*tok == '(')
1446         {
1447                 // Maybe we got an expression here, check for it
1448                 if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1449                 {
1450                         // Evaluate the expression and go to immediate code path
1451                         expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1452                         goto x_check_immed;
1453                 }
1454
1455                 // Nope, let's check for ea then
1456                 ea1 = checkea(termchar, X_ERRORS);
1457
1458                 if (ea1 == ERROR)
1459                         return ERROR;
1460
1461 x_gotea1:
1462                 if (W == 1)
1463                 {
1464                         if (*tok++ != ',')
1465                                 return error("Comma expected after 'X:(Rn)')");
1466
1467                         // It might be 'X:(Rn..)..,D' but we're not 100% sure yet.
1468                         // If it is, the only possible syntax here is 'X:ea,D'.
1469                         // So check ahead to see if EOL follows D, then we're good to go.
1470                         if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1471                         {
1472                                 //'X:ea,D'
1473                                 D1 = SDreg(*tok++);
1474
1475                                 inst = inst | B8(01000000) | (1 << 7);
1476                                 inst |= ea1;
1477                                 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1478                                 return inst;
1479                         }
1480                 }
1481                 else
1482                 {
1483                         if (*tok == EOL)
1484                         {
1485                                 //'S,X:ea'
1486                                 inst = inst | B8(01000000) | (0 << 7);
1487                                 inst |= ea1;
1488                                 inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1489                                 return inst;
1490                         }
1491                         else
1492                         {
1493                                 goto x_checkea_right;
1494                         }
1495                 }
1496
1497                 // 'X:eax,D1 Y:eay,D2', 'X:eax,D1 S2,Y:eay' or 'X:ea,D1 S2,D2'
1498                 // Check ahead for S2,D2 - if that's true then we have 'X:ea,D1 S2,D2'
1499                 if ((*tok == KW_X0 || *tok == KW_X1 || *tok == KW_A || *tok == KW_B) && (*(tok + 1) == KW_A || *(tok + 1) == KW_B) && (*(tok + 2) == ',') && (*(tok + 3) == KW_Y0 || (*(tok + 3) == KW_Y1)))
1500                 {
1501                         // 'X:ea,D1 S2,D2'
1502                         // Check if D1 is x0, x1, a or b
1503                         switch (*tok++)
1504                         {
1505                         case KW_X0: D1 = 0 << 10; break;
1506                         case KW_X1: D1 = 1 << 10; break;
1507                         case KW_A:  D1 = 2 << 10; break;
1508                         case KW_B:  D1 = 3 << 10; break;
1509                         default:    return error("unrecognised X:R parallel move syntax: expected x0, x1, a or b after 'X:eax,'");
1510                         }
1511
1512                         switch (*tok++)
1513                         {
1514                         case KW_A: S2 = 0 << 9; break;
1515                         case KW_B: S2 = 1 << 9; break;
1516                         default:   return error("unrecognised X:R parallel move syntax: expected a or b after 'X:eax,D1 '");
1517                         }
1518
1519                         if (*tok++ != ',')
1520                                 return error("unrecognised X:R parallel move syntax: expected ',' after 'X:eax,D1 S2'");
1521
1522                         if (*tok == KW_Y0 || *tok == KW_Y1)
1523                         {
1524                                 if (*tok++ == KW_Y0)
1525                                         D2 = 0 << 8;
1526                                 else
1527                                         D2 = 1 << 8;
1528
1529                                 if (*tok != EOL)
1530                                         return error("unrecognised X:R parallel move syntax: unexpected text after 'X:eax,D1 S2,S2'");
1531
1532                                 inst = B16(00010000, 00000000) | (W << 7);
1533                                 inst |= ea1 | D1 | S2 | D2;
1534                                 return inst;
1535                         }
1536                         else
1537                                 return error("unrecognised X:R parallel move syntax: expected y0 or y1 after 'X:eax,D1 S2,'");
1538                 }
1539
1540                 // Check to see if we got eax (which is a subset of ea)
1541                 if (check_for_x_y)
1542                 {
1543                         if ((inst = check_x_y(ea1, 0)) != 0)
1544                                 return inst;
1545                         else
1546                         {
1547                                 // Rewind pointer as it might be an expression and check for it
1548                                 tok--;
1549
1550                                 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
1551                                         return ERROR;
1552
1553                                 // Yes, we have an expression, so we now check for
1554                                 // 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay'
1555                                 goto x_check_immed;
1556                         }
1557                 }
1558         }
1559         else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1560         {
1561                 // Check for immediate address
1562                 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1563                         return ERROR;
1564
1565                 // We set ea1 here - if it's aa instead of ea
1566                 // then it won't be used anyway
1567                 ea1 = DSP_EA_ABS;
1568
1569                 if (!(dspImmedEXATTR&DEFINED))
1570                 {
1571                         force_imm = NUM_FORCE_LONG;
1572                         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1573                 }
1574
1575                 goto x_check_immed;
1576         }
1577         else if (*tok == '>')
1578         {
1579                 // Check for immediate address forced long
1580                 tok++;
1581
1582                 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1583                         return ERROR;
1584
1585                 if (dspImmedEXATTR & DEFINED)
1586                         if (dspImmedEXVAL > 0xffffff)
1587                                 return error("long address is bigger than $ffffff");
1588
1589                 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1590
1591                 force_imm = NUM_FORCE_LONG;
1592                 ea1 = DSP_EA_ABS;
1593                 goto x_check_immed;
1594         }
1595         else if (*tok == '<')
1596         {
1597                 // Check for immediate address forced short
1598                 tok++;
1599
1600                 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1601                         return ERROR;
1602
1603                 force_imm = NUM_FORCE_SHORT;
1604
1605                 if (dspImmedEXATTR & DEFINED)
1606                 {
1607                         if (dspImmedEXVAL > 0x3F)
1608                         {
1609                                 warn("short addressing mode forced but address is bigger than $3F - switching to long");
1610                                 force_imm = NUM_FORCE_LONG;
1611                                 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1612                                 ea1 = DSP_EA_ABS;
1613                         }
1614                 }
1615                 else
1616                 {
1617                         // This might end up as something like 'move Y:<adr,register'
1618                         // so let's mark it as an extra aa fixup here.
1619                         // Note: we are branching to x_check_immed without a
1620                         // defined dspImmed so it's going to be 0. It probably
1621                         // doesn't harm anything.
1622                         deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1623                 }
1624
1625                 goto x_check_immed;
1626         }
1627
1628         return error("unknown x: addressing mode");
1629 }
1630
1631
1632 //
1633 // Parse Y: addressing space parallel moves
1634 //
1635 static inline LONG parse_y(LONG inst, LONG S1, LONG D1, LONG S2)
1636 {
1637     int immreg;                                 // Immediate register destination
1638     LONG D2;                                    // Destination
1639     LONG ea1;                                   // ea bitfields
1640     int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1641     if (*tok == '-')
1642     {
1643         if (tok[1] == CONST || tok[1] == FCONST)
1644         {
1645             tok++;
1646             dspImmedEXVAL = *tok++;
1647             goto y_check_immed;
1648         }
1649         // This could be either -(Rn), -aa or -ea. Check for immediate first
1650                 if (*tok == SYMBOL || tok[1] == SYMBOL)
1651                 {
1652                         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1653                         {
1654                                 // Only check for aa if we have a defined number in our hands or we've
1655                                 // been asked to use a short number format. The former case we'll just test
1656                                 // it to see if it's small enough. The later - it's the programmer's call
1657                                 // so he'd better have a small address or the fixups will bite him/her in the arse!
1658                                 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1659                                 {
1660                                         // It's an immediate, so ea is probably an absolute address
1661                                         // (unless it's aa if the immediate is small enough)
1662                                         // 'Y:ea,D', 'Y:aa,D', 'S,Y:ea' or 'S,Y:aa'
1663                                 y_check_immed:
1664                                         // Check for aa (which is 6 bits zero extended)
1665                                         if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1666                                         {
1667                                                 // It might be Y:aa but we're not 100% sure yet.
1668                                                 // If it is, the only possible syntax here is 'Y:aa,D'/'S,Y:aa'.
1669                                                 // So check ahead to see if EOL follows D, then we're good to go.
1670                                                 if (*tok == EOL && S1 != 0)
1671                                                 {
1672                                                         // 'S,Y:aa'
1673                                                         inst = B16(01001000, 00000000);
1674                                                         inst |= dspImmedEXVAL;
1675                                                         inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1676                                                         return inst;
1677                                                 }
1678                                                 if (*tok == ',' && ((*(tok + 1) >= KW_X0 && *(tok + 1) <= KW_N7) || (*(tok + 1) >= KW_R0 && *(tok + 1) <= KW_R7) || (*(tok + 1) >= KW_A0 && *(tok + 1) <= KW_A2)) && *(tok + 2) == EOL)
1679                                                 {
1680                                                         // Yup, we're good to go - 'Y:aa,D' it is
1681                                                         tok++;
1682                                                         immreg = SDreg(*tok++);
1683                                                         inst |= dspImmedEXVAL;
1684                                                         inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
1685                                                         return inst;
1686                                                 }
1687                                         }
1688                                 }
1689                                 // Well, that settles it - we do have a ea in our hands
1690                                 if (*tok == EOL && S1 != 0)
1691                                 {
1692                                         // 'S,Y:ea'
1693                                         inst = B16(01001000, 01110000);
1694                                         inst |= ea1;
1695                                         inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1696                                         if (ea1 == DSP_EA_ABS)
1697                                                 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1698                                         return inst;
1699                                 }
1700                                 if (*tok++ != ',')
1701                                         return error("unrecognised Y: parallel move syntax: expected ',' after 'Y:ea'");
1702                                 if (D1 == 0 && S1 == 0)
1703                                 {
1704                                         // 'Y:ea,D'
1705                                         if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
1706                                         {
1707                                                 D1 = SDreg(*tok++);
1708                                                 if (*tok != EOL)
1709                                                         return error("unrecognised Y: parallel move syntax: expected EOL after 'Y:ea,D'");
1710                                                 inst |= B16(00000000, 01110000);
1711                                                 inst |= ea1;
1712                                                 inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1713                                                 if (ea1 == DSP_EA_ABS)
1714                                                         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1715                                                 return inst;
1716                                         }
1717                                         else
1718                                                 return error("unrecognised Y: parallel move syntax: expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after 'Y:ea,'");
1719                                 }
1720                                 else
1721                                 {
1722                                         // 'S1,D1 Y:ea,D2'
1723                                         if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
1724                                         {
1725                                                 D2 = SDreg(*tok++);
1726                                                 inst |= ea1;
1727                                                 inst |= 1 << 7;
1728                                                 inst |= (S1 & 1) << 11;
1729                                                 inst |= (D1 & 1) << 10;
1730                                                 inst |= (D2 & 8) << (9 - 3);
1731                                                 inst |= (D2 & 1) << 8;
1732                                                 return inst;
1733                                         }
1734                                         else
1735                                                 return error("unrecognised R:Y: parallel move syntax: expected a,b after 'S1,D1 Y:ea,'");
1736                                 }
1737                         }
1738                         else
1739                                 return ERROR;
1740                 }
1741         else
1742         {
1743             // It's not an immediate, check for '-(Rn)'
1744             ea1 = checkea(',', Y_ERRORS);
1745
1746             if (ea1 == ERROR)
1747                 return ERROR;
1748
1749             goto y_gotea1;
1750
1751         }
1752     }
1753     else if (*tok == '#')
1754     {
1755         tok++;
1756         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1757             return ERROR;
1758         // Okay so we have immediate data - mark it down
1759         ea1 = DSP_EA_IMM;
1760         // Now, proceed to the main code for this branch
1761         goto y_gotea1;
1762     }
1763     else if (*tok == '(')
1764     {
1765         // Maybe we got an expression here, check for it
1766         if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
1767         {
1768             // Evaluate the expression and go to immediate code path
1769             expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
1770             goto y_check_immed;
1771         }
1772
1773         // Nope, let's check for ea then
1774         if (S1 == 0 || (S1 != 0 && D1 != 0))
1775             ea1 = checkea(',', Y_ERRORS);
1776         else
1777             ea1 = checkea(EOL, Y_ERRORS);
1778
1779         if (ea1 == ERROR)
1780             return ERROR;
1781
1782     y_gotea1:
1783         if (S1 != 0 && *tok == EOL)
1784         {
1785             // 'S,Y:ea'
1786             inst = B16(01001000, 01000000);
1787             inst |= ea1;
1788             inst |= ((S1 & 0x18) << (12 - 3)) + ((S1 & 7) << 8);
1789             return inst;
1790         }
1791         else if (S1 != 0 && D1 != 0 && S2 == 0)
1792         {
1793             // 'S1,D1 Y:ea,D2'
1794             switch (S1)
1795             {
1796             case 14: S1 = 0 << 11; break; // A
1797             case 15: S1 = 1 << 11; break; // B
1798             default: return error("unrecognised R:Y parallel move syntax: S1 can only be A or B in 'S1,D1 Y:ea,D2'"); break;
1799             }
1800             switch (D1)
1801             {
1802             case 4: D1 = 0 << 10; break; // X0
1803             case 5: D1 = 1 << 10; break; // X1
1804             default: return error("unrecognised R:Y parallel move syntax: D1 can only be x0 or x1 in 'S1,D1 Y:ea,D2'");break;
1805             }
1806             if (*tok++ != ',')
1807                 return error("unrecognised R:Y parallel move syntax: expected ',' after 'S1,D1 Y:ea'");
1808             switch (*tok++)
1809             {
1810             case KW_Y0: D2 = 0 << 8; break;
1811             case KW_Y1: D2 = 1 << 8; break;
1812             case KW_A:  D2 = 2 << 8; break;
1813             case KW_B:  D2 = 3 << 8; break;
1814             default: return error("unrecognised R:Y parallel move syntax: D2 can only be y0, y1, a or b after 'S1,D1 Y:ea'");
1815             }
1816             inst = B16(00010000, 11000000);
1817             inst |= S1 | D1 | D2;
1818             inst |= ea1;
1819             return inst;
1820         }
1821         if (*tok++ != ',')
1822             return error("Comma expected after 'Y:(Rn)')");
1823         // It might be 'Y:(Rn..)..,D' but we're not 100% sure yet.
1824         // If it is, the only possible syntax here is 'Y:ea,D'.
1825         // So check ahead to see if EOL follows D, then we're good to go.
1826         if (((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)) && *(tok + 1) == EOL)
1827         {
1828             //'Y:ea,D'
1829             D1 = SDreg(*tok++);
1830             inst |= B16(00000000, 01000000);
1831             inst |= ea1;
1832             inst |= ((D1 & 0x18) << (12 - 3)) + ((D1 & 7) << 8);
1833             return inst;
1834         }
1835     }
1836     else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
1837     {
1838         // Check for immediate address
1839         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1840             return ERROR;
1841
1842         // Yes, we have an expression, so we now check for
1843         // 'Y:ea,D' or 'Y:aa,D'
1844         ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1845         if (!(dspImmedEXATTR&DEFINED))
1846         {
1847             force_imm = NUM_FORCE_LONG;
1848             deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1849         }
1850
1851         goto y_check_immed;
1852     }
1853     else if (*tok == '>')
1854     {
1855         // Check for immediate address forced long
1856         tok++;
1857         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1858             return ERROR;
1859         if (dspImmedEXATTR & DEFINED)
1860             if (dspImmedEXVAL > 0xffffff)
1861                 return error("long address is bigger than $ffffff");
1862
1863         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1864
1865         force_imm = NUM_FORCE_LONG;
1866         ea1 = DSP_EA_ABS;
1867         goto y_check_immed;
1868     }
1869     else if (*tok == '<')
1870     {
1871         tok++;
1872         if (S1 != 0 && D1 != 0)
1873         {
1874             // We're in 'S1,D1 Y:ea,D2' or 'S1,D1 S1,Y:ea'
1875             // there's no Y:aa mode here, so we'll force long
1876             warn("forced short addressing in R:Y mode is not allowed - switching to long");
1877
1878             if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1879                 return ERROR;
1880
1881             ea1 = DSP_EA_ABS;
1882
1883             force_imm = NUM_FORCE_LONG;
1884             deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1885             goto y_check_immed;
1886         }
1887         else
1888         {
1889             // Check for immediate address forced short
1890             ea1 = DSP_EA_ABS; // Reluctant - but it's probably correct
1891
1892             if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
1893                 return ERROR;
1894             force_imm = NUM_FORCE_SHORT;
1895             if (dspImmedEXATTR & DEFINED)
1896             {
1897                 if (dspImmedEXVAL > 0xfff)
1898                 {
1899                     warn("short addressing mode forced but address is bigger than $fff - switching to long");
1900                     ea1 = DSP_EA_ABS;
1901                     force_imm = NUM_FORCE_LONG;
1902                     deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1903                 }
1904             }
1905             else
1906             {
1907                 // This might end up as something like 'move Y:<adr,register'
1908                 // so let's mark it as an extra aa fixup here.
1909                 // Note: we are branching to y_check_immed without a
1910                 // defined dspImmed so it's going to be 0. It probably
1911                 // doesn't harm anything.
1912                 deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
1913             }
1914
1915             goto y_check_immed;
1916         }
1917     }
1918
1919     return error("unrecognised Y: parallel move syntax");
1920 }
1921
1922
1923 //
1924 // Parse L: addressing space parallel moves
1925 //
1926 static inline LONG parse_l(const int W, LONG inst, LONG S1)
1927 {
1928     int immreg;                                 // Immediate register destination
1929     LONG D1;                                    // Source and Destinations
1930     LONG ea1;                                   // ea bitfields
1931     int force_imm = NUM_NORMAL; // Holds forced immediate value (i.e. '<' or '>')
1932     if (*tok == '-')
1933     {
1934         if (*tok == CONST || tok[1] == FCONST)
1935         {
1936             tok++;
1937             dspImmedEXVAL = *tok++;
1938             goto l_check_immed;
1939         }
1940         // This could be either -(Rn), -aa or -ea. Check for immediate first
1941         // Maybe we got an expression here, check for it
1942         if (*tok == SYMBOL || tok[1] == SYMBOL)
1943         {
1944             // Evaluate the expression and go to immediate code path
1945             if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) == OK)
1946             {
1947                 // Only check for aa if we have a defined number in our hands or we've
1948                 // been asked to use a short number format. The former case we'll just test
1949                 // it to see if it's small enough. The later - it's the programmer's call
1950                 // so he'd better have a small address or the fixups will bite him/her in the arse!
1951                 if (dspImmedEXATTR&DEFINED || force_imm == NUM_FORCE_SHORT)
1952                 {
1953                     // It's an immediate, so ea is probably an absolute address
1954                     // (unless it's aa if the immediate is small enough)
1955                     // 'L:ea,D' or 'L:aa,D'
1956                 l_check_immed:
1957                     // Check for aa (which is 6 bits zero extended)
1958                     if (*tok == EOL)
1959                     {
1960                         // 'S,L:aa'
1961                         if (dspImmedEXVAL < 0x40 && force_imm != NUM_FORCE_LONG)
1962                         {
1963                             // 'S,L:aa'
1964                             if (S1 == KW_A)
1965                                 S1 = 4;
1966                             else if (S1 == KW_B)
1967                                 S1 = 5;
1968                             else
1969                                 S1 &= 7;
1970
1971                             inst = B16(01000000, 00000000);
1972                             inst |= dspImmedEXVAL;
1973                             inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
1974                             return inst;
1975                         }
1976                         else
1977                         {
1978                             // 'S,L:ea'
1979                             if (S1 == KW_A)
1980                                 S1 = 4;
1981                             else if (S1 == KW_B)
1982                                 S1 = 5;
1983                             else
1984                                 S1 &= 7;
1985
1986                             if (ea1 == DSP_EA_ABS)
1987                                 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
1988
1989                             inst |= B16(01000000, 01110000);
1990                             inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
1991                             inst |= ea1;
1992                             return inst;
1993                         }
1994
1995                     }
1996                     if (*tok++ != ',')
1997                         return error("unrecognised L: parallel move syntax: expected ',' after 'L:ea/L:aa'");
1998                     // Check for allowed registers for D (a0, b0, x, y, a, b, ab or ba)
1999                     if (!((*tok >= KW_A10 && *(tok + 1) <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)))
2000                         return error("unrecognised L: parallel move syntax: expected a0, b0, x, y, a, b, ab or ba after 'L:ea/L:aa'");
2001
2002                     if (dspImmedEXVAL < (1 << 6) && (dspImmedEXATTR&DEFINED))
2003                     {
2004                         // 'L:aa,D'
2005                         l_aa:
2006                         immreg = *tok++;
2007                         if (immreg == KW_A)
2008                             immreg = 4;
2009                         else if (immreg == KW_B)
2010                             immreg = 5;
2011                         else
2012                             immreg &= 7;
2013
2014                         if (*tok != EOL)
2015                             return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:aa,D");
2016
2017                         inst &= B16(11111111, 10111111);
2018                         inst |= dspImmedEXVAL;
2019                         inst |= ((immreg & 0x4) << (11 - 2)) + ((immreg & 3) << 8);
2020                         return inst;
2021                     }
2022                 }
2023
2024                 if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP)
2025                 {
2026                     // Hang on, we've got a L:<aa here, let's do that instead
2027                     goto l_aa;
2028                 }
2029
2030                 // Well, that settles it - we do have a ea in our hands
2031                 // 'L:ea,D'
2032                 D1 = *tok++;
2033                 if (D1 == KW_A)
2034                     D1 = 4;
2035                 else if (D1 == KW_B)
2036                     D1 = 5;
2037                 else
2038                     D1 &= 7;
2039
2040                 if (*tok != EOL)
2041                     return error("unrecognised L: parallel move syntax: expected End-Of-Line after L:ea,D");
2042
2043                 inst |= B16(00000000, 00110000);
2044                 inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2045                 return inst;
2046             }
2047         }
2048         else
2049         {
2050             //It's not an immediate, check for '-(Rn)'
2051             ea1 = checkea(',', L_ERRORS);
2052
2053             if (ea1 == ERROR)
2054                 return ERROR;
2055
2056             goto l_gotea1;
2057
2058         }
2059     }
2060     else if (*tok == '(')
2061     {
2062         // Maybe we got an expression here, check for it
2063         if (tok[1] == CONST || tok[1] == FCONST || tok[1] == SUNARY || tok[1] == SYMBOL || tok[1] == STRING)
2064         {
2065             // Evaluate the expression and go to immediate code path
2066             expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM);
2067             goto l_check_immed;
2068         }
2069
2070         //Nope, let's check for ea then
2071         if (S1 == 0)
2072             ea1 = checkea(',', L_ERRORS);
2073         else
2074             ea1 = checkea(EOL, L_ERRORS);
2075
2076         if (ea1 == ERROR)
2077             return ERROR;
2078
2079     l_gotea1:
2080         if (*tok == EOL)
2081         {
2082             // 'S,L:ea'
2083             inst = B16(01000000, 01000000);
2084             if (S1 == KW_A)
2085                 S1 = 4;
2086             else if (S1 == KW_B)
2087                 S1 = 5;
2088             else
2089                 S1 &= 7;
2090
2091             inst |= ea1;
2092             inst |= ((S1 & 0x4) << (11 - 2)) + ((S1 & 3) << 8);
2093             return inst;
2094         }
2095         else if (*tok++ != ',')
2096             return error("Comma expected after 'L:(Rn)')");
2097
2098         // It might be 'L:(Rn..)..,D' but we're not 100% sure yet.
2099         // If it is, the only possible syntax here is 'L:ea,D'.
2100         // So check ahead to see if EOL follows D, then we're good to go.
2101         if (((*tok >= KW_A10 && *tok <= KW_BA) || (*tok >= KW_A && *tok <= KW_B)) && *(tok + 1) == EOL)
2102         {
2103             //'L:ea,D'
2104             D1 = *tok++;
2105             if (D1 == KW_A)
2106                 D1 = 4;
2107             else if (D1 == KW_B)
2108                 D1 = 5;
2109             else
2110                 D1 &= 7;
2111
2112             inst |= ea1;
2113             inst |= ((D1 & 0x4) << (11 - 2)) + ((D1 & 3) << 8);
2114             return inst;
2115         }
2116     }
2117     else if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2118     {
2119         // Check for immediate address
2120         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2121             return ERROR;
2122
2123         // We set ea1 here - if it's aa instead of ea
2124         // then it won't be used anyway
2125         ea1 = DSP_EA_ABS;
2126         if (!(dspImmedEXATTR & DEFINED))
2127         {
2128             force_imm = NUM_FORCE_LONG;
2129             deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2130         }
2131                 else if (dspImmedEXVAL > 0x3f)
2132                 {
2133                         // Definitely no aa material, so it's going to be a long
2134                         // Mark that we need to deposit an extra word
2135                         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2136                 }
2137
2138         // Yes, we have an expression, so we now check for
2139         // 'L:ea,D' or 'L:aa,D'
2140         goto l_check_immed;
2141     }
2142     else if (*tok == '>')
2143     {
2144         // Check for immediate address forced long
2145         tok++;
2146         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2147             return ERROR;
2148         if (dspImmedEXATTR & DEFINED)
2149             if (dspImmedEXVAL > 0xffffff)
2150                 return error("long address is bigger than $ffffff");
2151
2152         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2153
2154         force_imm = NUM_FORCE_LONG;
2155         goto l_check_immed;
2156     }
2157     else if (*tok == '<')
2158     {
2159         // Check for immediate address forced short
2160         tok++;
2161         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2162             return ERROR;
2163         if (dspImmedEXATTR & DEFINED)
2164         {
2165             if (dspImmedEXVAL > 0xfff)
2166                 return error("short addressing mode forced but address is bigger than $fff");
2167         }
2168         else
2169         {
2170             // This might end up as something like 'move Y:<adr,register'
2171             // so let's mark it as an extra aa fixup here.
2172             // Note: we are branching to l_check_immed without a
2173             // defined dspImmed so it's going to be 0. It probably
2174             // doesn't harm anything.
2175             deposit_extra_ea = DEPOSIT_EXTRA_FIXUP;
2176         }
2177
2178         force_imm = NUM_FORCE_SHORT;
2179         goto l_check_immed;
2180     }
2181
2182     return error("internal assembler error: Please report this error message: 'reached the end of parse_l' with the line of code that caused it. Thanks, and sorry for the inconvenience");
2183 }
2184
2185
2186 //
2187 // Checks for all ea cases where indexed addressing is concenred
2188 //
2189 static inline LONG checkea(const uint32_t termchar, const int strings)
2190 {
2191     LONG ea;
2192     if (*tok == '-')
2193     {
2194         // -(Rn)
2195         tok++;
2196         if (*tok++ != '(')
2197             return error(ea_errors[strings][0]);
2198         if (*tok >= KW_R0 && *tok <= KW_R7)
2199         {
2200             // We got '-(Rn' so mark it down
2201             ea = DSP_EA_PREDEC1 | (*tok++ - KW_R0);
2202             if (*tok++ != ')')
2203                 return error(ea_errors[strings][1]);
2204             // Now, proceed to the main code for this branch
2205             return ea;
2206         }
2207         else
2208             return error(ea_errors[strings][2]);
2209     }
2210     else if (*tok == '(')
2211     {
2212         // Checking for ea of type (Rn)
2213         tok++;
2214         if (*tok >= KW_R0 && *tok <= KW_R7)
2215         {
2216             // We're in 'X:(Rn..)..,D', 'X:(Rn..)..,D1 Y:eay,D2', 'X:(Rn..)..,D1 S2,Y:eay'
2217             ea = *tok++ - KW_R0;
2218             if (*tok == '+')
2219             {
2220                 // '(Rn+Nn)'
2221                 tok++;
2222                 if (*tok < KW_N0 || *tok > KW_N7)
2223                     return error(ea_errors[strings][3]);
2224                 if ((*tok++ & 7) != ea)
2225                     return error(ea_errors[strings][4]);
2226                 ea |= DSP_EA_INDEX;
2227                 if (*tok++ != ')')
2228                     return error(ea_errors[strings][5]);
2229                 return ea;
2230             }
2231             else if (*tok == ')')
2232             {
2233                 // Check to see if we have '(Rn)+', '(Rn)-', '(Rn)-Nn', '(Rn)+Nn' or '(Rn)'
2234                 tok++;
2235                 if (*tok == '+')
2236                 {
2237                     tok++;
2238                     if (termchar == ',')
2239                     {
2240                         if (*tok == ',')
2241                         {
2242                             // (Rn)+
2243                             ea |= DSP_EA_POSTINC1;
2244                             return ea;
2245                         }
2246                         else if (*tok >= KW_N0 && *tok <= KW_N7)
2247                         {
2248                             // (Rn)+Nn
2249                             if ((*tok++ & 7) != ea)
2250                                 return error(ea_errors[strings][6]);
2251                             ea |= DSP_EA_POSTINC;
2252                             return ea;
2253                         }
2254                         else
2255                             return error(ea_errors[strings][7]);
2256                     }
2257                     else
2258                     {
2259                         if (*tok >= KW_N0 && *tok <= KW_N7)
2260                         {
2261                             // (Rn)+Nn
2262                             if ((*tok++ & 7) != ea)
2263                                 return error(ea_errors[strings][6]);
2264                             ea |= DSP_EA_POSTINC;
2265                             return ea;
2266                         }
2267                         else
2268                         {
2269                             // (Rn)+
2270                             ea |= DSP_EA_POSTINC1;
2271                             return ea;
2272                         }
2273                     }
2274                 }
2275                 else if (*tok == '-')
2276                 {
2277                     tok++;
2278                     if (termchar == ',')
2279                     {
2280                         if (*tok == ',')
2281                         {
2282                             // (Rn)-
2283                             ea |= DSP_EA_POSTDEC1;
2284                             return ea;
2285                         }
2286                         else if (*tok >= KW_N0 && *tok <= KW_N7)
2287                         {
2288                             // (Rn)-Nn
2289                             if ((*tok++ & 7) != ea)
2290                                 return error(ea_errors[strings][8]);
2291                             ea |= DSP_EA_POSTDEC;
2292                             return ea;
2293                         }
2294                         else
2295                             return error(ea_errors[strings][9]);
2296                     }
2297                     else
2298                     {
2299                         if (*tok >= KW_N0 && *tok <= KW_N7)
2300                         {
2301                             // (Rn)-Nn
2302                             if ((*tok++ & 7) != ea)
2303                                 return error(ea_errors[strings][8]);
2304                             ea |= DSP_EA_POSTDEC;
2305                             return ea;
2306                         }
2307                         else
2308                         {
2309                             // (Rn)-
2310                             ea |= DSP_EA_POSTDEC1;
2311                             return ea;
2312                         }
2313                     }
2314                 }
2315                 else if (termchar == ',')
2316                 {
2317                     if (*tok == ',')
2318                     {
2319                         // (Rn)
2320                         ea |= DSP_EA_NOUPD;
2321                         return ea;
2322                     }
2323                     else
2324                         return error(ea_errors[strings][10]);
2325                 }
2326                 else
2327                 {
2328                     // (Rn)
2329                     ea |= DSP_EA_NOUPD;
2330                     return ea;
2331                 }
2332             }
2333             else
2334                 return error(ea_errors[strings][11]);
2335         }
2336     }
2337     return error("internal assembler error: Please report this error message: 'reached the end of checkea' with the line of code that caused it. Thanks, and sorry for the inconvenience");
2338 }
2339
2340
2341 //
2342 // Checks for all ea cases, i.e. all addressing modes that checkea handles
2343 // plus immediate addresses included forced short/long ones.
2344 // In other words this is a superset of checkea (and in fact calls checkea).
2345 //
2346 LONG checkea_full(const uint32_t termchar, const int strings)
2347 {
2348     LONG ea1;
2349
2350     if (*tok == CONST || *tok == FCONST || *tok == SYMBOL)
2351     {
2352         // Check for immediate address
2353         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2354             return ERROR;
2355
2356         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2357
2358         // Yes, we have an expression
2359         return DSP_EA_ABS;
2360     }
2361     else if (*tok == '>')
2362     {
2363         // Check for immediate address forced long
2364         tok++;
2365         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2366             return ERROR;
2367         if (dspImmedEXATTR & DEFINED)
2368             if (dspImmedEXVAL > 0xffffff)
2369                 return error("long address is bigger than $ffffff");
2370
2371         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2372
2373         // Yes, we have an expression
2374         return DSP_EA_ABS;
2375     }
2376     else if (*tok == '<')
2377     {
2378         // Check for immediate address forced short
2379         tok++;
2380         if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2381             return ERROR;
2382         if (dspImmedEXATTR & DEFINED)
2383             if (dspImmedEXVAL > 0xfff)
2384                 return error("short addressing mode forced but address is bigger than $fff");
2385
2386         // Yes, we have an expression
2387         return DSP_EA_ABS;
2388     }
2389     else
2390     {
2391         ea1 = checkea(termchar, strings);
2392         if (ea1 == ERROR)
2393             return ERROR;
2394         else
2395             return ea1;
2396     }
2397
2398 }
2399
2400
2401 //
2402 // Main routine to check parallel move modes.
2403 // It's quite complex so it's split into a few procedures (in fact most of the
2404 // above ones). A big effort was made so this can be managable and not too
2405 // hacky, however one look at the 56001 manual regarding parallel moves and
2406 // you'll know that this is not an easy // problem to deal with!
2407 // dest=destination register from the main opcode. This must not be the same
2408 // as D1 or D2 and that even goes for stuff like dest=A, D1=A0/1/2!!!
2409 //
2410 LONG parmoves(WORD dest)
2411 {
2412         int force_imm;          // Addressing mode force operator
2413         int immreg;             // Immediate register destination
2414         LONG inst;              // 16 bit bitfield that has the parallel move opcode
2415         LONG S1, S2, D1, D2;    // Source and Destinations
2416         LONG ea1;                               // ea bitfields
2417
2418         if (*tok == EOL)
2419         {
2420                 // No parallel move
2421                 return B16(00100000, 00000000);
2422         }
2423
2424         if (*tok == '#')
2425         {
2426                 // '#xxxxxx,D', '#xx,D'
2427                 tok++;
2428                 force_imm = NUM_NORMAL;
2429
2430                 if (*tok == '>')
2431                 {
2432                         force_imm = NUM_FORCE_LONG;
2433                         tok++;
2434                 }
2435                 else if (*tok == '<')
2436                 {
2437                         force_imm = NUM_FORCE_SHORT;
2438                         tok++;
2439                 }
2440
2441                 if (expr(dspImmedEXPR, &dspImmedEXVAL, &dspImmedEXATTR, &dspImmedESYM) != OK)
2442                         return ERROR;
2443
2444                 if (*tok++ != ',')
2445                         return error("expected comma");
2446
2447                 if (!((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2)))
2448                         return error("expected x0,x1,y0,y1,a0,b0,a2,b2,a1,b1,a,b,r0-r7,n0-n7 after immediate");
2449
2450                 immreg = SDreg(*tok++);
2451
2452                 if (*tok == EOL)
2453                 {
2454                         if (!(dspImmedEXATTR & FLOAT))
2455                         {
2456                                 if (dspImmedEXATTR & DEFINED)
2457                                 {
2458                                         // From I parallel move:
2459                                         // "If the destination register D is X0, X1, Y0, Y1, A, or B, the 8-bit immediate short operand
2460                                         // is interpreted as a signed fraction and is stored in the specified destination register.
2461                                         // That is, the 8 - bit data is stored in the eight MS bits of the destination operand, and the
2462                                         // remaining bits of the destination operand D are zeroed."
2463                                         // The funny bit is that Motorola assembler can parse something like 'move #$FF0000,b' into an
2464                                         // I (immediate short move) - so let's do that as well then...
2465                                         if (((immreg >= 4 && immreg <= 7) || immreg == 14 || immreg == 15) && force_imm != NUM_FORCE_LONG)
2466                                         {
2467                                                 if ((dspImmedEXVAL & 0xffff) == 0)
2468                                                 {
2469                                                         dspImmedEXVAL >>= 16;
2470                                                 }
2471                                         }
2472
2473                                         if (force_imm == NUM_FORCE_SHORT)
2474                                         {
2475                                                 if (dspImmedEXVAL < 0xFF && (int32_t)dspImmedEXVAL > -0x100)
2476                                                 {
2477                                                         // '#xx,D'
2478                                                         // value fits in 8 bits - immediate move
2479                                                         inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2480                                                         return inst;
2481                                                 }
2482                                                 else
2483                                                 {
2484                                                         warn("forced short immediate value doesn't fit in 8 bits - switching to long");
2485                                                         force_imm = NUM_FORCE_LONG;
2486                                                 }
2487                                         }
2488
2489                                         if (force_imm == NUM_FORCE_LONG)
2490                                         {
2491                                                 // '#xxxxxx,D'
2492                                                 // it can either be
2493                                                 // X or Y Data move. I don't think it matters much
2494                                                 // which of the two it will be, so let's use X.
2495 deposit_immediate_long_with_register:
2496                                                 inst = B16(01000000, 11110100);
2497                                                 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2498                                                 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2499                                                 return inst;
2500                                         }
2501
2502                                         if (((int32_t)dspImmedEXVAL < 0x100) && ((int32_t)dspImmedEXVAL >= -0x100))
2503                                         {
2504                                                 // value fits in 8 bits - immediate move
2505 deposit_immediate_short_with_register:
2506                                                 inst = B16(00100000, 00000000) + (immreg << 8) + (uint32_t)dspImmedEXVAL;
2507                                                 return inst;
2508                                         }
2509                                         else
2510                                         {
2511                                                 // value doesn't fit in 8 bits, so it can either be
2512                                                 // X or Y Data move. I don't think it matters much
2513                                                 // which of the two it will be, so let's use X:.
2514                                                 // TODO: if we're just goto'ing perhaps the logic can be simplified
2515                                                 goto deposit_immediate_long_with_register;
2516                                         }
2517                                 }
2518                                 else
2519                                 {
2520                                         if (force_imm != NUM_FORCE_SHORT)
2521                                         {
2522                                                 // '#xxxxxx,D'
2523                                                 // TODO: if we're just goto'ing perhaps the logic can be simplified
2524                                                 goto deposit_immediate_long_with_register;
2525                                         }
2526                                         else
2527                                         {
2528                                                 // '#xx,D' - I mode
2529                                                 // No visibility of the number so let's add a fixup for this
2530                                                 AddFixup(FU_DSPIMM8, sloc, dspImmedEXPR);
2531                                                 inst = B16(00100000, 00000000);
2532                                                 inst |= ((immreg & 0x18) << (11 - 3)) + ((immreg & 7) << 8);
2533                                                 return inst;
2534                                         }
2535                                 }
2536                         }
2537                         else
2538                         {
2539                                 // Float constant
2540                                 if (dspImmedEXATTR & DEFINED)
2541                                 {
2542                                         double f = *(double *)&dspImmedEXVAL;
2543                                         // Check direct.c for ossom comments regarding conversion!
2544 //N.B.: This is bogus, we need to fix this so it does this the right way... !!! FIX !!!
2545                                         dspImmedEXVAL = ((uint32_t)(int32_t)round(f * (1 << 23))) & 0xFFFFFF;
2546                                         double g;
2547                                         g = f * (1 << 23);
2548                                         g = round(g);
2549
2550                                         if ((dspImmedEXVAL & 0xFFFF) == 0)
2551                                         {
2552                                                 // Value's 16 lower bits are not set so the value can fit in a single byte
2553                                                 // (check parallel I move quoted above)
2554                                                 warn("Immediate value fits inside 8 bits, so using instruction short format");
2555                                                 dspImmedEXVAL >>= 16;
2556                                                 goto deposit_immediate_short_with_register;
2557                                         }
2558
2559                                         if (force_imm == NUM_FORCE_SHORT)
2560                                         {
2561                                                 if ((dspImmedEXVAL & 0xFFFF) != 0)
2562                                                 {
2563                                                         warn("Immediate value short format forced but value does not fit inside 8 bits - switching to long format");
2564                                                         goto deposit_immediate_long_with_register;
2565                                                 }
2566
2567                                                 return error("internal assembler error: we haven't implemented floating point constants in parallel mode parser yet!");
2568                                         }
2569
2570                                         // If we reach here we either have NUM_FORCE_LONG or nothing, so we might as well store a long.
2571                                         goto deposit_immediate_long_with_register;
2572                                 }
2573                                 else
2574                                 {
2575                                         if (force_imm == NUM_FORCE_SHORT)
2576                                         {
2577                                                 goto deposit_immediate_short_with_register;
2578                                         }
2579                                         else
2580                                         {
2581                                                 // Just deposit a float fixup
2582                                                 AddFixup(FU_DSPIMMFL8, sloc, dspImmedEXPR);
2583                                                 inst = B16(00100000, 00000000);
2584                                                 inst |= ((immreg & 0x18) << (12 - 3)) + ((immreg & 7) << 8);
2585                                                 return inst;
2586                                         }
2587                                 }
2588                         }
2589                 }
2590                 else
2591                 {
2592                         // At this point we can only have '#xxxxxx,D1 S2,D2' (X:R Class I)
2593                         switch (immreg)
2594                         {
2595                         case 4: D1 = 0 << 10;break;  // X0
2596                         case 5: D1 = 1 << 10;break;  // X1
2597                         case 14: D1 = 2 << 10;break; // A
2598                         case 15: D1 = 3 << 10;break; // B
2599                         default: return error("unrecognised X:R parallel move syntax: D1 can only be x0,x1,a,b in '#xxxxxx,D1 S2,D2'"); break;
2600                         }
2601
2602                         switch (*tok++)
2603                         {
2604                         case KW_A: S2 = 0 << 9; break;
2605                         case KW_B: S2 = 1 << 9; break;
2606                         default: return error("unrecognised X:R parallel move syntax: S2 can only be A or B in '#xxxxxx,D1 S2,D2'"); break;
2607                         }
2608
2609                         if (*tok++ != ',')
2610                                 return error("unrecognised X:R parallel move syntax: expected comma after '#xxxxxx,D1 S2'");
2611
2612                         switch (*tok++)
2613                         {
2614                         case KW_Y0: D2 = 0 << 8; break;
2615                         case KW_Y1: D2 = 1 << 8; break;
2616                         default: return error("unrecognised X:R parallel move syntax: D2 can only be Y0 or Y1 in '#xxxxxx,D1 S2,D2'"); break;
2617                         }
2618
2619                         if (*tok != EOL)
2620                                 return error("unrecognised X:R parallel move syntax: expected end-of-line after '#xxxxxx,D1 S2,D2'");
2621
2622                         inst = B16(00010000, 10110100) | D1 | S2 | D2;
2623                         deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2624                         return inst;
2625                 }
2626         }
2627         else if (*tok == KW_X)
2628         {
2629                 if (tok[1] == ',')
2630                         // Hey look, it's just the register X and not the addressing mode - fall through to general case
2631                         goto parse_everything_else;
2632
2633                 tok++;
2634
2635                 if (*tok++ != ':')
2636                         return error("expected ':' after 'X' in parallel move (i.e. X:)");
2637
2638                 // 'X:ea,D' or 'X:aa,D' or 'X:ea,D1 S2,D2' or 'X:eax,D1 Y:eay,D2' or 'X:eax,D1 S2,Y:eay'
2639                 return parse_x(1, B16(01000000, 00000000), 0, 1);
2640         }
2641         else if (*tok == KW_Y)
2642         {
2643                 if (tok[1] == ',')
2644                         // Hey look, it's just the register y and not the addressing mode - fall through to general case
2645                         goto parse_everything_else;
2646
2647                 tok++;
2648
2649                 if (*tok++ != ':')
2650                         return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2651
2652                 // 'Y:ea,D' or 'Y:aa,D'
2653                 return parse_y(B16(01001000, 10000000), 0, 0, 0);
2654         }
2655         else if (*tok == KW_L)
2656         {
2657                 // 'L:ea,D' or 'L:aa,D'
2658                 tok++;
2659                 if (*tok++ != ':')
2660                         return error("expected ':' after 'L' in parallel move (i.e. L:)");
2661
2662                 return parse_l(1, B16(01000000, 11000000), 0);
2663         }
2664         else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2) || (*tok >= KW_A10 && *tok <= KW_BA))
2665         {
2666                 // Everything else - brace for impact!
2667                 // R:   'S,D'
2668                 // X:   'S,X:ea' 'S,X:aa'
2669                 // X:R  'S,X:ea S2,D2' 'A,X:ea X0,A' 'B,X:ea X0,B'
2670                 // Y:   'S,Y:ea' 'S,Y:aa'
2671                 // R:Y: 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 #xxxxxx,D2' 'Y0,A A,Y:ea' 'Y0,B B,Y:ea'
2672                 // L:   'S,L:ea' 'S,L:aa'
2673                 LONG L_S1;
2674 parse_everything_else:
2675                 L_S1 = *tok++;
2676                 S1 = SDreg(L_S1);
2677
2678                 if (*tok++ != ',')
2679                         return error("Comma expected after 'S')");
2680
2681                 if (*tok == KW_X)
2682                 {
2683                         // 'S,X:ea' 'S,X:aa' 'S,X:ea S2,D2' 'S1,X:eax Y:eay,D2' 'S1,X:eax S2,Y:eay'
2684                         // 'A,X:ea X0,A' 'B,X:ea X0,B'
2685                         tok++;
2686
2687                         if (*tok++ != ':')
2688                                 return error("unrecognised X: parallel move syntax: expected ':' after 'S,X'");
2689
2690                         return parse_x(0, B16(01000000, 00000000), S1, 1);
2691                 }
2692                 else if (*tok == KW_Y)
2693                 {
2694                         // 'S,Y:ea' 'S,Y:aa'
2695                         tok++;
2696
2697                         if (*tok++ != ':')
2698                                 return error("unrecognised Y: parallel move syntax: expected ':' after 'S,Y'");
2699
2700                         return parse_y(B16(0000000, 00000000), S1, 0, 0);
2701                 }
2702                 else if (*tok == KW_L)
2703                 {
2704                         // 'S,L:ea' 'S,L:aa'
2705                         tok++;
2706
2707                         if (*tok++ != ':')
2708                                 return error("unrecognised L: parallel move syntax: expected ':' after 'S,L'");
2709
2710                         return parse_l(1, B16(00000000, 00000000), L_S1);
2711                 }
2712                 else if ((*tok >= KW_X0 && *tok <= KW_N7) || (*tok >= KW_R0 && *tok <= KW_R7) || (*tok >= KW_A0 && *tok <= KW_A2))
2713                 {
2714                         // 'S,D'
2715                         // 'S1,D1 Y:ea,D2' 'S1,D1 S2,Y:ea' 'S1,D1 #xxxxxx,D2'
2716                         // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea'
2717                         D1 = SDreg(*tok++);
2718
2719                         if (*tok == EOL)
2720                         {
2721                                 // R 'S,D'
2722                                 inst = B16(00100000, 00000000);
2723                                 inst |= (S1 << 5) | (D1);
2724                                 return inst;
2725                         }
2726                         else if (*tok == KW_Y)
2727                         {
2728                                 // 'S1,D1 Y:ea,D2'
2729                                 tok++;
2730                                 if (*tok++ != ':')
2731                                         return error("expected ':' after 'Y' in parallel move (i.e. Y:)");
2732                                 return parse_y(B16(00010000, 01000000), S1, D1, 0);
2733
2734                         }
2735                         else if (*tok == KW_A || *tok == KW_B || *tok == KW_Y0 || *tok == KW_Y1)
2736                         {
2737                                 // 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' 'S1,D1 S2,Y:ea'
2738                                 S2 = SDreg(*tok++);
2739
2740                                 if (S1 == 6 && D1 == 14 && S2 == 14)
2741                                 {
2742                                         // 'Y0,A A,Y:ea'
2743                                         if (*tok++ != ',')
2744                                                 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,A A");
2745
2746                                         if (*tok++ != KW_Y)
2747                                                 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,A A,");
2748
2749                                         if (*tok++ != ':')
2750                                                 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,A A,Y");
2751
2752                                         ea1 = checkea_full(EOL, Y_ERRORS);
2753
2754                                         if (ea1 == ERROR)
2755                                                 return ERROR;
2756
2757                                         inst = B16(00001000, 10000000);
2758                                         inst |= 0 << 8;
2759                                         inst |= ea1;
2760                                         return inst;
2761                                 }
2762                                 else if (S1 == 6 && D1 == 15 && S2 == 15)
2763                                 {
2764                                         // 'Y0,B B,Y:ea'
2765                                         if (*tok++ != ',')
2766                                                 return error("unrecognised Y: parallel move syntax: expected ',' after Y0,B B");
2767
2768                                         if (*tok++ != KW_Y)
2769                                                 return error("unrecognised Y: parallel move syntax: expected 'Y' after Y0,B B,");
2770
2771                                         if (*tok++ != ':')
2772                                                 return error("unrecognised Y: parallel move syntax: expected ':' after Y0,B B,Y");
2773
2774                                         ea1 = checkea_full(EOL, Y_ERRORS);
2775
2776                                         if (ea1 == ERROR)
2777                                                 return ERROR;
2778
2779                                         inst = B16(00001000, 10000000);
2780                                         inst |= 1 << 8;
2781                                         inst |= ea1;
2782                                         return inst;
2783                                 }
2784                                 else if ((S1 == 14 || S1 == 15) && (D1 == 4 || D1 == 5) && (S2 == 6 || S2 == 7 || S2 == 14 || S2 == 15))
2785                                 {
2786                                         //'S1,D1 S2,Y:ea'
2787                                         if (*tok++ != ',')
2788                                                 return error("unrecognised Y: parallel move syntax: expected ',' after S1,D1 S2");
2789
2790                                         if (*tok++ != KW_Y)
2791                                                 return error("unrecognised Y: parallel move syntax: expected 'Y' after S1,D1 S2,");
2792
2793                                         if (*tok++ != ':')
2794                                                 return error("unrecognised Y: parallel move syntax: expected ':' after S1,D1 S2,Y");
2795
2796                                         ea1 = checkea_full(EOL, Y_ERRORS);
2797
2798                                         if (ea1 == ERROR)
2799                                                 return ERROR;
2800
2801                                         inst = B16(00010000, 01000000);
2802                                         inst |= (S1 & 1) << 11;
2803                                         inst |= (D1 & 1) << 10;
2804                                         inst |= ((S2 & 8) << (10 - 4)) | ((S2 & 1) << 8);
2805                                         inst |= ea1;
2806                                         return inst;
2807                                 }
2808                                 else
2809                                         return error("unrecognised Y: parallel move syntax: only 'Y0,A A,Y:ea' 'Y0,B B,Y:ea' allowed'");
2810                                 // Check for Y:
2811                         }
2812                         else if (*tok == '#')
2813                         {
2814                                 // R:Y: 'S1,D1 #xxxxxx,D2'
2815                                 tok++;
2816
2817                                 if (*tok == '>')
2818                                 {
2819                                         // Well, forcing an immediate to be 24 bits is legal here
2820                                         // but then it's the only available option so my guess is that this
2821                                         // is simply superfluous. So let's just eat the character
2822                                         tok++;
2823                                 }
2824
2825                                 if (expr(dspaaEXPR, &dspaaEXVAL, &dspaaEXATTR, &dspaaESYM) != OK)
2826                                         return ERROR;
2827
2828                                 if (dspImmedEXATTR & DEFINED)
2829                                         if (dspImmedEXVAL > 0xffffff)
2830                                                 return error("immediate is bigger than $ffffff");
2831
2832                                 deposit_extra_ea = DEPOSIT_EXTRA_WORD;
2833
2834                                 if (*tok++ != ',')
2835                                         return error("Comma expected after 'S1,D1 #xxxxxx')");
2836
2837                                 // S1 is a or b, D1 is x0 or x1 and d2 is y0, y1, a or b
2838                                 switch (*tok++)
2839                                 {
2840                                 case KW_Y0: D2 = 0 << 8; break;
2841                                 case KW_Y1: D2 = 1 << 8; break;
2842                                 case KW_A:  D2 = 2 << 8; break;
2843                                 case KW_B:  D2 = 3 << 8; break;
2844                                 default:    return error("unrecognised R:Y: parallel move syntax: D2 must be y0, y1, a or b in 'S1,D1 #xxxxxx,D2'");
2845                                 }
2846
2847                                 if (S1 == 14 || S1 == 15)
2848                                 {
2849                                         if (D1 == 4 || D1 == 5)
2850                                         {
2851                                                 inst = B16(00010000, 11110100);
2852                                                 inst |= (S1 & 1) << 11;
2853                                                 inst |= (D1 & 1) << 10;
2854                                                 inst |= D2;
2855                                                 dspImmedEXVAL = dspaaEXVAL;
2856                                                 return inst;
2857                                         }
2858                                         else
2859                                                 return error("unrecognised R:Y: parallel move syntax: D1 must be x0 or x1 in 'S1,D1 #xxxxxx,D2'");
2860                                 }
2861                                 else
2862                                         return error("unrecognised R:Y: parallel move syntax: S1 must be a or b in 'S1,D1 #xxxxxx,D2'");
2863                         }
2864                         else
2865                                 return error("unrecognised R:Y: parallel move syntax: Unexpected text after S,D in 'S1,D1 #xxxxxx,D2'");
2866                 }
2867                 else
2868                         return error("unrecognised R:Y: parallel move syntax: Unexpected text after 'S,'");
2869         }
2870         else if (*tok == '(')
2871         {
2872                 // U: 'ea'
2873                 // U 'ea' can only be '(Rn)-Nn', '(Rn)+Nn', '(Rn)-' or '(Rn)+'
2874                 tok++;
2875
2876                 if (*tok >= KW_R0 && *tok <= KW_R7)
2877                 {
2878                         ea1 = (*tok++ - KW_R0);
2879                 }
2880                 else
2881                         return error("unrecognised U parallel move syntax: expected 'Rn' after '('");
2882
2883                 if (*tok++ != ')')
2884                         return error("unrecognised U parallel move syntax: expected ')' after '(Rn'");
2885
2886                 if (*tok == '+')
2887                 {
2888                         tok++;
2889
2890                         if (*tok == EOL)
2891                                 // (Rn)+
2892                                 ea1 |= 3 << 3;
2893                         else if (*tok >= KW_N0 && *tok <= KW_N7)
2894                         {
2895                                 // (Rn)+Nn
2896                                 if ((*tok++ & 7) != ea1)
2897                                         return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)+Nn')");
2898
2899                                 ea1 |= 1 << 3;
2900
2901                                 if (*tok != EOL)
2902                                         return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)+Nn'");
2903                         }
2904                         else
2905                                 return error("unrecognised U parallel move syntax: expected End-Of-Line or 'Nn' after '(Rn)+'");
2906                 }
2907                 else if (*tok == '-')
2908                 {
2909                         tok++;
2910
2911                         if (*tok == EOL)
2912                         {
2913                                 // (Rn)-
2914                                 ea1 |= 2 << 3;
2915                                 tok++;
2916                         }
2917                         else if (*tok >= KW_N0 && *tok <= KW_N7)
2918                         {
2919                                 // (Rn)-Nn
2920                                 if ((*tok++ & 7) != ea1)
2921                                         return error("unrecognised U parallel move syntax: Same register number expected for Rn, Nn in '(Rn)-Nn')");
2922
2923                                 ea1 |= 0 << 3;
2924
2925                                 if (*tok != EOL)
2926                                         return error("unrecognised U parallel move syntax: expected End-Of-Line after '(Rn)-Nn'");
2927                         }
2928                 }
2929
2930                 inst = B16(00100000, 01000000);
2931                 inst |= ea1;
2932                 return inst;
2933         }
2934         else
2935                 return error("extra (unexpected) text found");
2936
2937         return OK;
2938 }
2939