]> Shamusworld >> Repos - rmac/blobdiff - 6502.c
Code cleanup, version bump for last commit. :-)
[rmac] / 6502.c
diff --git a/6502.c b/6502.c
index 823263ad96965f44f6a9cb12d49962aab9009e09..0e203f098b5dadc6c0647b065a791fb933d5f244 100644 (file)
--- a/6502.c
+++ b/6502.c
@@ -1,49 +1,35 @@
-/*
- *  6502 Assembler
- *
- *    Init6502 initialization
- *    d_6502    handle ".6502" directive
- *    m6502cg  generate code for a 6502 mnemonic
- *    d_org    handle 6502 section's ".org" directive
- *    m6502obj generate 6502 object file
- *
- */
-#include "rmac.h"
-#include "sect.h"
+//
+// 6502 Assembler
+//
+//    Init6502 initialization
+//    d_6502    handle ".6502" directive
+//    m6502cg  generate code for a 6502 mnemonic
+//    d_org    handle 6502 section's ".org" directive
+//    m6502obj generate 6502 object file
+//
+#include "direct.h"
 #include "expr.h"
 #include "error.h"
+#include "mach.h"
+#include "procln.h"
+#include "riscasm.h"
+#include "rmac.h"
+#include "sect.h"
+#include "token.h"
 
-#define        UPSEG_SIZE      0x10010L /* size of 6502 code buffer, 64K+16bytes */
-
-
-/*
- *  Imports
- */
-extern TOKEN *tok;             /* -> current token */
-extern int debug;              /* >0, in debug mode (-x) */
-extern int m6502;              /* 1, in 6502 mode */
-extern TOKEN exprbuf[];                /* "universal" postfix expression buffer */
-extern LONG lsloc;             /* `sloc' at start of line */
-extern unsigned orgactive;             // RISC/6502 org directive active
-extern unsigned orgaddr;               // Org'd address
-extern char * string[];
-
-extern char extra_stuff[];     /* needed-eol error message */
-extern char *range_error;      /* value-out-of-range error message */
-
-
-/*
- *  Exports
- */
-char in_6502mode[] = "directive illegal in .6502 section";
-static uint16_t orgmap[1024][2]; /* mark all 6502 org changes */
-uint16_t *currentorg = (uint16_t *)orgmap; /* current org range */
-
-/*
- *  6502 addressing modes;
- *  do not change these values.
- *
- */
+#define        UPSEG_SIZE      0x10010L // size of 6502 code buffer, 64K+16bytes
+
+//
+// Exported vars
+//
+const char in_6502mode[] = "directive illegal in .6502 section";
+static uint16_t orgmap[1024][2];               // Mark all 6502 org changes
+uint16_t * currentorg = &orgmap[0][0]; // Current org range
+
+//
+// 6502 addressing modes;
+// DO NOT CHANGE THESE VALUES.
+//
 #define        A65_ABS         0
 #define        A65_ABSX        1
 #define        A65_ABSY        2
@@ -59,11 +45,11 @@ uint16_t *currentorg = (uint16_t *)orgmap; /* current org range */
 #define A65_IMMEDH  12
 #define A65_IMMEDL  13
 
-#define        NMACHOPS 56             /* number of machine ops */
-#define        NMODES  14              /* number of addressing modes */
-#define        NOP     0xea            /* 6502 NOP instruction */
-#define        ILLEGAL 0xff            /* 'illegal instr' marker */
-#define END65  0xff            /* end-of-an-instr-list */
+#define        NMACHOPS 56             // Number of machine ops
+#define        NMODES  14              // Number of addressing modes
+#define        NOP     0xEA            // 6502 NOP instruction
+#define        ILLEGAL 0xFF    // 'Illegal instr' marker
+#define END65  0xFF    // End-of-an-instr-list
 
 static char imodes[] =
 {
@@ -139,48 +125,48 @@ static char imodes[] =
        A65_IMPL, 0x98, END65
 };
 
-static char ops[NMACHOPS][NMODES]; /* opcodes */
-static unsigned char inf[NMACHOPS][NMODES]; /* construction info */
+static char ops[NMACHOPS][NMODES];                     // Opcodes
+static unsigned char inf[NMACHOPS][NMODES];    // Construction info
 
