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