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