+// Absolute-to-zeropage translation table
 static int abs2zp[] =
-{                              /* absolute-to-zeropage trans table */
-       A65_ZP,                 /* ABS */
-       A65_ZPX,                        /* ABSX */
-       A65_ZPY,                        /* ABSY */
-       -1,                             /* IMPL */
-       -1,                             /* IMMED */
-       -1,                             /* INDX */
-       -1,                             /* INDY */
-       -1,                             /* IND */
-       -1,                             /* REL */
-       -1,                             /* ZP */
-       -1,                             /* ZPX */
-       -1                              /* ZPY */
+{
+       A65_ZP,         // ABS
+       A65_ZPX,        // ABSX
+       A65_ZPY,        // ABSY
+       -1,                     // IMPL
+       -1,                     // IMMED
+       -1,                     // INDX
+       -1,                     // INDY
+       -1,                     // IND
+       -1,                     // REL
+       -1,                     // ZP
+       -1,                     // ZPX
+       -1                      // ZPY
 };
 
 
-/*
- *  initialize 6502 assembler
- *
- */
+//
+// Initialize 6502 assembler
+//
 void Init6502()
 {
        register int i;
        register int j;
-       register char *s;
 
-       s = imodes;
+       register char * s = imodes;
 
-       /* set all instruction slots to illegal */
-       for (i = 0; i < NMACHOPS; ++i)
-               for (j = 0; j < NMODES; ++j)
+       // Set all instruction slots to illegal
+       for(i=0; i<NMACHOPS; i++)
+               for(j=0; j<NMODES; j++)
                        inf[i][j] = ILLEGAL;
 
-       /* uncompress legal instructions into their slots */
-       for (i = 0; i < NMACHOPS; ++i)
+       // Uncompress legal instructions into their slots
+       for(i=0; i<NMACHOPS; i++)
        {
-               do {
-                       j = *s & 0xff;
+               do
+               {
+                       j = *s & 0xFF;
                        inf[i][j] = *s;
                        ops[i][j] = s[1];
 
@@ -192,226 +178,254 @@ void Init6502()
                                inf[i][A65_ZP] = A65_REL;
                                ops[i][A65_ZP] = s[1];
                        }
-               } while(*(s += 2) != (char)END65);
-               ++s;
+               }
+               while (*(s += 2) != (char)END65);
+
+               s++;
        }
 
-    /* set up first org section (set to zero) */
-    orgmap[0][0] = 0;
+       // Set up first org section (set to zero)
+       orgmap[0][0] = 0;
 }
 
 
-/*
- *  .6502 --- enter 6502 mode
- *
- */
+//
+// .6502 --- enter 6502 mode
+//
 int d_6502()
 {
-       SaveSection();                  /* save curent section */
-       SwitchSection(M6502);   /* switch to 6502 section */
-    if (challoc == 0) {
-        /*
-         *  Allocate and clear 64K of space for the 6502 section
-         */
-        chcheck(UPSEG_SIZE);
-        memset(sect[M6502].scode->chptr, 0, UPSEG_SIZE);
-    }
-    return 0;
+       SaveSection();                  // Save curent section
+       SwitchSection(M6502);   // Switch to 6502 section
+
+       if (challoc == 0)
+       {
+               // Allocate and clear 64K of space for the 6502 section
+               chcheck(UPSEG_SIZE);
+               memset(sect[M6502].scode->chptr, 0, UPSEG_SIZE);
+       }
+
+       return 0;
 }
 
 
