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