f0abc54af621152b4ad92e72a53150c51c036d3a
[rmac] / procln.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // PROCLN.C - Line Processing
4 // Copyright (C) 199x Landon Dyer, 2011 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 "listing.h"
11 #include "amode.h"
12 #include "error.h"
13 #include "sect.h"
14 #include "expr.h"
15 #include "mach.h"
16 #include "direct.h"
17 #include "macro.h"
18 #include "symbol.h"
19 #include "risca.h"
20
21 #define DEF_KW                                              // Declare keyword values 
22 #include "kwtab.h"                                          // Incl generated keyword tables & defs
23
24 #define DEF_MN                                              // Incl 68k keyword definitions
25 #define DECL_MN                                             // Incl 68k keyword state machine tables
26 #include "mntab.h"
27
28 #define DEF_MR
29 #define DECL_MR
30 #include "risckw.h"
31
32 IFENT *ifent;                                               // Current ifent
33 static IFENT ifent0;                                        // Root ifent
34 static IFENT *f_ifent;                                      // Freelist of ifents
35 static int disabled;                                        // Assembly conditionally disabled
36 int just_bss;                                               // 1, ds.b in microprocessor mode 
37 VALUE pcloc;                                                // Value of "PC" at beginning of line 
38 IFENT *ifent;                                               // Current ifent
39 SYM *lab_sym;                                               // Label on line (or NULL)
40
41
42 char extra_stuff[] = "extra (unexpected) text found after addressing mode";
43 char *comma_error = "missing comma";
44 char *syntax_error = "syntax error";
45 char *locgl_error = "cannot GLOBL local symbol";
46 char *lab_ignored = "label ignored";
47
48 // Table to convert an addressing-mode number to a bitmask.
49 LONG amsktab[0112] = {
50    M_DREG, M_DREG, M_DREG, M_DREG,
51    M_DREG, M_DREG, M_DREG, M_DREG,
52
53    M_AREG, M_AREG, M_AREG, M_AREG,
54    M_AREG, M_AREG, M_AREG, M_AREG,
55
56    M_AIND, M_AIND, M_AIND, M_AIND,
57    M_AIND, M_AIND, M_AIND, M_AIND,
58
59    M_APOSTINC, M_APOSTINC, M_APOSTINC, M_APOSTINC,
60    M_APOSTINC, M_APOSTINC, M_APOSTINC, M_APOSTINC,
61
62    M_APREDEC, M_APREDEC, M_APREDEC, M_APREDEC,
63    M_APREDEC, M_APREDEC, M_APREDEC, M_APREDEC,
64
65    M_ADISP, M_ADISP, M_ADISP, M_ADISP,
66    M_ADISP, M_ADISP, M_ADISP, M_ADISP,
67
68    M_AINDEXED, M_AINDEXED, M_AINDEXED, M_AINDEXED,
69    M_AINDEXED, M_AINDEXED, M_AINDEXED, M_AINDEXED,
70
71    M_ABSW,                                                  // 070
72    M_ABSL,                                                  // 071
73    M_PCDISP,                                                // 072
74    M_PCINDEXED,                                             // 073
75    M_IMMED,                                                 // 074
76    0L,                                                      // 075
77    0L,                                                      // 076
78    0L,                                                      // 077
79    M_ABASE,                                                 // 0100
80    M_MEMPOST,                                               // 0101 
81    M_MEMPRE,                                                // 0102 
82    M_PCBASE,                                                // 0103
83    M_PCMPOST,                                               // 0104
84    M_PCMPRE,                                                // 0105
85    M_AM_USP,                                                // 0106
86    M_AM_SR,                                                 // 0107 
87    M_AM_CCR,                                                // 0110
88    M_AM_NONE                                                // 0111 
89 };                                                          // 0112 length
90
91 //
92 // --- Initialize Line Processor -------------------------------------------------------------------
93 //
94
95 void init_procln(void) {
96    disabled = 0;
97    ifent = &ifent0;
98    f_ifent = ifent0.if_prev = NULL;
99    ifent0.if_state = 0;
100 }
101
102 //
103 // --- Line Processor ------------------------------------------------------------------------------
104 //
105
106 void assemble(void) {
107    int state;                                               // Keyword machine state (output)
108    int j;                                                   // Random int, must be fast
109    char *p;                                                 // Random char ptr, must be fast
110    TOKEN *tk;                                               // First token in line
111    char *label;                                             // Symbol (or NULL)
112    char *equate;                                            // Symbol (or NULL)
113    int labtyp = 0;                                          // Label type (':', DCOLON)
114    int equtyp = 0;                                          // Equ type ('=', DEQUALS)
115    VALUE eval;                                              // Expression value
116    WORD eattr;                                              // Expression attributes
117    SYM *esym;                                               // External symbol involved in expr.
118    WORD siz = 0;                                            // Size suffix to mnem/diretve/macro
119    LONG amsk0, amsk1;                                       // Address-type masks for ea0, ea1
120    MNTAB *m;                                                // Code generation table pointer
121    SYM *sy, *sy2;                                           // Symbol (temp usage)
122    char *opname = NULL;                                     // Name of dirctve/mnemonic/macro
123    int listflag;                                            // 0: Don't call listeol()
124    int as68mode = 0;                                        // 1: Handle multiple labels
125    WORD rmask;                                              // Register list, for REG
126    int registerbank;                                        // RISC register bank
127    int riscreg;                                             // RISC register
128
129    listflag = 0;                                            // Initialise listing flag
130
131    loop:                                                    // Line processing loop label
132
133    if(tokln() == TKEOF) {                                   // Get another line of tokens
134       if(list_flag && listflag)                             // Flush last line of source
135          listeol();
136       if(ifent->if_prev != NULL)                            // Check conditional token
137          error("hit EOF without finding matching .endif");
138       return;
139    }
140
141    if(list_flag) {
142       if(listflag && listing > 0) listeol();                // Tell listing generator about EOL
143       lstout((char)(disabled ? '-' : lntag));               // Prepare new line for listing
144       listflag = 1;                                         // OK to call `listeol' now
145       just_bss = 0;                                         // Reset just_bss mode
146    }
147
148    state = -3;                                              // No keyword (just EOL)
149    label = NULL;                                            // No label
150    lab_sym = NULL;                                          // No (exported) label
151    equate = NULL;                                           // No equate
152    tk = tok;                                                // Save first token in line
153    pcloc = (VALUE)sloc;                                     // Set beginning-of-line PC
154
155    loop1:                                                   // Internal line processing loop
156
157    if(*tok == EOL)                                          // Restart loop if end-of-line
158       goto loop;
159
160    if(*tok != SYMBOL) {                                     // First token MUST be a symbol
161       error(syntax_error);
162       goto loop;
163    }
164
165    j = (int)tok[2];                                         // Skip equates (normal statements)
166    if(j == '=' ||       j == DEQUALS || j == SET || j == REG || j == EQUREG || j == CCDEF) {   
167       equate = (char *)tok[1];
168       equtyp = j;
169       tok += 3;
170       goto normal;
171    }
172
173    if(j == ':' || j == DCOLON) {                            // Skip past label (but record it)
174    
175       as68label:
176
177       label = (char *)tok[1];                               // Get label name
178       labtyp = tok[2];                                      // Get label type
179       tok += 3;                                             // Go to next line token
180
181       // Handle multiple labels; if there's another label, go process it, 
182       // and come back at `as68label' above.
183       if(as68_flag) {
184          as68mode = 0;
185          if(*tok == SYMBOL && tok[2] == ':') {
186             as68mode = 1;
187             goto do_label;
188          }
189       }
190    }
191
192    if(*tok == EOL)                                          // EOL is legal here...
193       goto normal;
194
195    if(*tok++ != SYMBOL) {                                   // Next token MUST be a symbol
196       error(syntax_error);
197       goto loop;
198    }
199    opname = p = (char *)*tok++;                             // Store opcode name here
200
201    // Check to see if the SYMBOL is a keyword (a mnemonic or directive).
202    // On output, `state' will have one of the values:
203    //    -3          there was no symbol (EOL)
204    //    -2..-1      the symbol didn't match any keyword
205    //    0..499      vanilla directives (dc, ds, etc.)
206    //    500..999    electric directives (macro, rept, etc.)
207    //    1000..+     mnemonics (move, lsr, etc.)
208    for(state = 0; state >= 0;) {
209       j = mnbase[state] + (int)tolowertab[*p];
210       if(mncheck[j] != state) {                             // Reject, character doesn't match
211          state = -1;                                        // No match
212          break;
213       }
214       if(!*++p) {                                           // Must accept or reject at EOS
215          state = mnaccept[j];                               // (-1 on no terminal match)
216          break;
217       }
218       state = mntab[j];
219    }
220
221    // Check for ".b" ".w" ".l" after directive, macro or mnemonic.
222    siz = SIZN;
223    if(*tok == DOTW) 
224       siz = SIZW, ++tok;
225    else if(*tok == DOTL)
226       siz = SIZL, ++tok;
227    else if(*tok == DOTB)
228       siz = SIZB, ++tok;
229
230    // Do special directives (500..999) (These must be handled in "real time")
231    if(state >= 500 && state < 1000)
232       switch(state) {
233          case MN_IF:
234             d_if();
235             goto loop;
236          case MN_ELSE:
237             d_else();
238             goto loop;
239          case MN_ENDIF:
240             d_endif();
241             goto loop;
242          case MN_IIF:                                       // .iif --- immediate if
243             if(disabled || expr(exprbuf, &eval, &eattr, &esym) != OK)
244                goto loop;
245             if(!(eattr & DEFINED)) {
246                error(undef_error);
247                goto loop;
248             }
249             if(*tok++ != ',') {
250                error(comma_error);
251                goto loop;
252             }
253             if(eval == 0)
254                goto loop;
255             goto loop1;
256          case MN_MACRO:                                     // .macro --- macro definition
257             if(!disabled) {
258                if(label != NULL)
259                   warn(lab_ignored);
260                defmac();
261             }
262             goto loop;
263          case MN_EXITM:                                     // .exitm --- exit macro
264          case MN_ENDM:                                      // .endm --- same as .exitm
265             if(!disabled) {
266                if(label != NULL)
267                   warn(lab_ignored);
268                exitmac();
269             }
270             goto loop;
271          case MN_REPT:
272             if(!disabled) {
273                if(label != NULL)
274                   warn(lab_ignored);
275                defrept();
276             }
277             goto loop;
278          case MN_ENDR:
279             if(!disabled)
280                error("mis-nested .endr");
281             goto loop;
282       }
283
284    normal:
285
286    if(disabled)                                             // Conditionally disabled code
287       goto loop;
288
289    // Do equates
290    if(equate != NULL) {
291       j = 0;                                                // Pick global or local sym enviroment
292       if(*equate == '.')
293          j = curenv;
294
295       sy = lookup(equate, LABEL, j);
296       if(sy == NULL) {
297          sy = newsym(equate, LABEL, j);
298          sy->sattr = 0;
299          if(equtyp == DEQUALS) {
300             if(j) {                                         // Can't GLOBAL a local symbol
301                error(locgl_error);
302                goto loop;
303             }
304             sy->sattr = GLOBAL;
305          }
306       } else if((sy->sattr & DEFINED) && equtyp != SET) {
307          if((equtyp == EQUREG) && (sy->sattre & UNDEF_EQUR)) {
308             sy->sattre |= ~UNDEF_EQUR; 
309             sy->svalue  = 0;
310          } else if((equtyp == CCDEF) && (sy->sattre & UNDEF_CC)) {
311             sy->sattre |= ~UNDEF_CC;
312             sy->svalue = 0;
313          } else {
314             errors("multiple equate to '%s'", sy->sname);
315             goto loop;
316          }
317       }
318
319       // Put symbol in "order of definition" list
320       if(!(sy->sattr & SDECLLIST)) sym_decl(sy);
321
322       // Parse value to equate symbol to;
323       // o  .equr
324       // o  .reg
325       // o  everything else
326       if(equtyp == EQUREG) {
327          if(!rgpu && !rdsp) {                               // Check that we are in a RISC section
328             error(".equr/.regequ must be defined in .gpu/.dsp section");
329             goto loop;
330          }
331          if((*tok >= KW_R0) && (*tok <= KW_R31)) {          // Check for register to equate to
332             sy->sattre  = EQUATEDREG | RISCSYM;             // Mark as equated register
333             riscreg = (*tok - KW_R0);
334             sy->sattre |= (riscreg << 8);                   // Store register number
335             if((tok[1] == ',') && (tok[2] == CONST)) {
336                tok += 3;
337                if(*tok == 0) registerbank = BANK_0;
338                else if(*tok == 1) registerbank = BANK_1;
339                else registerbank = BANK_N;
340             } else {
341                registerbank = BANK_N;
342             }
343             sy->sattre |= regbank;                          // Store register bank
344             eattr = ABS | DEFINED | GLOBAL;
345             eval = 0x80000080 + (riscreg) + (registerbank << 8);
346             tok++;
347          } else if(tok[0] == SYMBOL) {                      // Checking for a register symbol
348             sy2 = lookup((char *)tok[1], LABEL, j);
349             if(!sy2 || !(sy2->sattre & EQUATEDREG)) {       // Make sure symbol is a valid equreg
350                error("invalid GPU/DSP .equr/.regequ definition");
351                goto loop;
352             } else {
353                eattr = ABS | DEFINED | GLOBAL;              // Copy symbols attributes
354                sy->sattre = sy2->sattre;
355                eval = (sy2->svalue & 0xFFFFF0FF);
356                tok += 2;
357             }
358          } else {
359             error("invalid GPU/DSP .equr/.regequ definition");
360             goto loop;
361          }
362       } else if(equtyp == REG) {
363          if(reglist(&rmask) < 0)
364             goto loop;
365          eval = (VALUE)rmask;
366          eattr = ABS | DEFINED;
367       } else if(equtyp == CCDEF) {
368          sy->sattre |= EQUATEDCC;
369          eattr = ABS | DEFINED | GLOBAL;
370          if(tok[0] == SYMBOL) {
371             sy2 = lookup((char *)tok[1], LABEL, j);
372             if(!sy2 || !(sy2->sattre & EQUATEDCC)) {
373                error("invalid gpu/dsp .ccdef definition");
374                goto loop;
375             } else {
376                eattr = ABS | DEFINED | GLOBAL;
377                sy->sattre = sy2->sattre;
378                eval = sy2->svalue;
379                tok += 2;
380             }
381          } else
382             if(expr(exprbuf, &eval, &eattr, &esym) != OK)
383                goto loop;
384       } else if(*tok == SYMBOL) {  //equ a equr
385          sy2 = lookup((char *)tok[1], LABEL, j);
386          if(sy2 && (sy2->sattre & EQUATEDREG)) {
387             sy->stype = sy2->stype;
388             sy->sattr = sy2->sattr;
389             sy->sattre = sy2->sattre;
390             sy->svalue = (sy2->svalue & 0xFFFFF0FF);
391             goto loop;
392          } else 
393             if(expr(exprbuf, &eval, &eattr, &esym) != OK)
394                goto loop;
395       } else
396          if(expr(exprbuf, &eval, &eattr, &esym) != OK)
397             goto loop;
398
399       if(!(eattr & DEFINED)) {
400          error(undef_error);
401          goto loop;
402       }
403
404       
405       sy->sattr |= eattr | EQUATED;                         // Symbol inherits value and attributes
406       sy->svalue = eval;
407       if(list_flag)                                         // Put value in listing
408          listvalue(eval);
409
410       at_eol();                                             // Must be at EOL now
411       goto loop;
412    }
413
414    // Do labels
415    if(label != NULL) {
416
417       do_label:
418
419       j = 0;
420       if(*label == '.')
421          j = curenv;
422       sy = lookup(label, LABEL, j);
423
424       if(sy == NULL) {
425          sy = newsym(label, LABEL, j);
426          sy->sattr = 0;
427          sy->sattre = RISCSYM;
428       } else if(sy->sattr & DEFINED) {
429          errors("multiply-defined label '%s'", label);
430          goto loop;
431       }
432
433       // Put symbol in "order of definition" list
434       if(!(sy->sattr & SDECLLIST)) sym_decl(sy);
435
436       if(orgactive) {
437          sy->svalue = orgaddr;
438          sy->sattr |= ABS | DEFINED | EQUATED;
439       } else {
440          sy->svalue = sloc;
441          sy->sattr |= DEFINED | cursect;
442       }
443
444       lab_sym = sy;
445       if(!j)
446          ++curenv;
447
448       if(labtyp == DCOLON) {                                // Make label global
449          if(j) {
450             error(locgl_error);
451             goto loop;
452          }
453          sy->sattr |= GLOBAL;
454       }
455
456       // If we're in as68 mode, and there's another label, go back and handle it
457       if(as68_flag && as68mode)
458          goto as68label;
459    }
460
461    // Punt on EOL
462    if(state == -3)
463       goto loop;
464
465    // If we are in GPU or DSP mode and still in need of a mnemonic then search for one
466    if((rgpu || rdsp) && (state < 0 || state >= 1000)) {
467       for(state = 0, p = opname; state >= 0;) {
468          j = mrbase[state] + (int)tolowertab[*p];
469          if(mrcheck[j] != state)        {                          // Reject, character doesn't match
470             state = -1;                                     // No match
471             break;
472          }
473
474          if(!*++p) {                                        // Must accept or reject at EOS
475             state = mraccept[j];                            // (-1 on no terminal match)
476             break;
477          }
478          state = mrtab[j];
479       }
480
481       // Call RISC code generator if we found a mnemonic
482       if(state >= 3000) {
483          risccg(state);
484          goto loop;
485       }
486    }
487
488    // Invoke macro or complain about bad mnemonic
489    if(state < 0) {
490       if((sy = lookup(opname, MACRO, 0)) != NULL) 
491          invokemac(sy, siz);
492       else errors("unknown op '%s'", opname);
493       goto loop;
494    }
495
496    // Call directive handlers
497    if(state < 500) {
498       (*dirtab[state])(siz);
499       goto loop;
500    }
501
502    // Do mnemonics
503    // o  can't deposit instrs in BSS or ABS
504    // o  do automatic .EVEN for instrs
505    // o  allocate space for largest possible instr
506    // o  can't do ".b" operations with an address register
507    if(scattr & SBSS) {
508       error("cannot initialize non-storage (BSS) section");
509       goto loop;
510    }
511
512    if(sloc & 1)                                             // Automatic .even
513       auto_even();
514
515    if(challoc - ch_size < 18)                               // Make sure have space in current chunk
516       chcheck(0L);
517
518    m = &machtab[state - 1000];
519    if(m->mnattr & CGSPECIAL) {                              // Call special-mode handler
520       (*m->mnfunc)(m->mninst, siz);
521       goto loop;
522    }
523
524    if(amode(1) < 0)                                         // Parse 0, 1 or 2 addr modes
525       goto loop;
526
527    if(*tok != EOL)
528       error(extra_stuff);
529
530    amsk0 = amsktab[am0];
531    amsk1 = amsktab[am1];
532
533    // Catch attempts to use ".B" with an address register (yes, this check does work at this level)
534    if(siz == SIZB && (am0 == AREG || am1 == AREG)) {
535       error("cannot use '.b' with an address register");
536       goto loop;
537    }
538
539    for(;;) {
540       if((m->mnattr & siz) && (amsk0 & m->mn0) != 0 && (amsk1 & m->mn1) != 0) {
541          (*m->mnfunc)(m->mninst, siz);
542          goto loop;
543       }
544       m = &machtab[m->mncont];
545    }
546 }
547
548 // 
549 // --- .if, Start Conditional Assembly -------------------------------------------------------------
550 //
551
552 int d_if(void) {
553    IFENT *rif;
554    WORD eattr;
555    VALUE eval;
556    SYM *esym;
557
558    // Alloc an IFENTRY
559    if((rif = f_ifent) == NULL) rif = (IFENT *)amem((LONG)sizeof(IFENT));
560    else f_ifent = rif->if_prev;
561
562    rif->if_prev = ifent;
563    ifent = rif;
564
565    if(!disabled) {
566       if(expr(exprbuf, &eval, &eattr, &esym) != OK) return(0);
567       if((eattr & DEFINED) == 0) return(error(undef_error));
568       disabled = !eval;
569    }
570    rif->if_state = (WORD)disabled;
571    return(0);
572 }
573
574 // 
575 // --- .else, Do Alternate Case For .if ------------------------------------------------------------
576 //
577
578 int d_else(void) {
579    IFENT *rif;
580
581    rif = ifent;
582
583    if(rif->if_prev == NULL) return(error("mismatched .else"));
584
585    if(disabled) disabled = rif->if_prev->if_state;
586    else disabled = 1;
587
588    rif->if_state = (WORD)disabled;
589    return(0);
590 }
591
592 //
593 // -------------------------------------------------------------------------------------------------
594 // .endif, End of conditional assembly block
595 // This is also called by fpop() to pop levels of IFENTs in case a macro or include file exits 
596 // early with `exitm' or `end'.
597 // -------------------------------------------------------------------------------------------------
598 //
599
600 int d_endif(void) {
601    IFENT *rif;
602
603    rif = ifent;
604    if(rif->if_prev == NULL) return(error("mismatched .endif"));
605
606    ifent = rif->if_prev;
607    disabled = rif->if_prev->if_state;
608    rif->if_prev = f_ifent;
609    f_ifent = rif;
610    return(0);
611 }
612