-/*
- *  Do 6502 code generation
- *
- */
-VOID m6502cg(int op)
+//
+// Do 6502 code generation
+//
+void m6502cg(int op)
 {
-       register int amode;             /* (parsed) addressing mode */
+       register int amode;             // (Parsed) addressing mode
        register int i;
-       VALUE eval;                     /* expression value */
-       WORD eattr;                     /* expression attributes */
-       int zpreq;                      /* 1, optimize instr to zero-page form */
-       register char *p;               /* (temp) string usage */
-
-
-       ch_size = 0;            /* reset chunk size on every instruction */
-
-       /*
-        *  Parse 6502 addressing mode
-        *
-        */
+       VALUE eval;                             // Expression value
+       WORD eattr;                             // Expression attributes
+       int zpreq;                              // 1, optimize instr to zero-page form
+       register char * p;              // (Temp) string usage
+       ch_size = 0;                    // Reset chunk size on every instruction
+
+       //
+       // Parse 6502 addressing mode
+       //
        zpreq = 0;
+
        switch ((int)*tok)
        {
-               case EOL:
-                       amode = A65_IMPL;
-                       break;
+       case EOL:
+               amode = A65_IMPL;
+               break;
 
-               case '#':
-                       ++tok;
-            if (*tok == '>')
-            {
-                ++tok;
-                if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
-                amode = A65_IMMEDH;
-                break;
-            }
-            else if (*tok == '<')
-            {
-                ++tok;
-                if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
-                amode = A65_IMMEDL;
-                break;
-            }
-                       if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
-                       amode = A65_IMMED;
-                       break;
+       case '#':
+               tok++;
 
-               case '(':
-                       ++tok;
-                       if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
-
-                       if (*tok == ')')
-                       {                       /* (foo) or (foo),y */
-                               if (*++tok == ',')
-                               {                       /* (foo),y */
-                                       ++tok;
-                                       p = string[tok[1]];
-                                       if (*tok != SYMBOL ||
-                                                 p[1] != EOS ||
-                                                 (*p | 0x20) != 'y') /* sleazo tolower() */
-                                               goto badmode;
-                                       tok += 2;
-                                       amode = A65_INDY;
-                               }
-                               else amode = A65_IND;
-                       }
-                       else if (*tok == ',')
-                       {                       /* (foo,x) */
-                               ++tok;
-                               p = string[tok[1]];
-                               if (*tok != SYMBOL ||
-                                         p[1] != EOS ||
-                                         (*p | 0x20) != 'x') /* sleazo tolower() */
-                                       goto badmode;
-                               tok += 2;
-                               if (*tok++ != ')')
-                                       goto badmode;
-                               amode = A65_INDX;
-                       }
-                       else goto badmode;
+               if (*tok == '>')
+               {
+                       tok++;
+                       if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+                               return;
+
+                       amode = A65_IMMEDH;
                        break;
+               }
+               else if (*tok == '<')
+               {
+                       tok++;
+                       if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+                               return;
+
+                       amode = A65_IMMEDL;
+                       break;
+               }
+
+               if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+                       return;
+
+               amode = A65_IMMED;
+               break;
+
+       case '(':
+               tok++;
 
-               case '@':
-                       ++tok;
-                       if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
+               if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+                       return;
 
-                       if (*tok == '(')
+               if (*tok == ')')
+               {
+                       // (foo) or (foo),y
+                       if (*++tok == ',')
                        {
-                               ++tok;
+                               // (foo),y
+                               tok++;
                                p = string[tok[1]];
-                               if (*tok != SYMBOL ||
-                                         p[1] != EOS ||
-                                         tok[2] != ')' ||
-                                         tok[3] != EOL)
+
+                               if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'y') // Sleazo tolower()
                                        goto badmode;
 
-                               i = (*p | 0x20);        /* sleazo tolower */
-                               if (i == 'x')
-                                       amode = A65_INDX;
-                               else if (i == 'y')
-                                       amode = A65_INDY;
-                               else goto badmode;
-                               tok += 3;               /* past SYMBOL <string> ')' EOL */
-                               zpreq = 1;              /* request zeropage optimization */
+                               tok += 2;
+                               amode = A65_INDY;
                        }
-                       else if (*tok == EOL)
+                       else
                                amode = A65_IND;
-                       else goto badmode;
-                       break;
+               }
+               else if (*tok == ',')
+               {
+                       // (foo,x)
+                       tok++;
+                       p = string[tok[1]];
 
-               default:
-                       /*
-                        *  Short-circuit
-                        *    x,foo
-                        *    y,foo
-                        *
-                        */
+                       if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'x') // Sleazo tolower()
+                               goto badmode;
+
+                       tok += 2;
+
+                       if (*tok++ != ')')
+                               goto badmode;
+
+                       amode = A65_INDX;
+               }
+               else
+                       goto badmode;
+
+               break;
+
+       case '@':
+               tok++;
+
+               if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+                       return;
+
+               if (*tok == '(')
+               {
+                       tok++;
                        p = string[tok[1]];
-                       if (*tok == SYMBOL &&
-                                 p[1] == EOS &&
-                                 tok[2] == ',')
-                       {
-                               tok += 3;               /* past: SYMBOL <string> ',' */
-                               i = (*p | 0x20);
-
-                               if (i == 'x')
-                                       amode = A65_ABSX;
-                               else if (i == 'y')
-                                       amode = A65_ABSY;
-                               else goto not_coinop;
-
-                               if (expr(exprbuf, &eval, &eattr, NULL) < 0)
-                                       return;
-                               if (*tok != EOL)
-                                       goto badmode;
 
-                               zpreq = 1;
-                               break;
-                       }
+                       if (*tok != SYMBOL || p[1] != EOS || tok[2] != ')' || tok[3] != EOL)
+                               goto badmode;
 
-not_coinop:
-                       if (expr(exprbuf, &eval, &eattr, NULL) < 0) return;
-                       zpreq = 1;
+                       i = (*p | 0x20);        // Sleazo tolower()
 
-                       if (*tok == EOL)
-                               amode = A65_ABS;
-                       else if (*tok == ',')
-                       {
-                               ++tok;
-                               p = string[tok[1]];
-                               if (*tok != SYMBOL ||
-                                         p[1] != EOS)
-                                       goto badmode;
-                               tok += 2;
+                       if (i == 'x')
+                               amode = A65_INDX;
+                       else if (i == 'y')
+                               amode = A65_INDY;
+                       else
+                               goto badmode;
+
+                       tok += 3;               // Past SYMBOL <string> ')' EOL
+                       zpreq = 1;              // Request zeropage optimization
+               }
+               else if (*tok == EOL)
+                       amode = A65_IND;
+               else
+                       goto badmode;
+
+               break;
+
+       default:
+               //
+               // Short-circuit
+               //   x,foo
+               //   y,foo
+               //
+               p = string[tok[1]];
+
+               if (*tok == SYMBOL && p[1] == EOS && tok[2] == ',')
+               {
+                       tok += 3;               // Past: SYMBOL <string> ','
+                       i = (*p | 0x20);
+
+                       if (i == 'x')
+                               amode = A65_ABSX;
+                       else if (i == 'y')
+                               amode = A65_ABSY;
+                       else
+                               goto not_coinop;
 
-                               /*
-                                *  Check for X or Y index register;
-                                *  the OR with 0x20 is a sleazo conversion
-                                *  to lower-case that actually works.
-                                */
-                               i = *p | 0x20;  /* oooh, this is slimey (but fast!) */
-                               if (i == 'x')
-                                       amode = A65_ABSX;
-                               else if (i == 'y')
-                                       amode = A65_ABSY;
-                               else goto badmode;
-                       }
-                       else goto badmode;
+                       if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+                               return;
+
+                       if (*tok != EOL)
+                               goto badmode;
+
+                       zpreq = 1;
                        break;
+               }
+
+not_coinop:
+               if (expr(exprbuf, &eval, &eattr, NULL) < 0)
+                       return;
+
+               zpreq = 1;
+
+               if (*tok == EOL)
+                       amode = A65_ABS;
+               else if (*tok == ',')
+               {
+                       tok++;
+                       p = string[tok[1]];
+
+                       if (*tok != SYMBOL || p[1] != EOS)
+                               goto badmode;
+
+                       tok += 2;
+
+                       //
+                       // Check for X or Y index register;
+                       // the OR with 0x20 is a sleazo conversion
+                       // to lower-case that actually works.
+                       //
+                       i = *p | 0x20;  // Oooh, this is slimey (but fast!)
+
+                       if (i == 'x')
+                               amode = A65_ABSX;
+                       else if (i == 'y')
+                               amode = A65_ABSY;
+                       else
+                               goto badmode;
+               }
+               else
+                       goto badmode;
+
+               break;
 
 badmode:
