Now we're pretty sure that the codebase doesn't cause any regressions.
[rmac] / procln.c
1 //
2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // PROCLN.C - Line Processing
4 // Copyright (C) 199x Landon Dyer, 2011-2018 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 "procln.h"
10 #include "6502.h"
11 #include "amode.h"
12 #include "direct.h"
13 #include "dsp56k_amode.h"
14 #include "dsp56k_mach.h"
15 #include "error.h"
16 #include "expr.h"
17 #include "listing.h"
18 #include "mach.h"
19 #include "macro.h"
20 #include "op.h"
21 #include "riscasm.h"
22 #include "sect.h"
23 #include "symbol.h"
24
25 #define DEF_KW                                  // Declare keyword values
26 #include "kwtab.h"                              // Incl generated keyword tables & defs
27
28 #define DEF_MN                                  // Incl 68k keyword definitions
29 #define DECL_MN                                 // Incl 68k keyword state machine tables
30 #include "mntab.h"
31
32 #define DEF_MR
33 #define DECL_MR
34 #include "risckw.h"
35
36 #define DEF_MP                                  // Include 6502 keyword definitions
37 #define DECL_MP                                 // Include 6502 keyword state machine tables
38 #include "6502kw.h"
39
40 #define DEF_MO                                  // Include OP keyword definitions
41 #define DECL_MO                                 // Include OP keyword state machine tables
42 #include "opkw.h"
43
44 #define DEF_DSP                                 // Include DSP56K keywords definitions
45 #define DECL_DSP                                // Include DSP56K keyword state machine tables
46 #include "dsp56kkw.h"
47
48
49 IFENT * ifent;                                  // Current ifent
50 static IFENT ifent0;                    // Root ifent
51 IFENT * f_ifent;                                // Freelist of ifents
52 int disabled;                                   // Assembly conditionally disabled
53 int just_bss;                                   // 1, ds.b in microprocessor mode
54 uint32_t pcloc;                                 // Value of "PC" at beginning of line
55 SYM * lab_sym;                                  // Label on line (or NULL)
56
57 const char extra_stuff[] = "extra (unexpected) text found after addressing mode";
58 const char comma_error[] = "missing comma";
59 const char syntax_error[] = "syntax error";
60 const char locgl_error[] = "cannot GLOBL local symbol";
61 const char lab_ignored[] = "label ignored";
62
63 // Table to convert an addressing-mode number to a bitmask.
64 LONG amsktab[0124] = {
65         M_DREG, M_DREG, M_DREG, M_DREG,
66         M_DREG, M_DREG, M_DREG, M_DREG,
67
68         M_AREG, M_AREG, M_AREG, M_AREG,
69         M_AREG, M_AREG, M_AREG, M_AREG,
70
71         M_AIND, M_AIND, M_AIND, M_AIND,
72         M_AIND, M_AIND, M_AIND, M_AIND,
73
74         M_APOSTINC, M_APOSTINC, M_APOSTINC, M_APOSTINC,
75         M_APOSTINC, M_APOSTINC, M_APOSTINC, M_APOSTINC,
76
77         M_APREDEC, M_APREDEC, M_APREDEC, M_APREDEC,
78         M_APREDEC, M_APREDEC, M_APREDEC, M_APREDEC,
79
80         M_ADISP, M_ADISP, M_ADISP, M_ADISP,
81         M_ADISP, M_ADISP, M_ADISP, M_ADISP,
82
83         M_AINDEXED, M_AINDEXED, M_AINDEXED, M_AINDEXED,
84         M_AINDEXED, M_AINDEXED, M_AINDEXED, M_AINDEXED,
85
86         M_ABSW,                 // 070
87         M_ABSL,                 // 071
88         M_PCDISP,               // 072
89         M_PCINDEXED,    // 073
90         M_IMMED,                // 074
91         0L,                             // 075
92         0L,                             // 076
93         0L,                             // 077
94         M_ABASE,                // 0100
95         M_MEMPOST,              // 0101
96         M_MEMPRE,               // 0102
97         M_PCBASE,               // 0103
98         M_PCMPOST,              // 0104
99         M_PCMPRE,               // 0105
100         M_AM_USP,               // 0106
101         M_AM_SR,                // 0107
102         M_AM_CCR,               // 0110
103         M_AM_NONE,              // 0111
104         0x30,                   // 0112
105         0x30,                   // 0113
106         0L,                             // 0114
107         0L,                             // 0115
108         0L,                             // 0116
109         0L,                             // 0117
110         M_CACHE40,              // 0120
111         M_CREG,                 // 0121
112         M_FREG,                 // 0122
113         M_FPSCR                 // 0123
114 };                                      // 0123 length
115
116
117 // Function prototypes
118 int HandleLabel(char *, int);
119
120
121 //
122 // Initialize line processor
123 //
124 void InitLineProcessor(void)
125 {
126         disabled = 0;
127         ifent = &ifent0;
128         f_ifent = ifent0.if_prev = NULL;
129         ifent0.if_state = 0;
130 }
131
132
133 //
134 // Line processor
135 //
136 void Assemble(void)
137 {
138         int state;                                      // Keyword machine state (output)
139         int j;                                          // Random int, must be fast
140         char * p;                                       // Random char ptr, must be fast
141         TOKEN * tk;                                     // First token in line
142         char * label;                           // Symbol (or NULL)
143         char * equate;                          // Symbol (or NULL)
144         int labtyp = 0;                         // Label type (':', DCOLON)
145         int equtyp = 0;                         // Equ type ('=', DEQUALS)
146         uint64_t eval;                          // Expression value
147         WORD eattr;                                     // Expression attributes
148         SYM * esym;                                     // External symbol involved in expr.
149         WORD siz = 0;                           // Size suffix to mnem/diretve/macro
150         LONG amsk0, amsk1;                      // Address-type masks for ea0, ea1
151         MNTAB * m;                                      // Code generation table pointer
152         SYM * sy, * sy2;                        // Symbol (temp usage)
153         char * opname = NULL;           // Name of dirctve/mnemonic/macro
154         int listflag;                           // 0: Don't call listeol()
155         WORD rmask;                                     // Register list, for REG
156         int registerbank;                       // RISC register bank
157         int riscreg;                            // RISC register
158         listflag = 0;                           // Initialise listing flag
159
160 loop:                                                   // Line processing loop label
161
162         // Get another line of tokens
163         if (TokenizeLine() == TKEOF)
164         {
165 DEBUG { printf("Assemble: Found TKEOF flag...\n"); }
166                 if (list_flag && listflag)                      // Flush last line of source
167                         listeol();
168
169                 if (ifent->if_prev != NULL)                     // Check conditional token
170                         error("hit EOF without finding matching .endif");
171
172                 return;
173         }
174
175         DEBUG { DumpTokenBuffer(); }
176
177         if (list_flag)
178         {
179                 if (listflag && listing > 0)
180                         listeol();                                              // Tell listing generator about EOL
181
182                 lstout((char)(disabled ? '-' : lntag)); // Prepare new line for listing
183                 listflag = 1;                                           // OK to call `listeol' now
184                 just_bss = 0;                                           // Reset just_bss mode
185         }
186
187         state = -3;                                                             // No keyword (just EOL)
188         label = NULL;                                                   // No label
189         lab_sym = NULL;                                                 // No (exported) label
190         equate = NULL;                                                  // No equate
191         tk = tok;                                                               // Save first token in line
192         pcloc = (uint32_t)sloc;                                 // Set beginning-of-line PC
193
194 loop1:                                                                          // Internal line processing loop
195
196         if (*tok == EOL)                                                // Restart loop if end-of-line
197                 goto loop;
198
199         // First token MUST be a symbol (Shamus: not sure why :-/)
200         if (*tok != SYMBOL)
201         {
202                 if ((*tok >= KW_D0) && (*tok <= KW_R31))
203                         error("cannot use reserved keyword as label name or .equ");
204                 else
205                         error("syntax error; expected symbol");
206
207                 goto loop;
208         }
209
210         j = (int)tok[2];                                                // Skip equates (normal statements)
211
212         if (j == '=' || j == DEQUALS || j == SET || j == REG || j == EQUREG || j == CCDEF)
213         {
214                 equate = string[tok[1]];
215                 equtyp = j;
216                 tok += 3;
217                 goto normal;
218         }
219
220         // Skip past label (but record it)
221         if (j == ':' || j == DCOLON)
222         {
223 as68label:
224                 label = string[tok[1]];                         // Get label name
225                 labtyp = tok[2];                                        // Get label type
226                 tok += 3;                                                       // Go to next line token
227
228                 // AS68 MODE:
229                 // Looks like another label follows the previous one, so handle
230                 // the previous one until there aren't any more
231                 if (as68_flag && (*tok == SYMBOL && tok[2] == ':'))
232                 {
233                         if (HandleLabel(label, labtyp) != 0)
234                                 goto loop;
235
236                         goto as68label;
237                 }
238         }
239
240         // EOL is legal here...
241         if (*tok == EOL)
242                 goto normal;
243
244         // First token MUST be a symbol (if we get here, tok didn't advance)
245         if (*tok++ != SYMBOL)
246         {
247                 error("syntax error; expected symbol");
248                 goto loop;
249         }
250
251         opname = p = string[*tok++];
252
253         // Check to see if the SYMBOL is a keyword (a mnemonic or directive).
254         // On output, `state' will have one of the values:
255         //    -3          there was no symbol (EOL)
256         //    -2..-1      the symbol didn't match any keyword
257         //    0..499      vanilla directives (dc, ds, etc.)
258         //    500..999    electric directives (macro, rept, etc.)
259         //    1000..+     mnemonics (move, lsr, etc.)
260         for(state=0; state>=0;)
261         {
262                 j = mnbase[state] + (int)tolowertab[*p];
263
264                 // Reject, character doesn't match
265                 if (mncheck[j] != state)
266                 {
267                         state = -1;                                             // No match
268                         break;
269                 }
270
271                 // Must accept or reject at EOS
272                 if (!*++p)
273                 {
274                         state = mnaccept[j];                    // (-1 on no terminal match)
275                         break;
276                 }
277
278                 state = mntab[j];
279         }
280
281         // Check for ".b" ".w" ".l" after directive, macro or mnemonic.
282         siz = SIZN;
283
284         switch (*tok)
285         {
286         case DOTW: siz = SIZW, tok++; break;
287         case DOTL: siz = SIZL, tok++; break;
288         case DOTB: siz = SIZB, tok++; break;
289         case DOTD: siz = SIZD, tok++; break;
290         case DOTP: siz = SIZP, tok++; break;
291         case DOTQ: siz = SIZQ, tok++; break;
292         case DOTS: siz = SIZS, tok++; break;
293         case DOTX: siz = SIZX, tok++; break;
294         }
295
296         // Do special directives (500..999) (These must be handled in "real time")
297         if (state >= 500 && state < 1000)
298         {
299                 switch (state)
300                 {
301                 case MN_IF:
302                         d_if();
303                         goto loop;
304
305                 case MN_ELSE:
306                         d_else();
307                         goto loop;
308
309                 case MN_ENDIF:
310                         d_endif();
311                         goto loop;
312
313                 case MN_IIF:                                            // .iif --- immediate if
314                         if (disabled || expr(exprbuf, &eval, &eattr, &esym) != OK)
315                                 goto loop;
316
317                         if (!(eattr & DEFINED))
318                         {
319                                 error(undef_error);
320                                 goto loop;
321                         }
322
323                         if (*tok++ != ',')
324                         {
325                                 error(comma_error);
326                                 goto loop;
327                         }
328
329                         if (eval == 0)
330                                 goto loop;
331
332                         goto loop1;
333
334                 case MN_MACRO:                                          // .macro --- macro definition
335                         if (!disabled)
336                         {
337                                 // Label on a macro definition is bad mojo... Warn the user
338                                 if (label != NULL)
339                                         warn(lab_ignored);
340
341                                 DefineMacro();
342                         }
343
344                         goto loop;
345
346                 case MN_EXITM:                                          // .exitm --- exit macro
347                 case MN_ENDM:                                           // .endm --- same as .exitm
348                         if (!disabled)
349                         {
350                                 if (label != NULL)
351                                         warn(lab_ignored);
352
353                                 ExitMacro();
354                         }
355
356                         goto loop;
357
358                 case MN_REPT:
359                         if (!disabled)
360                         {
361                                 // Handle labels on REPT directive lines...
362                                 if (label)
363                                 {
364                                         if (HandleLabel(label, labtyp) != 0)
365                                                 goto loop;
366                                 }
367
368                                 HandleRept();
369                         }
370
371                         goto loop;
372
373                 case MN_ENDR:
374                         if (!disabled)
375                                 error("mis-nested .endr");
376
377                         goto loop;
378                 }
379         }
380
381 normal:
382         if (disabled)                                                   // Conditionally disabled code
383                 goto loop;
384
385         // Do equates
386         if (equate != NULL)
387         {
388                 // Pick global or local symbol enviroment
389                 j = (*equate == '.' ? curenv : 0);
390                 sy = lookup(equate, LABEL, j);
391
392                 if (sy == NULL)
393                 {
394                         sy = NewSymbol(equate, LABEL, j);
395                         sy->sattr = 0;
396
397                         if (equtyp == DEQUALS)
398                         {
399                                 // Can't GLOBAL a local symbol
400                                 if (j)
401                                 {
402                                         error(locgl_error);
403                                         goto loop;
404                                 }
405
406                                 sy->sattr = GLOBAL;
407                         }
408                 }
409                 else if ((sy->sattr & DEFINED) && equtyp != SET)
410                 {
411                         if ((equtyp == EQUREG) && (sy->sattre & UNDEF_EQUR))
412                         {
413                                 sy->sattre &= ~UNDEF_EQUR;
414                                 sy->svalue = 0;
415                         }
416                         else if ((equtyp == CCDEF) && (sy->sattre & UNDEF_CC))
417                         {
418                                 sy->sattre &= ~UNDEF_CC;
419                                 sy->svalue = 0;
420                         }
421                         else
422                         {
423                                 error("multiple equate to '%s'", sy->sname);
424                                 goto loop;
425                         }
426                 }
427
428                 // Put symbol in "order of definition" list if it's not already there
429                 AddToSymbolDeclarationList(sy);
430
431                 // Parse value to equate symbol to;
432                 // o  .equr
433                 // o  .reg
434                 // o  everything else
435                 if (equtyp == EQUREG)
436                 {
437 //Linko's request to issue a warning on labels that equated to the same
438 //register would go here. Not sure how to implement it though. :-/
439 /*
440 Maybe like this way:
441 have an array of bools with 64 entries. Whenever a register is equated, set the
442 corresponding register bool to true. Whenever it's undef'ed, set it to false.
443 When checking to see if it's already been equated, issue a warning.
444 */
445                         // Check that we are in a RISC section
446                         if (!rgpu && !rdsp)
447                         {
448                                 error(".equr/.regequ must be defined in .gpu/.dsp section");
449                                 goto loop;
450                         }
451
452                         // Check for register to equate to
453                         if ((*tok >= KW_R0) && (*tok <= KW_R31))
454                         {
455 //                              sy->sattre  = EQUATEDREG | RISCSYM;     // Mark as equated register
456                                 sy->sattre  = EQUATEDREG;       // Mark as equated register
457                                 riscreg = (*tok - KW_R0);
458 //is there any reason to do this, since we're putting this in svalue?
459 //i'm thinking, no. Let's test that out! :-D
460 //                              sy->sattre |= (riscreg << 8);           // Store register number
461 //everything seems to build fine without it... We'll leave it here Just In Case(tm)
462
463 #define DEBODGE_REGBANK
464 #ifdef DEBODGE_REGBANK
465                                 // Default is current state of "regbank"
466                                 registerbank = regbank;
467 #else
468                                 // Default is no register bank specified
469                                 registerbank = BANK_N;
470 #endif
471
472                                 // Check for ",<bank #>" override notation
473                                 if ((tok[1] == ',') && (tok[2] == CONST))
474                                 {
475                                         // Advance token pointer to the constant
476                                         tok += 3;
477
478                                         // Anything other than a 0 or a 1 will result in "No Bank"
479                                         if (*(uint64_t *)tok == 0)
480                                                 registerbank = BANK_0;
481                                         else if (*(uint64_t *)tok == 1)
482                                                 registerbank = BANK_1;
483                                 }
484
485 #ifdef DEBODGE_REGBANK
486                                 sy->sattre |= registerbank;     // Store register bank
487 #else
488 // What needs to happen here is to prime registerbank with regbank, then use
489 // registerbank down below for the bank marking.
490 #warning "!!! regbank <-> registerbank confusion here !!!"
491 // The question here is why, if we're allowed to override the ".regbankN" rules
492 // above, then why is it using the one set by the directive in the extended
493 // attributes and not in what ends up in symbol->svalue?
494 // ".regbankN" is not an original Madmac directive, so it's suspect
495                                 sy->sattre |= regbank;          // Store register bank
496 #endif
497                                 eattr = ABS | DEFINED | GLOBAL;
498                                 eval = riscreg;
499                                 tok++;
500                         }
501                         // Checking for a register symbol
502                         else if (tok[0] == SYMBOL)
503                         {
504                                 sy2 = lookup(string[tok[1]], LABEL, j);
505
506                                 // Make sure symbol is a valid equreg
507                                 if (!sy2 || !(sy2->sattre & EQUATEDREG))
508                                 {
509                                         error("invalid GPU/DSP .equr/.regequ definition");
510                                         goto loop;
511                                 }
512                                 else
513                                 {
514                                         eattr = ABS | DEFINED | GLOBAL; // Copy symbols attributes
515                                         sy->sattre = sy2->sattre;
516                                         eval = (sy2->svalue & 0xFFFFF0FF);
517                                         tok += 2;
518                                 }
519                         }
520                         else
521                         {
522                                 error("invalid GPU/DSP .equr/.regequ definition");
523                                 goto loop;
524                         }
525                 }
526                 else if (equtyp == REG)
527                 {
528                         if (reglist(&rmask) < 0)
529                                 goto loop;
530
531                         eval = (uint32_t)rmask;
532                         eattr = ABS | DEFINED;
533                 }
534                 else if (equtyp == CCDEF)
535                 {
536                         sy->sattre |= EQUATEDCC;
537                         eattr = ABS | DEFINED | GLOBAL;
538
539                         if (tok[0] == SYMBOL)
540                         {
541                                 sy2 = lookup(string[tok[1]], LABEL, j);
542
543                                 if (!sy2 || !(sy2->sattre & EQUATEDCC))
544                                 {
545                                         error("invalid gpu/dsp .ccdef definition");
546                                         goto loop;
547                                 }
548                                 else
549                                 {
550                                         eattr = ABS | DEFINED | GLOBAL;
551                                         sy->sattre = sy2->sattre;
552                                         eval = sy2->svalue;
553                                         tok += 2;
554                                 }
555                         }
556                         else if (expr(exprbuf, &eval, &eattr, &esym) != OK)
557                                 goto loop;
558                 }
559                 // equ an equr
560                 else if (*tok == SYMBOL)
561                 {
562                         sy2 = lookup(string[tok[1]], LABEL, j);
563
564                         if (sy2 && (sy2->sattre & EQUATEDREG))
565                         {
566                                 sy->stype = sy2->stype;
567                                 sy->sattr = sy2->sattr;
568                                 sy->sattre = sy2->sattre;
569                                 sy->svalue = sy2->svalue;
570                                 goto loop;
571                         }
572                         else if (expr(exprbuf, &eval, &eattr, &esym) != OK)
573                                 goto loop;
574                 }
575                 else if (expr(exprbuf, &eval, &eattr, &esym) != OK)
576                         goto loop;
577
578                 if (!(eattr & DEFINED))
579                 {
580                         error(undef_error);
581                         goto loop;
582                 }
583
584                 sy->sattr |= eattr | EQUATED;   // Symbol inherits value and attributes
585                 sy->svalue = eval;
586
587                 if (list_flag)                                  // Put value in listing
588                         listvalue((uint32_t)eval);
589
590                 at_eol();                                               // Must be at EOL now
591                 goto loop;
592         }
593
594         // Do labels
595         if (label != NULL)
596         {
597                 // Non-zero == error occurred
598                 if (HandleLabel(label, labtyp) != 0)
599                         goto loop;
600         }
601
602         // Punt on EOL
603         if (state == -3)
604                 goto loop;
605
606         // If we're in 6502 mode and are still in need of a mnemonic, then search
607         // for valid 6502 mnemonic.
608         if (m6502 && (state < 0 || state >= 1000))
609         {
610 #ifdef ST
611                 state = kmatch(opname, mpbase, mpcheck, mptab, mpaccept);
612 #else
613                 for(state=0, p=opname; state>= 0; )
614                 {
615                         j = mpbase[state] + tolowertab[*p];
616
617                         if (mpcheck[j] != state)        // Reject, character doesn't match
618                         {
619                                 state = -1;             // No match
620                                 break;
621                         }
622
623                         if (!*++p)
624                         {                       // Must accept or reject at EOS
625                                 state = mpaccept[j];    // (-1 on no terminal match)
626                                 break;
627                         }
628
629                         state = mptab[j];
630                 }
631 #endif
632
633                 // Call 6502 code generator if we found a mnemonic
634                 if (state >= 2000)
635                 {
636                         m6502cg(state - 2000);
637                         goto loop;
638                 }
639         }
640
641         // If we are in GPU or DSP mode and still in need of a mnemonic then search
642         // for one
643         if ((rgpu || rdsp) && (state < 0 || state >= 1000))
644         {
645                 for(state=0, p=opname; state>=0;)
646                 {
647                         j = mrbase[state] + (int)tolowertab[*p];
648
649                         // Reject, character doesn't match
650                         if (mrcheck[j] != state)
651                         {
652                                 state = -1;                                     // No match
653                                 break;
654                         }
655
656                         // Must accept or reject at EOS
657                         if (!*++p)
658                         {
659                                 state = mraccept[j];            // (-1 on no terminal match)
660                                 break;
661                         }
662
663                         state = mrtab[j];
664                 }
665
666                 // Call RISC code generator if we found a mnemonic
667                 if (state >= 3000)
668                 {
669                         GenerateRISCCode(state);
670                         goto loop;
671                 }
672         }
673
674         // If we are in OP mode and still in need of a mnemonic then search for one
675         if (robjproc && ((state < 0) || (state >= 1000)))
676         {
677                 for(state=0, p=opname; state>=0;)
678                 {
679                         j = mobase[state] + (int)tolowertab[*p];
680
681                         // Reject, character doesn't match
682                         if (mocheck[j] != state)
683                         {
684                                 state = -1;                                     // No match
685                                 break;
686                         }
687
688                         // Must accept or reject at EOS
689                         if (!*++p)
690                         {
691                                 state = moaccept[j];            // (-1 on no terminal match)
692                                 break;
693                         }
694
695                         state = motab[j];
696                 }
697
698                 // Call OP code generator if we found a mnemonic
699                 if (state >= 3100)
700                 {
701                         GenerateOPCode(state);
702                         goto loop;
703                 }
704         }
705
706         // If we are in 56K mode and still in need of a mnemonic then search for one
707         if (dsp56001 && ((state < 0) || (state >= 1000)))
708         {
709                 for(state=0, p=opname; state>=0;)
710                 {
711                         j = dspbase[state] + (int)tolowertab[*p];
712
713                         // Reject, character doesn't match
714                         if (dspcheck[j] != state)
715                         {
716                                 state = -1;                                     // No match
717                                 break;
718                         }
719
720                         // Must accept or reject at EOS
721                         if (!*++p)
722                         {
723                                 state = dspaccept[j];           // (-1 on no terminal match)
724                                 break;
725                         }
726
727                         state = dsptab[j];
728                 }
729
730                 // Call DSP code generator if we found a mnemonic
731                 if (state >= 2000)
732                 {
733                         LONG parcode;
734                         int operands;
735                         MNTABDSP * md = &dsp56k_machtab[state - 2000];
736                         deposit_extra_ea = 0;   // Assume no extra word needed
737
738                         if (md->mnfunc == dsp_mult)
739                         {
740                                 // Special case for multiplication instructions: they require
741                                 // 3 operands
742                                 if ((operands = dsp_amode(3)) == ERROR)
743                                         goto loop;
744                         }
745                         else if ((md->mnattr & PARMOVE) && md->mn0 != M_AM_NONE)
746                         {
747                                 if (dsp_amode(2) == ERROR)
748                                         goto loop;
749                         }
750                         else if ((md->mnattr & PARMOVE) && md->mn0 == M_AM_NONE)
751                         {
752                                 // Instructions that have parallel moves but use no operands
753                                 // (probably only move). In this case, don't parse addressing
754                                 // modes--just go straight to parallel parse
755                                 dsp_am0 = dsp_am1 = M_AM_NONE;
756                         }
757                         else
758                         {
759                                 // Non parallel move instructions can have up to 4 parameters
760                                 // (well, only tcc instructions really)
761                                 if ((operands = dsp_amode(4)) == ERROR)
762                                         goto loop;
763
764                                 if (operands == 4)
765                                 {
766                                         dsp_tcc4(md->mninst);
767                                         goto loop;
768                                 }
769                         }
770
771                         if (md->mnattr & PARMOVE)
772                         {
773                                 // Check for parallel moves
774                                 if ((parcode = parmoves(dsp_a1reg)) == ERROR)
775                                         goto loop;
776                         }
777                         else
778                         {
779                                 if (*tok != EOL)
780                                         error("parallel moves not allowed with this instruction");
781
782                                 parcode = 0;
783                         }
784
785                         while ((dsp_am0 & md->mn0) == 0 || (dsp_am1 & md->mn1) == 0)
786                                 md = &dsp56k_machtab[md->mncont];
787
788                         (*md->mnfunc)(md->mninst | (parcode << 8));
789                         goto loop;
790                 }
791         }
792
793         // Invoke macro or complain about bad mnemonic
794         if (state < 0)
795         {
796                 if ((sy = lookup(opname, MACRO, 0)) != NULL)
797                         InvokeMacro(sy, siz);
798                 else
799                         error("unknown op '%s'", opname);
800
801                 goto loop;
802         }
803
804         // Call directive handlers
805         if (state < 500)
806         {
807                 (*dirtab[state])(siz);
808                 goto loop;
809         }
810
811         // Do mnemonics
812         //  o  can't deposit instrs in BSS or ABS
813         //  o  do automatic .EVEN for instrs
814         //  o  allocate space for largest possible instr
815         //  o  can't do ".b" operations with an address register
816         if (scattr & SBSS)
817         {
818                 error("cannot initialize non-storage (BSS) section");
819                 goto loop;
820         }
821
822         if (sloc & 1)                                   // Automatic .even
823                 auto_even();
824
825         if (challoc - ch_size < 18)             // Make sure have space in current chunk
826                 chcheck(0);
827
828         m = &machtab[state - 1000];
829
830         // Call special-mode handler
831         if (m->mnattr & CGSPECIAL)
832         {
833                 (*m->mnfunc)(m->mninst, siz);
834                 goto loop;
835         }
836
837         if (amode(1) < 0)                               // Parse 0, 1 or 2 addr modes
838                 goto loop;
839
840         if (*tok != EOL)
841                 error(extra_stuff);
842
843         amsk0 = amsktab[am0];
844         amsk1 = amsktab[am1];
845
846         // Catch attempts to use ".B" with an address register (yes, this check
847         // does work at this level)
848         if (siz == SIZB && (am0 == AREG || am1 == AREG))
849         {
850                 error("cannot use '.b' with an address register");
851                 goto loop;
852         }
853
854         // Keep a backup of chptr (used for optimisations during codegen)
855         chptr_opcode = chptr;
856
857         while (!(m->mnattr & siz) || (amsk0 & m->mn0) == 0 || (amsk1 & m->mn1) == 0)
858                 m = &machtab[m->mncont];
859
860         DEBUG { printf("    68K: mninst=$%X, siz=$%X, mnattr=$%X, amsk0=$%X, mn0=$%X, amsk1=$%X, mn1=$%X\n", m->mninst, siz, m->mnattr, amsk0, m->mn0, amsk1, m->mn1); }
861
862         (*m->mnfunc)(m->mninst, siz);
863         goto loop;
864 }
865
866
867 //
868 // Handle the creation of labels
869 //
870 int HandleLabel(char * label, int labelType)
871 {
872         // Check for dot in front of label; means this is a local label if present
873         int environment = (*label == '.' ? curenv : 0);
874         SYM * symbol = lookup(label, LABEL, environment);
875
876         if (symbol == NULL)
877         {
878                 symbol = NewSymbol(label, LABEL, environment);
879                 symbol->sattr = 0;
880                 symbol->sattre = 0;
881         }
882         else if (symbol->sattr & DEFINED)
883                 return error("multiply-defined label '%s'", label);
884
885         // Put symbol in "order of definition" list if it's not already in it
886         AddToSymbolDeclarationList(symbol);
887
888         if (orgactive)
889         {
890                 symbol->svalue = orgaddr;
891                 symbol->sattr |= ABS | DEFINED | EQUATED;
892         }
893         else
894         {
895                 symbol->svalue = sloc;
896                 symbol->sattr |= DEFINED | cursect;
897         }
898
899         lab_sym = symbol;
900
901         // Yes, our CS professors told us to write checks for equality this way,
902         // but damn, it hurts my brain every time I look at it. :-/
903         if (0 == environment)
904                 curenv++;
905
906         // Make label global if it has a double colon
907         if (labelType == DCOLON)
908         {
909                 if (environment != 0)
910                         return error(locgl_error);
911
912                 symbol->sattr |= GLOBAL;
913         }
914
915         return 0;
916 }
917