Version bump for last commit; now at v2.0.23.
[rmac] / dsp56k_mach.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // DSP56L_MACH.C - Code Generation for Motorola DSP56001
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_mach.h"
10 #include "direct.h"
11 #include "dsp56k.h"
12 #include "error.h"
13 #include "rmac.h"
14 #include "sect.h"
15 #include "token.h"
16
17 #define DEF_KW
18 #include "kwtab.h"
19
20
21 // Globals
22 unsigned int dsp_orgaddr;       // DSP 56001 ORG address
23 unsigned int dsp_orgseg;        // DSP 56001 ORG segment
24
25
26 // Fucntion prototypes
27 int m_unimp(WORD, WORD), m_badmode(WORD, WORD);
28 int dsp_ab(LONG);
29 int dsp_baab(LONG inst);
30 int dsp_acc48(LONG inst);
31 int dsp_self(LONG inst);
32 int dsp_xyab(LONG inst);
33 int dsp_x0y0ab(LONG inst);
34 int dsp_immcr(LONG inst);
35 int dsp_immmovec(LONG inst);
36 int dsp_imm12(LONG inst);
37 int dsp_tcc2(LONG inst);
38 int dsp_tcc4(LONG inst);
39 int dsp_ea(LONG inst);
40 int dsp_ea_imm5(LONG inst);
41 int dsp_abs12(LONG inst);
42 int dsp_reg_imm5(LONG inst);
43 int dsp_ea_abs16(LONG inst);
44 int dsp_reg_abs16(LONG inst);
45 int dsp_imm12_abs16(LONG inst);
46 int dsp_alu24_abs16(LONG inst);
47 int dsp_reg(LONG inst);
48 int dsp_alu24(LONG inst);
49 int dsp_reg_imm5_abs16(LONG inst);
50 int dsp_ea_imm5_abs16(LONG inst);
51 int dsp_ea_lua(LONG inst);
52 int dsp_ab_rn(LONG inst);
53 int dsp_movec_ea(LONG inst);
54 int dsp_movec_aa(LONG inst);
55 int dsp_movec_reg(LONG inst);
56 int dsp_mult(LONG inst);
57 int dsp_movem_ea(LONG inst);
58 int dsp_movem_aa(LONG inst);
59 int dsp_movep_ea(LONG inst);
60 int dsp_movep_reg(LONG inst);
61
62
63 // Common error messages
64
65
66 // Include code tables
67 MNTABDSP dsp56k_machtab[] = {
68    { 0xFFFFFFFF, 0xFFFFFFFF, 0x0000, 0x0000, 0, (int (*)(LONG))m_badmode }, // 0
69    #include "dsp56ktab.h"
70    {  0L,  0L, 0x0000, 0x0000, 0, (int (*)(LONG))m_unimp   }                   // Last entry
71 };
72
73
74 static inline int dsp_extra_ea()
75 {
76         if (deposit_extra_ea == DEPOSIT_EXTRA_WORD)
77         {
78                 if (!(dspImmedEXATTR & FLOAT))
79                 {
80                         if (dspImmedEXATTR & DEFINED)
81                         {
82                                 D_dsp(dspImmedEXVAL);
83                         }
84                         else
85                         {
86                                 // TODO: what if it's an address and not an immediate? Does it matter at all?
87                                 AddFixup(FU_DSPIMM24, sloc, dspImmedEXPR);
88                                 D_dsp(0);
89                         }
90                 }
91                 else
92                 {
93                         if (dspImmedEXATTR & DEFINED)
94                         {
95                                 D_dsp(dspImmedEXVAL);
96                         }
97                         else
98                         {
99                                 // TODO: what if it's an address and not an immediate? Does it matter at all?
100                                 AddFixup(FU_DSPIMMFL24, sloc, dspImmedEXPR);
101                                 D_dsp(0);
102                         }
103                 }
104         }
105         else if (deposit_extra_ea == DEPOSIT_EXTRA_FIXUP)
106         {
107                 // Probably superfluous check (we're not likely to land here with a
108                 // known aa) but oh well
109                 if (!(dspImmedEXATTR & DEFINED))
110                 {
111                         // Since we already deposited the word to be fixup'd we need to
112                         // subtract 1 from sloc
113                         chptr -= 3;
114                         AddFixup(FU_DSPADR06, sloc - 1, dspImmedEXPR);
115                         chptr += 3;
116                 }
117         }
118
119         return OK;
120 }
121
122
123 int dsp_ab(LONG inst)
124 {
125         inst |= (dsp_a0reg & 1) << 3;
126         D_dsp(inst);
127         dsp_extra_ea();         // Deposit effective address if needed
128         return OK;
129 }
130
131
132 int dsp_baab(LONG inst)
133 {
134         if (dsp_a0reg == dsp_a1reg)
135                 return error("source and destination registers must not be the same");
136
137         inst |= ((dsp_a0reg + 1) & 1) << 3;
138         D_dsp(inst);
139         dsp_extra_ea();         // Deposit effective address if needed
140
141         return OK;
142 }
143
144
145 int dsp_acc48(LONG inst)
146 {
147         if (dsp_a0reg == dsp_a1reg)
148                 return error("source and destination registers must not be the same");
149
150         inst |= (dsp_a1reg & 1) << 3;
151
152         switch (dsp_a0reg)
153         {
154         case KW_X:  inst |= 2 << 4; break;
155         case KW_Y:  inst |= 3 << 4; break;
156         case KW_X0: inst |= 4 << 4;break;
157         case KW_Y0: inst |= 5 << 4;break;
158         case KW_X1: inst |= 6 << 4;break;
159         case KW_Y1: inst |= 7 << 4;break;
160         default: return error("dsp_acc48: shouldn't reach here!");
161         }
162
163         D_dsp(inst);
164         dsp_extra_ea();         // Deposit effective address if needed
165
166         return OK;
167 }
168
169
170 int dsp_self(LONG inst)
171 {
172         D_dsp(inst);
173         dsp_extra_ea();         // Deposit effective address if needed
174
175         return OK;
176 }
177
178
179 int dsp_xyab(LONG inst)
180 {
181         if (dsp_a0reg == dsp_a1reg)
182                 return error("source and destination registers must not be the same");
183
184         inst |= (dsp_a0reg & 1) << 4;
185         inst |= (dsp_a1reg & 1) << 3;
186         D_dsp(inst);
187         dsp_extra_ea();         // Deposit effective address if needed
188
189         return OK;
190 }
191
192
193 int dsp_x0y0ab(LONG inst)
194 {
195         if (dsp_a0reg == dsp_a1reg)
196                 return error("source and destination registers must not be the same");
197
198         int inverse = (dsp_a0reg & 3);
199         inverse = ((inverse & 1) << 1) | ((inverse & 2) >> 1);
200         inst |= inverse << 4;
201         inst |= (dsp_a1reg & 1) << 3;
202         D_dsp(inst);
203         dsp_extra_ea();         // Deposit effective address if needed
204
205         return OK;
206 }
207
208
209 int dsp_immcr(LONG inst)
210 {
211         switch (dsp_a1reg)
212         {
213         case KW_CCR: inst |= 1; break;
214         case KW_MR:inst |= 0; break;
215         case KW_OMR:inst |= 2; break;
216         default: return error("invalid destination register (only ccr, mr, omr allowed");
217         }
218
219         if (dsp_a0exattr & DEFINED)
220         {
221                 inst |= dsp_a0exval << 8;
222                 D_dsp(inst);
223         }
224         else
225         {
226                 AddFixup(FU_DSPIMM8, sloc, dsp_a0expr);
227                 D_dsp(inst);
228         }
229
230         return OK;
231 }
232
233
234 int dsp_immmovec(LONG inst)
235 {
236         switch (dsp_a1reg)
237         {
238         case 0:
239         case 1:
240         case 2:
241         case 3:
242         case 4:
243         case 5:
244         case 6:
245         case 7:      inst |= dsp_a1reg; break; // M0-M7
246         case KW_SR:  inst |= 25; break;
247         case KW_OMR: inst |= 26; break;
248         case KW_SP:  inst |= 27; break;
249         case KW_SSH: inst |= 28; break;
250         case KW_SSL: inst |= 29; break;
251         case KW_LA:  inst |= 30; break;
252         case KW_LC:  inst |= 31; break;
253         default: return error("invalid destination register (only m0-m7, SR, OMR, SP, SSH, SSL, LA, LC allowed");
254         }
255
256         if (dsp_a0exattr & DEFINED)
257         {
258                 inst |= (dsp_a0exval & 0xff) << 8;
259                 D_dsp(inst);
260         }
261         else
262         {
263                 AddFixup(FU_DSPIMM8, sloc, dsp_a0expr);
264                 D_dsp(inst);
265         }
266
267         return OK;
268 }
269
270
271 int dsp_imm12(LONG inst)
272 {
273         if (dsp_a0exattr & DEFINED)
274         {
275                 if ((dsp_am0 & (M_DSPIM12 | M_DSPIM8)) == 0)
276                         return error("immediate out of range ($000-$fff)");
277                 inst |= ((dsp_a0exval & 0x0ff) << 8) | ((dsp_a0exval & 0xf00) >> 8);
278                 D_dsp(inst);
279         }
280         else
281         {
282                 AddFixup(FU_DSPIMM12, sloc, dsp_a0expr);
283                 D_dsp(inst);
284         }
285
286         return OK;
287 }
288
289
290 // Tcc instructions with 2 operands (48bit)
291 int dsp_tcc2(LONG inst)
292 {
293         if (dsp_a0reg == dsp_a1reg)
294                 return error("First pair of source and destination registers must not be the same");
295
296         int inverse;
297         inverse = (dsp_a0reg & 7);
298         inverse = ((inverse & 1) << 1) | ((inverse & 2) >> 1) | (inverse & 4);
299         inst |= inverse << 4;
300         inst |= ((dsp_a1reg) & 1) << 3;
301         D_dsp(inst);
302
303         return OK;
304 }
305
306
307 // Tcc instructions with 4 operands
308 int dsp_tcc4(LONG inst)
309 {
310         if (dsp_a0reg == dsp_a1reg)
311                 return error("First pair of source and destination registers must not be the same");
312
313         if (dsp_am2 != M_DSPR || dsp_am3 != M_DSPR)
314                 return error("Second pair of source and destination registers must be R0-R7");
315
316         if (dsp_am0 == M_ACC56 && dsp_am1 == M_ACC56)
317         {
318                 inst |= ((dsp_a0reg + 1) & 1) << 3;
319         }
320         else
321         {
322                 int inverse;
323                 inverse = (dsp_a0reg & 7);
324                 inverse = ((inverse & 1) << 1) | ((inverse & 2) >> 1) | (inverse & 4);
325                 inst |= inverse << 4;
326                 inst |= ((dsp_a1reg) & 1) << 3;
327         }
328
329         inst |= 1 << 16;
330         inst |= (dsp_a2reg << 8) | (dsp_a3reg);
331         D_dsp(inst);
332
333         return OK;
334 }
335
336
337 // Just store ea
338 int dsp_ea(LONG inst)
339 {
340         inst |= dsp_a0reg << 8;
341
342         if (dsp_a0memspace != -1)
343                 inst |= dsp_a0memspace;
344
345         if (dsp_am0 == M_DSPAA)
346                 inst |= ((dsp_a0exval & 0x3f) << 8);
347
348         D_dsp(inst);
349
350         if (dsp_a0reg == DSP_EA_ABS)
351         {
352                 if (dsp_a0exattr & DEFINED)
353                 {
354                         D_dsp(dsp_a0exval);
355                 }
356                 else
357                 {
358                         AddFixup(FU_DSPADR24, sloc, dsp_a0expr);
359                         D_dsp(0);
360                 }
361         }
362
363         return OK;
364 }
365
366
367 // Store ea and 5-bit constant
368 int dsp_ea_imm5(LONG inst)
369 {
370         if (dsp_a1memspace == -1)
371                 return error("Only X: or Y: memory space allowed");
372
373         if (dsp_a0exattr & DEFINED)
374         {
375                 int v = (int)dsp_a0exval;
376
377                 if (v < 0 || v > 23)
378                         return error("immediate value must be between 0 and 23");
379
380                 if (dsp_a1reg == DSP_EA_ABS)
381                 {
382                         inst |= (v | dsp_a1memspace | (dsp_a1reg << 8));
383                 }
384                 else
385                 {
386                         inst |= ((dsp_a1exval & 0x3F) << 8) | v | dsp_a1memspace | (dsp_a1reg << 8);
387                 }
388
389                 D_dsp(inst);
390
391                 if (dsp_a1reg == DSP_EA_ABS)
392                 {
393                         if (dsp_a1exattr & DEFINED)
394                         {
395                                 D_dsp(dsp_a1exval);
396                         }
397                         else
398                         {
399                                 AddFixup(FU_DSPADR24, sloc, dsp_a1expr);
400                                 D_dsp(0);
401                         }
402                 }
403         }
404         else
405         {
406                 if (dsp_a1reg == DSP_EA_ABS)
407                 {
408                         inst |= dsp_a1memspace | (dsp_a1reg << 8);
409                 }
410                 else
411                 {
412                         inst |= ((dsp_a1exval & 0x3F) << 8) | dsp_a1memspace | (dsp_a1reg << 8);
413                 }
414
415                 AddFixup(FU_DSPIMM5, sloc, dsp_a0expr);
416                 D_dsp(inst);
417
418                 if (dsp_a1reg == DSP_EA_ABS)
419                 {
420                         if (dsp_a1exattr & DEFINED)
421                         {
422                                 D_dsp(dsp_a1exval);
423                         }
424                         else
425                         {
426                                 AddFixup(FU_DSPADR24, sloc, dsp_a1expr);
427                                 D_dsp(0);
428                         }
429                 }
430         }
431
432         return OK;
433 }
434
435
436 // Processes the input register according to table A-18 of the Motorola DSP
437 // manual and returns the correct encoding.
438 // Note: returns only the 3 lower bits of the table. The rest is handled in
439 //       dsp56ktab.
440 static inline LONG tab_A18(int *am, int *reg)
441 {
442         switch (*am)
443         {
444         case M_ALU24:
445                 return (*reg & 7);
446         case M_DSPM:
447         case M_DSPN:
448         case M_DSPR:
449                 return *reg;
450                 break;
451         case M_ACC56:
452         case M_ACC24:
453         case M_ACC8:
454                 if (*reg == KW_A1)
455                         return 4;
456                 else
457                         return (*reg & 7);
458
459                 break;
460         case M_DSPPCU:
461                 switch (*reg)
462                 {
463                 case KW_SR:  return 1; break;
464                 case KW_OMR: return 2; break;
465                 case KW_SP:  return 3; break;
466                 case KW_SSH: return 4; break;
467                 case KW_SSL: return 5; break;
468                 case KW_LA:  return 6; break;
469                 case KW_LC:  return 7; break;
470                 default:
471                         return error("specified control register not allowed as destination");
472                         break;
473                 }
474
475                 break;
476         default:
477                 return error("reached at the end of tab_A18 - shouldn't happen!");
478         }
479 }
480
481
482 // Store register (table A-18 in the motorola manual) and 5-bit constant
483 int dsp_reg_imm5(LONG inst)
484 {
485         LONG reg;
486
487         if ((reg = tab_A18(&dsp_am1, &dsp_a1reg)) == ERROR)
488                 return ERROR;
489
490         inst |= (reg << 8);
491
492         if (dsp_a0exattr & DEFINED)
493         {
494                 int v = (int)dsp_a0exval;
495
496                 if (v < 0 || v > 23)
497                         return error("immediate value must be between 0 and 23");
498
499                 inst |= v;
500                 D_dsp(inst);
501         }
502         else
503         {
504                 AddFixup(FU_DSPIMM5, sloc, dsp_a0expr);
505                 D_dsp(inst);
506         }
507
508         return OK;
509 }
510
511
512 // Store 12-bit address
513 int dsp_abs12(LONG inst)
514 {
515         if (dsp_a0exattr & DEFINED)
516         {
517                 int v = (int)dsp_a0exval;
518
519                 if (v < 0 || v > 0xFFF)
520                         return error("immediate out of range ($000-$FFF)");
521
522                 inst |= v;
523                 D_dsp(inst);
524         }
525         else
526         {
527                 AddFixup(FU_DSPADR12, sloc, dsp_a0expr);
528                 D_dsp(inst);
529         }
530
531         return OK;
532 }
533
534
535 // Manipulate expr to append a '-1'. Used specifically for DO.
536 void append_minus_1(TOKEN * expr)
537 {
538         // Find where the end of expression is
539         while (*expr != ENDEXPR)
540         {
541                 if (*expr == SYMBOL || *expr == CONST || *expr == FCONST)
542                         expr++;
543                 else if (*expr == ACONST)
544                         expr += 3;
545
546                 expr++;
547         }
548
549         // Overwrite ENDEXPR and append '-1'
550         *expr++ = CONST;
551         uint64_t *expr64 = (uint64_t *)expr;
552         *expr64++ = 1;
553         expr = (uint32_t *)expr64;
554         *expr++ = '-';
555         *expr = ENDEXPR;
556 }
557
558
559 // Store a 12bit immediate and 16bit address.
560 // Note: This function is specifically handling DO. DO has a requirement of
561 //       storing the address of a label minus 1! Quoting the manual:
562 //       "Note: The assembler calculates the end-of-loop address to be loaded
563 //        into LA (the absolute address extension word) by evaluating the end
564 //        -of-loop expression <expr> and subtracting one. This is done to
565 //        accommodate the case where the last word in the DO loop is a two-word
566 //        instruction. Thus, the end-of-loop expression <expr> in the source
567 //        code must represent the address of the instruction AFTER the last
568 //        instruction in the loop as shown in the example."
569 //       This is fine if we know the address already, but a problem when we
570 //       don't.
571 int dsp_imm12_abs16(LONG inst)
572 {
573         if (dsp_a0exattr & DEFINED)
574         {
575                 if ((dsp_am0 & (M_DSPIM12 | M_DSPIM8)) == 0)
576                         return error("immediate out of range ($000-$FFF)");
577
578                 inst |= ((dsp_a0exval & 0x0FF) << 8) | ((dsp_a0exval & 0xF00) >> 8);
579                 D_dsp(inst);
580         }
581         else
582         {
583                 AddFixup(FU_DSPIMM12, sloc, dsp_a0expr);
584                 D_dsp(inst);
585         }
586
587         if (dsp_a1exattr & DEFINED)
588         {
589                 D_dsp((a1exval - 1));
590         }
591         else
592         {
593                 append_minus_1(dsp_a1expr);
594                 AddFixup(FU_DSPADR16, sloc, dsp_a1expr);
595                 D_dsp(0);
596         }
597
598         return OK;
599 }
600
601
602 // Just store ea and 16bit address
603 // Note: this function is specifically handling DO.
604 // The same notes as dsp_imm12_abs16 apply here.
605 int dsp_ea_abs16(LONG inst)
606 {
607         if ((dsp_a0reg == DSP_EA_ABS && dsp_a0memspace == -1) || dsp_a1reg == DSP_EA_IMM)
608                 return error("immediate values > 31 or absolute values not allowed");
609
610         if (dsp_a0exattr & DEFINED)
611         {
612                 if (dsp_a0exval > 31)
613                         return error("absolute address (aa) bigger than $1F");
614
615                 inst |= dsp_a0exval << 8;
616         }
617
618         inst |= dsp_a0reg << 8;
619
620         if (dsp_a0memspace == -1)
621                 return error("only X:, Y: address spaces allowed");
622
623         if ((deposit_extra_ea == DEPOSIT_EXTRA_FIXUP) || (dsp_a0reg == DSP_EA_ABS && dsp_am0 == M_DSPEA))
624         {
625                 // Change instruction to aa instead of ea. TODO: check if this is true
626                 // for all cases
627                 inst = 0x060000;
628                 inst |= dsp_a0memspace;
629
630                 // Probably superfluous check (we're not likely to land here with a
631                 // known aa) but oh well
632                 if (!(dsp_a0exattr & DEFINED))
633                 {
634                         AddFixup(FU_DSPADR06, sloc, dsp_a0expr);
635                         D_dsp(inst);
636                 }
637                 else
638                 {
639                         D_dsp(inst);
640                 }
641         }
642         else
643         {
644                 inst |= dsp_a0memspace;
645                 D_dsp(inst);
646         }
647
648         if (dsp_a1exattr & DEFINED)
649         {
650                 D_dsp((dsp_a1exval - 1));
651         }
652         else
653         {
654                 append_minus_1(dsp_a1expr);
655                 AddFixup(FU_DSPADR16, sloc, dsp_a1expr);
656                 D_dsp(0);
657         }
658
659         return OK;
660 }
661
662
663 // Store register (table A-18 in the motorola manual) 5-bit constant and 16bit address
664 // Note: this function is specifically handling DO.
665 // The same notes as dsp_imm12_abs16 apply here.
666 int dsp_reg_abs16(LONG inst)
667 {
668         LONG reg;
669
670         if ((reg = tab_A18(&dsp_am0, &dsp_a0reg)) == ERROR)
671                 return ERROR;
672
673         inst |= reg << 8;
674
675         if (dsp_a1exattr & DEFINED)
676         {
677                 int v = (int)dsp_a1exval - 1;
678                 D_dsp(inst);
679                 D_dsp(v);
680         }
681         else
682         {
683                 D_dsp(inst);
684                 append_minus_1(dsp_a1expr);
685                 AddFixup(FU_DSPADR16, sloc, dsp_a1expr);
686                 D_dsp(0);
687         }
688
689         return OK;
690 }
691
692
693 // Store ALU24 register and 16bit address
694 // Note: this function is specifically handling DO.
695 // The same notes as dsp_imm12_abs16 apply here.
696 int dsp_alu24_abs16(LONG inst)
697 {
698         inst |= (dsp_a0reg & 7) << 8;
699
700         if (dsp_a1exattr & DEFINED)
701         {
702                 int v = (int)dsp_a1exval - 1;
703                 D_dsp(inst);
704                 D_dsp(v);
705         }
706         else
707         {
708                 D_dsp(inst);
709                 append_minus_1(dsp_a1expr);
710                 AddFixup(FU_DSPADR16, sloc, dsp_a1expr);
711                 D_dsp(0);
712         }
713
714         return OK;
715 }
716
717
718 // Store register (table A-18 in the motorola manual)
719 int dsp_reg(LONG inst)
720 {
721         LONG reg;
722
723         if ((reg = tab_A18(&dsp_am0, &dsp_a0reg)) == ERROR)
724                 return ERROR;
725
726         inst |= reg << 8;
727         D_dsp(inst);
728
729         return OK;
730 }
731
732
733 int dsp_alu24(LONG inst)
734 {
735         inst |= (dsp_a0reg & 7) << 8;
736         D_dsp(inst);
737
738         return OK;
739 }
740
741
742 // Store register (table A-18 in the motorola manual) and 5-bit constant
743 int dsp_reg_imm5_abs16(LONG inst)
744 {
745         LONG reg;
746
747         // First, check that we have at best an 16bit absolute address in
748         // operand 3 since we don't check that anywhere else
749         if (dsp_a2exattr & DEFINED)
750         {
751                 if ((dsp_am2 & C_DSPABS16) == 0)
752                         return error("expected 16-bit address as third operand.");
753         }
754
755         if ((reg = tab_A18(&dsp_am1, &dsp_a1reg)) == ERROR)
756                 return ERROR;
757
758         inst |= reg << 8;
759
760         if (dsp_a0exattr & DEFINED)
761         {
762                 int v = (int)dsp_a0exval;
763
764                 if (v < 0 || v > 23)
765                         return error("immediate value must be between 0 and 23");
766
767                 inst |= v;
768                 D_dsp(inst);
769
770                 if (dsp_a2exattr & DEFINED)
771                 {
772                         int v = (int)dsp_a2exval;
773                         D_dsp(v);
774                 }
775                 else
776                 {
777                         AddFixup(FU_DSPADR16, sloc, dsp_a2expr);
778                         D_dsp(0);
779                 }
780         }
781         else
782         {
783                 AddFixup(FU_DSPIMM5, sloc, dsp_a0expr);
784                 D_dsp(inst);
785
786                 if (dsp_a2exattr & DEFINED)
787                 {
788                         int v = (int)dsp_a2exval;
789                         D_dsp(v);
790                 }
791                 else
792                 {
793                         AddFixup(FU_DSPADR16, sloc, dsp_a2expr);
794                         D_dsp(0);
795                 }
796         }
797
798         return OK;
799 }
800
801
802 // Store ea, 5-bit constant and 16-bit address in the extension word
803 int dsp_ea_imm5_abs16(LONG inst)
804 {
805         // First, check that we have at best an 16bit absolute address in
806         // operand 3 since we don't check that anywhere else
807         if (dsp_a2exattr&DEFINED)
808         {
809                 if ((dsp_am2&C_DSPABS16) == 0)
810                         return error("expected 16-bit address as third operand.");
811         }
812
813         if (dsp_a1memspace == -1)
814                 return error("Only X: or Y: memory space allowed");
815
816         if (dsp_am1 == M_DSPAA)
817         {
818                 if (dsp_a1exattr & DEFINED)
819                         inst |= (dsp_a1exval & 0x3F) << 8;
820                 else
821                         AddFixup(FU_DSPADR06, sloc, dsp_a1expr);
822         }
823
824         if (dsp_am1 == M_DSPPP)
825         {
826                 if (dsp_a1exattr & DEFINED)
827                         inst |= (dsp_a1exval & 0x3f) << 8;
828                 else
829                         AddFixup(FU_DSPPP06, sloc, dsp_a1expr);
830         }
831
832         if (dsp_a0exattr & DEFINED)
833         {
834                 int v = (int)dsp_a0exval;
835
836                 if (v < 0 || v > 23)
837                         return error("immediate value must be between 0 and 23");
838
839                 inst |= (dsp_a1reg << 8) | v | dsp_a1memspace;
840                 D_dsp(inst);
841
842                 if (dsp_a2exattr & DEFINED)
843                 {
844                         int v = (int)dsp_a2exval;
845                         D_dsp(v);
846                 }
847                 else
848                 {
849                         AddFixup(FU_DSPADR16, sloc, dsp_a2expr);
850                         D_dsp(0);
851                 }
852         }
853         else
854         {
855                 inst |= (dsp_a1reg << 8) | dsp_a1memspace;
856                 AddFixup(FU_DSPIMM5, sloc, dsp_a0expr);
857                 D_dsp(inst);
858
859                 if (dsp_a2exattr & DEFINED)
860                 {
861                         int v = (int)dsp_a2exval;
862                         D_dsp(v);
863                 }
864                 else
865                 {
866                         AddFixup(FU_DSPADR16, sloc, dsp_a2expr);
867                         D_dsp(0);
868                 }
869         }
870
871         return OK;
872 }
873
874
875 int dsp_ea_lua(LONG inst)
876 {
877         int am = dsp_a0reg & 0x38;
878
879         if (am != DSP_EA_POSTDEC && am != DSP_EA_POSTINC &&
880                 am != DSP_EA_POSTDEC1 && am != DSP_EA_POSTINC1)
881                 return error("addressing mode not allowed");
882
883         inst |= dsp_a0reg << 8;
884
885         if (dsp_am1 == M_DSPN)
886                 inst |= 1 << 3;
887
888         inst |= dsp_a1reg;
889         D_dsp(inst);
890
891         return OK;
892 }
893
894
895 int dsp_ab_rn(LONG inst)
896 {
897         inst |= (dsp_a1reg & 1) << 3;
898         inst |= (dsp_a0reg) << 8;
899         D_dsp(inst);
900
901         return OK;
902 }
903
904
905 int dsp_movec_ea(LONG inst)
906 {
907         int ea = dsp_a1reg;
908         int memspace = dsp_a1memspace;
909         WORD exattr = dsp_a1exattr;
910         LONG exval = (uint32_t)dsp_a1exval;
911         TOKEN * expr = dsp_a1expr;
912         int reg = dsp_a0reg;
913         int am = dsp_am0;
914         int reg2 = dsp_a1reg;
915
916         if (dsp_am0 == M_DSPEA || (dsp_am0 & C_DSPIM))
917         {
918                 ea = dsp_a0reg;
919                 exattr = dsp_a0exattr;
920                 exval = (uint32_t)dsp_a0exval;
921                 memspace = dsp_a0memspace;
922                 expr = dsp_a0expr;
923                 reg = dsp_a1reg;
924                 reg2 = dsp_a0reg;
925                 am = dsp_am1;
926         }
927
928         // Abort if unsupported registers are requested
929         if (reg == KW_PC || reg == KW_MR || reg == KW_CCR)
930                 return error("illegal registers for instruction.");
931
932         if (dsp_am0 & C_DSPIM)
933                 memspace = 0;
934
935         if (memspace == -1)
936                 return error("only x: or y: memory spaces allowed.");
937
938         // No memspace required when loading an immediate
939         if (dsp_am0 & C_DSPIM)
940                 memspace = 0;
941
942         reg = tab_A18(&am, &reg);
943         inst |= (ea << 8) | memspace | reg;
944
945         if (am == M_DSPPCU)
946                 inst |= 3 << 3;
947
948         D_dsp(inst);
949
950         if (reg2 == DSP_EA_ABS || (dsp_am0 & C_DSPIM))
951         {
952                 if (exattr & DEFINED)
953                 {
954                         int v = exval;
955                         D_dsp(v);
956                 }
957                 else
958                 {
959                         if (dsp_am0 == M_DSPIM)
960                         {
961                                 AddFixup(FU_DSPIMM24, sloc, expr);
962                                 D_dsp(0);
963                         }
964                         else
965                         {
966                                 AddFixup(FU_DSPADR24, sloc, expr);
967                                 D_dsp(0);
968                         }
969                 }
970         }
971
972         return OK;
973 }
974
975
976 int dsp_movec_aa(LONG inst)
977 {
978         int ea = dsp_a1reg;
979         int memspace = dsp_a1memspace;
980         WORD exattr = dsp_a1exattr;
981         LONG exval = (uint32_t)dsp_a1exval;
982         TOKEN * expr = dsp_a1expr;
983         int reg = dsp_a0reg;
984         int am = dsp_am0;
985         int reg2 = dsp_a1reg;
986
987         if (dsp_am0 == M_DSPAA)
988         {
989                 ea = dsp_a0reg;
990                 exattr = dsp_a0exattr;
991                 exval = (uint32_t)dsp_a0exval;
992                 memspace = dsp_a0memspace;
993                 expr = dsp_a0expr;
994                 reg = dsp_a1reg;
995                 reg2 = dsp_a0reg;
996                 am = dsp_am1;
997         }
998
999         // Abort if unsupported registers are requested
1000         if (reg == KW_PC || reg == KW_MR || reg == KW_CCR)
1001                 return error("PC, MR, CCR are illegal registers for this instruction.");
1002
1003         if (memspace == -1)
1004                 return error("only x: or y: memory spaces allowed.");
1005
1006         reg = tab_A18(&am, &reg);
1007         inst |= (ea << 8) | memspace | reg;
1008
1009         if (am == M_DSPPCU)
1010                 inst |= 3 << 3;
1011
1012         if (exattr & DEFINED)
1013         {
1014                 inst |= exval << 8;
1015                 D_dsp(inst);
1016         }
1017         else
1018         {
1019                 AddFixup(FU_DSPADR06, sloc, expr);
1020                 D_dsp(inst);
1021         }
1022
1023         return OK;
1024 }
1025
1026
1027 int dsp_movec_reg(LONG inst)
1028 {
1029         int am0 = dsp_am0;
1030         int am1 = dsp_am1;
1031
1032         // Abort if unsupported registers are requested
1033         if (dsp_a0reg == KW_PC || dsp_a0reg == KW_MR || dsp_a0reg == KW_CCR ||
1034                 dsp_a1reg == KW_PC || dsp_a1reg == KW_MR || dsp_a1reg == KW_CCR)
1035                 return error("PC, MR, CCR are illegal registers for this instruction.");
1036
1037         int reg1 = tab_A18(&dsp_am0, &dsp_a0reg);
1038         int reg2 = tab_A18(&dsp_am1, &dsp_a1reg);
1039
1040         if (inst & (1 << 15))
1041         {
1042                 // S1,D2
1043         }
1044         else
1045         {
1046                 // S2,D1
1047                 int temp = am0;
1048                 am0 = am1;
1049                 am1 = temp;
1050                 temp = reg1;
1051                 reg1 = reg2;
1052                 reg2 = temp;
1053         }
1054
1055         switch (am0)
1056         {
1057         case M_ALU24:  reg1 |= 0x00; break;
1058         case M_ACC8:
1059         case M_ACC24:  reg1 |= 0x08; break;
1060         case M_ACC56:  reg1 |= 0x0E; break;
1061         case M_DSPR:   reg1 |= 0x10; break;
1062         case M_DSPN:   reg1 |= 0x18; break;
1063         case M_DSPM:   reg1 |= 0x20; break;
1064         case M_DSPPCU: reg1 |= 0x38; break;
1065         default:
1066                 return error("reached the end of dsp_movec_reg case 1 - should not happen!");
1067         }
1068
1069         switch (am1)
1070         {
1071         case M_DSPM:   reg2 |= 0x00; break;
1072         case M_DSPPCU: reg2 |= 0x18; break;
1073         default:
1074                 return error("reached the end of dsp_movec_reg case 2 - should not happen!");
1075         }
1076
1077         inst |= (reg1 << 8) | reg2;
1078         D_dsp(inst);
1079
1080         return OK;
1081 }
1082
1083
1084 int dsp_mult(LONG inst)
1085 {
1086         if (dsp_am2 != M_ACC56)
1087                 return error("only A or B allowed as third operand.");
1088
1089         switch (((dsp_a0reg & 3) << 2) + (dsp_a1reg & 3))
1090         {
1091         case (0 << 2) + 0: inst |= 0 << 4; break; // x0 x0
1092         case (2 << 2) + 2: inst |= 1 << 4; break; // y0 y0
1093         case (1 << 2) + 0: inst |= 2 << 4; break; // x1 x0
1094         case (0 << 2) + 1: inst |= 2 << 4; break; // x0 x1
1095         case (3 << 2) + 2: inst |= 3 << 4; break; // y1 y0
1096         case (2 << 2) + 3: inst |= 3 << 4; break; // y0 y1
1097         case (0 << 2) + 3: inst |= 4 << 4; break; // x0 y1
1098         case (3 << 2) + 0: inst |= 4 << 4; break; // y1 x0
1099         case (2 << 2) + 0: inst |= 5 << 4; break; // y0 x0
1100         case (0 << 2) + 2: inst |= 5 << 4; break; // x0 y0
1101         case (1 << 2) + 2: inst |= 6 << 4; break; // x1 y0
1102         case (2 << 2) + 1: inst |= 6 << 4; break; // y0 x1
1103         case (3 << 2) + 1: inst |= 7 << 4; break; // y1 x1
1104         case (1 << 2) + 3: inst |= 7 << 4; break; // x1 y1
1105         default:
1106                 return error("x0/y0/x1/y1 combination not allowed for multiplication.");
1107         }
1108
1109         if (dsp_a2reg == KW_B)
1110                 inst |= 1 << 3;
1111
1112         inst |= dsp_k;
1113         D_dsp(inst);
1114         dsp_extra_ea();         // Deposit effective address if needed
1115
1116         return OK;
1117 }
1118
1119
1120 int dsp_movem_ea(LONG inst)
1121 {
1122         int ea = dsp_a1reg;
1123         int memspace = dsp_a0memspace;
1124         WORD exattr = dsp_a1exattr;
1125         LONG exval = (uint32_t)dsp_a1exval;
1126         TOKEN * expr = dsp_a1expr;
1127         int reg = dsp_a0reg;
1128         int am = dsp_am0;
1129         int reg2 = dsp_a1reg;
1130
1131         if (dsp_am0 == M_DSPEA || dsp_am0 == M_DSPIM)
1132         {
1133                 ea = dsp_a0reg;
1134                 exattr = dsp_a0exattr;
1135                 exval = (uint32_t)dsp_a0exval;
1136                 memspace = dsp_a0memspace;
1137                 expr = dsp_a0expr;
1138                 reg = dsp_a1reg;
1139                 reg2 = dsp_a0reg;
1140                 am = dsp_am1;
1141                 inst |= 1 << 15;
1142         }
1143
1144         // Abort if unsupported registers are requested
1145         if (reg == KW_PC || reg == KW_MR || reg == KW_CCR)
1146                 return error("illegal registers for instruction.");
1147
1148         if (memspace != -1)
1149                 return error("only p: memory space allowed.");
1150
1151         reg = tab_A18(&am, &reg);
1152         inst |= (ea << 8) | reg;
1153
1154         if (am == M_DSPPCU)
1155                 inst |= 3 << 3;
1156
1157         D_dsp(inst);
1158
1159         if (reg2 == DSP_EA_ABS || dsp_am0 == M_DSPIM)
1160         {
1161                 if (exattr & DEFINED)
1162                 {
1163                         int v = exval;
1164                         D_dsp(v);
1165                 }
1166                 else
1167                 {
1168                         if (dsp_am0 == M_DSPIM)
1169                         {
1170                                 AddFixup(FU_DSPIMM24, sloc, expr);
1171                                 D_dsp(0);
1172                         }
1173                         else
1174                         {
1175                                 AddFixup(FU_DSPADR24, sloc, expr);
1176                                 D_dsp(0);
1177                         }
1178                 }
1179         }
1180
1181         return OK;
1182 }
1183
1184
1185 int dsp_movem_aa(LONG inst)
1186 {
1187         int ea = dsp_a1reg;
1188         int memspace = dsp_a1memspace;
1189         WORD exattr = dsp_a1exattr;
1190         LONG exval = (uint32_t)dsp_a1exval;
1191         TOKEN * expr = dsp_a1expr;
1192         int reg = dsp_a0reg;
1193         int am = dsp_am0;
1194         int reg2 = dsp_a1reg;
1195
1196         if (dsp_am0 == M_DSPAA)
1197         {
1198                 ea = dsp_a0reg;
1199                 exattr = dsp_a0exattr;
1200                 exval = (uint32_t)dsp_a0exval;
1201                 memspace = dsp_a0memspace;
1202                 expr = dsp_a0expr;
1203                 reg = dsp_a1reg;
1204                 reg2 = dsp_a0reg;
1205                 am = dsp_am1;
1206         }
1207
1208         // Abort if unsupported registers are requested
1209         if (reg == KW_PC || reg == KW_MR || reg == KW_CCR)
1210                 return error("PC, MR, CCR are illegal registers for this instruction.");
1211
1212         if (memspace != -1)
1213                 return error("only p: memory space allowed.");
1214
1215         reg = tab_A18(&am, &reg);
1216         inst |= (ea << 8) | reg;
1217
1218         if (am == M_DSPPCU)
1219                 inst |= 3 << 3;
1220
1221         if (exattr & DEFINED)
1222         {
1223                 inst |= exval << 8;
1224                 D_dsp(inst);
1225         }
1226         else
1227         {
1228                 AddFixup(FU_DSPADR06, sloc, expr);
1229                 D_dsp(inst);
1230         }
1231
1232     return OK;
1233 }
1234
1235
1236 int dsp_movep_ea(LONG inst)
1237 {
1238         // movep doesn't allow any aa modes but we might detect this during amode
1239         // detection. No worries, just change it to ea with extra address instead
1240         if (dsp_am0 == M_DSPAA)
1241         {
1242                 dsp_a0reg = DSP_EA_ABS;
1243                 dsp_a1reg = 0;
1244         }
1245         if (dsp_am1 == M_DSPAA)
1246         {
1247                 dsp_a0reg = 0;
1248                 dsp_a1reg = DSP_EA_ABS;
1249         }
1250
1251         // So we might encounter something like 'movep x:pp,x:pp' which we
1252         // obviously flagged as M_DSPPP during ea parsing. In this case we give up
1253         // and declare the second term as a classic absolute address (we chop off
1254         // the high bits too) and let the routine treat is as such. At least that's
1255         // what Motorola's assembler seems to be doing.
1256         if (dsp_am0 == M_DSPPP && dsp_am1 == M_DSPPP)
1257         {
1258                 dsp_am1 = DSP_EA_ABS;
1259                 dsp_a1reg = DSP_EA_ABS;
1260                 dsp_a1exval &= 0xFFFF;
1261         }
1262
1263         // Assume first operand is :pp
1264         int ea = dsp_a1reg;
1265         int memspace = dsp_a1memspace;
1266         int perspace = dsp_a0perspace;
1267         WORD exattr = dsp_a1exattr;
1268         WORD exattr2 = dsp_a0exattr;
1269         LONG exval = (uint32_t)dsp_a1exval;
1270         LONG exval2 = (uint32_t)dsp_a0exval;
1271         TOKEN * expr = dsp_a1expr;
1272         TOKEN * expr2 = dsp_a0expr;
1273         int reg = dsp_a0reg;
1274         int am = dsp_am0;
1275         int reg2 = dsp_a1reg;
1276
1277         if (dsp_am1 == M_DSPPP)
1278         {
1279                 ea = dsp_a0reg;
1280                 exattr = dsp_a0exattr;
1281                 exattr2 = dsp_a1exattr;
1282                 exval = (uint32_t)dsp_a0exval;
1283                 exval2 = (uint32_t)dsp_a1exval;
1284                 memspace = dsp_a0memspace;
1285                 perspace = dsp_a1perspace;
1286                 expr = dsp_a0expr;
1287                 expr2 = dsp_a1expr;
1288                 reg = dsp_a1reg;
1289                 reg2 = dsp_a0reg;
1290                 am = dsp_am1;
1291         }
1292
1293         if (dsp_a0perspace == -1 && dsp_a1perspace == -1)
1294         {
1295                 // Ok, so now we have to guess which of the two parameters is X:pp or
1296                 // Y:pp. This happened because we didn't get a << marker in any of the
1297                 // addressing modes
1298                 if (((dsp_a0exattr | dsp_a1exattr) & DEFINED) == 0)
1299                         // You have got to be shitting me...
1300                         // One way to deal with this (for example X:ea,X:pp / X:pp,X:ea
1301                         // aliasing would be to check number ranges and see which one is
1302                         // negative. ...unless one of the two isn't known during this phase
1303                         return error("internal assembler error: could not deduce movep syntax");
1304
1305                 if (dsp_a0exattr & DEFINED)
1306                 {
1307                         if (dsp_a0exval >= 0xFFC0 && dsp_a0exval <= 0xFFFF)
1308                         {
1309                                 // First operand is :pp - do nothing
1310                                 perspace = dsp_a0memspace << 10;
1311                                 // When the source contains a << then we bolt on the :pp
1312                                 // address during ea parsing, but since we couldn't recognise
1313                                 // the addressing mode in this case let's just insert it right
1314                                 // now...
1315                                 reg |= (dsp_a0exval & 0x3F);
1316                         }
1317                 }
1318
1319                 if (dsp_a1exattr & DEFINED)
1320                 {
1321                         if (dsp_a1exval >= 0xFFC0 && dsp_a1exval <= 0xFFFF)
1322                         {
1323                                 ea = dsp_a0reg;
1324                                 exattr = dsp_a0exattr;
1325                                 exval = (uint32_t)dsp_a0exval;
1326                                 memspace = dsp_a0memspace;
1327                                 perspace = dsp_a1memspace << 10;
1328                                 expr = dsp_a0expr;
1329                                 reg = dsp_a0reg;
1330                                 reg2 = dsp_a1reg;
1331                                 am = dsp_am1;
1332                                 // See above
1333                                 reg |= (dsp_a1exval & 0x3F);
1334                         }
1335                 }
1336
1337                 if (perspace == -1)
1338                         // You have got to be shitting me (twice)...
1339                         return error("internal assembler error: could not deduce movep syntax");
1340         }
1341
1342         inst |= reg | (ea << 8) | perspace;       // reg contains memory space
1343
1344         if ((dsp_am0 & (M_DSPIM | M_DSPIM8 | M_DSPIM12)) == 0)
1345         {
1346                 if (memspace == -1)
1347                 {
1348                         inst &= ~(1 << 7);
1349                         inst |= 1 << 6;
1350                 }
1351                 else
1352                         inst |= memspace;
1353         }
1354
1355         if (am == M_DSPPP)
1356         {
1357                 if (exattr2&DEFINED)
1358                 {
1359                         inst |= (exval2 & 0x3F);
1360                         D_dsp(inst);
1361                 }
1362                 else
1363                 {
1364                         AddFixup(FU_DSPIMM5, sloc, expr2);
1365                         D_dsp(inst);
1366                 }
1367         }
1368         else
1369         {
1370                 D_dsp(inst);
1371         }
1372
1373         if (dsp_am0 & (M_DSPIM | M_DSPIM8 | M_DSPIM12))
1374         {
1375                 if (dsp_a0exattr & DEFINED)
1376                 {
1377                         int v = (int)dsp_a0exval;
1378                         D_dsp(v);
1379                 }
1380                 else
1381                 {
1382                         AddFixup(FU_DSPADR16, sloc, dsp_a0expr);
1383                         D_dsp(0);
1384                 }
1385         }
1386         else if (reg2 == DSP_EA_ABS)
1387         {
1388                 if (exattr & DEFINED)
1389                 {
1390                         int v = exval;
1391                         D_dsp(v);
1392                 }
1393                 else
1394                 {
1395                         AddFixup(FU_DSPADR24, sloc, expr);
1396                         D_dsp(0);
1397                 }
1398         }
1399
1400         return OK;
1401 }
1402
1403
1404 int dsp_movep_reg(LONG inst)
1405 {
1406         // Assume first operand is :pp
1407         int ea = dsp_a0reg;
1408         int memspace = dsp_a0memspace;
1409         int perspace = dsp_a0perspace;
1410         WORD exattr = dsp_a1exattr;
1411         LONG exval = (uint32_t)dsp_a1exval;
1412         TOKEN * expr = dsp_a1expr;
1413         int reg = dsp_a0reg;
1414         int am = dsp_am1;
1415         int reg2 = dsp_a1reg;
1416
1417         if (dsp_am1 == M_DSPPP)
1418         {
1419                 ea = dsp_a1reg;
1420                 exattr = dsp_a0exattr;
1421                 exval = (uint32_t)dsp_a0exval;
1422                 memspace = dsp_a1memspace;
1423                 perspace = dsp_a1perspace;
1424                 expr = dsp_a0expr;
1425                 reg = dsp_a1reg;
1426                 reg2 = dsp_a0reg;
1427                 am = dsp_am0;
1428         }
1429
1430         // Abort if unsupported registers are requested
1431         if (reg == KW_PC || reg == KW_MR || reg == KW_CCR)
1432                 return error("illegal registers for instruction.");
1433
1434         reg2 = tab_A18(&am, &reg2);
1435         inst |= (reg2 << 8) | reg;
1436
1437         if (perspace == -1)
1438                 return error("only x: or y: memory space allowed.");
1439         else
1440                 inst |= perspace;
1441
1442         D_dsp(inst);
1443
1444         if (reg2 == DSP_EA_ABS)
1445         {
1446                 if (exattr & DEFINED)
1447                 {
1448                         int v = exval;
1449                         D_dsp(v);
1450                 }
1451                 else
1452                 {
1453                         AddFixup(FU_DSPADR24, sloc, expr);
1454                         D_dsp(0);
1455                 }
1456         }
1457
1458         return OK;
1459 }
1460