-                       error("bad 6502 addressing mode");
-            return;
+               error("bad 6502 addressing mode");
+               return;
        }
 
-       /*
-        *  Optimize ABS modes to zero-page when possible
-        *    o  ZPX or ZPY is illegal, or
-        *    o  expr is zeropage && zeropageRequest && expression is defined
-        */
-       if (inf[op][amode] == ILLEGAL || /* if current op is illegal, or */
-                 (eval < 0x100 &&              /* expr must be zero-page */
-                  zpreq != 0 &&                /* amode must request zero-page opt. */
-                  (eattr & DEFINED)))  /* and the expression must be defined */
+       //
+       // Optimize ABS modes to zero-page when possible
+       //   o  ZPX or ZPY is illegal, or
+       //   o  expr is zeropage && zeropageRequest && expression is defined
+       //
+       if (inf[op][amode] == ILLEGAL   // If current op is illegal,
+               || (eval < 0x100                        // or expr must be zero-page
+               && zpreq != 0                           // amode must request zero-page opt.
+               && (eattr & DEFINED)))          // and the expression must be defined
        {
-               i = abs2zp[amode];      /* i = zero-page translation of amode */
+               i = abs2zp[amode];                      // i = zero-page translation of amode
 #ifdef DO_DEBUG
                DEBUG printf(" OPT: op=%d amode=%d i=%d inf[op][i]=%d\n",
                                         op, amode, i, inf[op][i]);
 #endif
-               if (i >= 0 &&
-                         (inf[op][i] & 0xff) != ILLEGAL) /* use it if it's legal */
+               if (i >= 0 && (inf[op][i] & 0xFF) != ILLEGAL) // Use it if it's legal
                        amode = i;
        }
 
