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