@@ -422,31 +436,35 @@ badmode:
 
        switch (inf[op][amode])
        {
-               case A65_IMPL:          /* just leave the instruction */
+               case A65_IMPL:          // Just leave the instruction
                        D_byte(ops[op][amode]);
                        break;
 
-        case A65_IMMEDH:
-            D_byte(ops[op][amode]);
-            if (!(eattr & DEFINED))
-            {
-                AddFixup(FU_BYTEH, sloc, exprbuf);
-                eval = 0;
-            }
-            eval = (eval >> 8) & 0xff; /* bring high byte to low */
-            D_byte(eval);              /* deposit byte following instr */
-            break;
-
-        case A65_IMMEDL:
-            D_byte(ops[op][amode]);
-            if (!(eattr & DEFINED))
-            {
-                AddFixup(FU_BYTEL, sloc, exprbuf);
-                eval = 0;
-            }
-            eval = eval & 0xff; /* mask high byte */
-            D_byte(eval);              /* deposit byte following instr */
-            break;
+               case A65_IMMEDH:
+                       D_byte(ops[op][amode]);
+
+                       if (!(eattr & DEFINED))
+                       {
+                               AddFixup(FU_BYTEH, sloc, exprbuf);
+                               eval = 0;
+                       }
+
+                       eval = (eval >> 8) & 0xFF; // Bring high byte to low
+                       D_byte(eval);                           // Deposit byte following instr
+                       break;
+
+               case A65_IMMEDL:
+                       D_byte(ops[op][amode]);
+
+                       if (!(eattr & DEFINED))
+                       {
+                               AddFixup(FU_BYTEL, sloc, exprbuf);
+                               eval = 0;
+                       }
+
+                       eval = eval & 0xFF; // Mask high byte
+                       D_byte(eval);           // Deposit byte following instr
+                       break;
 
                case A65_IMMED:
                case A65_INDX:
@@ -455,6 +473,7 @@ badmode:
                case A65_ZPX:
                case A65_ZPY:
                        D_byte(ops[op][amode]);
+
                        if (!(eattr & DEFINED))
                        {
                                AddFixup(FU_BYTE, sloc, exprbuf);
@@ -465,19 +484,23 @@ badmode:
                                error(range_error);
                                eval = 0;
                        }
-                       D_byte(eval);           /* deposit byte following instr */
+
+                       D_byte(eval);           // Deposit byte following instr
                        break;
 
                case A65_REL:
                        D_byte(ops[op][amode]);
+
                        if (eattr & DEFINED)
                        {
                                eval -= (sloc + 1);
+
                                if (eval + 0x80 >= 0x100)
                                {
                                        error(range_error);
                                        eval = 0;
                                }
+
                                D_byte(eval);
                        }
                        else
@@ -485,6 +508,7 @@ badmode:
                                AddFixup(FU_6BRA, sloc, exprbuf);
                                D_byte(0);
                        }
+
                        break;
 
                case A65_ABS:
@@ -492,68 +516,65 @@ badmode:
                case A65_ABSY:
                case A65_IND:
                        D_byte(ops[op][amode]);
+
                        if (!(eattr & DEFINED))
                        {
                                AddFixup(FU_WORD, sloc, exprbuf);
                                eval = 0;
                        }
+
                        D_rword(eval);
                        break;
 
-                       /*
-                        *  Deposit 3 NOPs for illegal things
-                        */
+                       //
+                       // Deposit 3 NOPs for illegal things
+                       //
                default:
                case ILLEGAL:
-                       for (i = 0; i < 3; ++i) {
+                       for(i=0; i<3; i++)
                                D_byte(NOP);
-                       }
+
                        error("illegal 6502 addressing mode");
        }
 
-       /*
-        *  Check for overflow of code region
-        */
-       if (sloc > 0x10000L) fatal("6502 code pointer > 64K");
-       if (*tok != EOL) error(extra_stuff);
+       // Check for overflow of code region
+       if (sloc > 0x10000L)
+               fatal("6502 code pointer > 64K");
+
+       if (*tok != EOL)
+               error(extra_stuff);
 }
 
 
-/*
- *  Generate 6502 object output file.
- *
- */
+//
+// Generate 6502 object output file.
+//
 // ggn: converted into a com/exe/xex output format
-//      Notes: 1. The $ffff is only mandatory for the first segment, but let's dump it everywhere for now
+//      Notes: 1. The $FFFF is only mandatory for the first segment, but let's dump it everywhere for now
 //             2. It's still dumping pages instead of more fine grained stuff. Should look into this - a8 people don't like waste so much ;)
-VOID m6502obj(ofd)
-int ofd;
+void m6502obj(int ofd)
 {
-       register CHUNK *ch;
-       register char *p;
-    uint16_t exeheader[3];
-    uint16_t *l;
-    int headsize = 6;
-    uint16_t *headpoint = (uint16_t *)exeheader;
-
-       /*
-        *  If no 6502 code was generated, forget it
-        */
-       if ((ch = sect[M6502].scode) == NULL ||
-                 ch->challoc == 0)
-               return;
+       uint16_t exeheader[3];
+       int headsize = 6;
+       uint16_t * headpoint = exeheader;
+
+       CHUNK * ch = sect[M6502].scode;
 
-    exeheader[0] = 0xffff;  // mandatory for first segment
-    p = ch->chptr;
+       // If no 6502 code was generated, forget it
+       if ((ch == NULL) || (ch->challoc == 0))
+               return;
 
-    for (l = (uint16_t *)orgmap;l < currentorg;l+=2)
-    {
-        exeheader[1] = l[0];
-        exeheader[2] = l[1]-1;
-        write(ofd, headpoint, headsize);   // Write header 
-        write(ofd, p + l[0], l[1] - l[0]);
-        headpoint = &exeheader[1];            // skip the $ffff after first segment, it's not mandatory
-        headsize = 4;
-    }
+       exeheader[0] = 0xFFFF;          // Mandatory for first segment
+       register uint8_t * p = ch->chptr;
 
+       for(uint16_t * l=&orgmap[0][0]; l<currentorg; l+=2)
+       {
+               exeheader[1] = l[0];
+               exeheader[2] = l[1] - 1;
+               size_t unused = write(ofd, headpoint, headsize);   // Write header
+               unused = write(ofd, p + l[0], l[1] - l[0]);
+               headpoint = &exeheader[1];            // Skip the $FFFF after first segment, it's not mandatory
+               headsize = 4;
+       }
 }
+