//
-// RMAC - Reboot's Macro Assembler for all Atari computers
+// RMAC - Renamed Macro Assembler for all Atari computers
// 6502.C - 6502 Assembler
-// Copyright (C) 199x Landon Dyer, 2011-2019 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
// Source utilised with the kind permission of Landon Dyer
//
void m6502cg(int op)
{
register int amode; // (Parsed) addressing mode
- register int i;
- uint64_t eval; // Expression value
- WORD eattr; // Expression attributes
- int zpreq; // 1, optimize instr to zero-page form
- register char * p; // (Temp) string usage
+ uint64_t eval = -1; // Expression value
+ WORD eattr = 0; // Expression attributes
+ int zpreq = 0; // 1 = optimize instr to zero-page form
ch_size = 0; // Reset chunk size on every instruction
//
// Parse 6502 addressing mode
//
- zpreq = 0;
-
switch (tok[0])
{
case EOL:
if (tok[1] != EOL)
goto badmode;
- amode = A65_IMPL;
tok++;
+ amode = A65_IMPL;
break;
case '#':
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;
}
+ else
+ amode = A65_IMMED;
if (expr(exprbuf, &eval, &eattr, NULL) < 0)
return;
- amode = A65_IMMED;
break;
case '(':
{
// (foo),y
tok++;
-#if 0
- p = string[tok[1]];
-
- // Sleazo tolower() -----------------vvvvvvvvvvv
- if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'y')
- goto badmode;
-
- tok += 2;
amode = A65_INDY;
-#else
- if (tok[0] == KW_Y)
- amode = A65_INDY;
- if (tok[1] != EOL)
+ if (tok[0] != KW_Y)
goto badmode;
tok++;
-#endif
}
else
amode = A65_IND;
}
- else if (*tok == ',')
+ else if ((tok[0] == ',') && (tok[1] == KW_X) && (tok[2] == ')'))
{
// (foo,x)
- tok++;
-#if 0
- p = string[tok[1]];
-
- // Sleazo tolower() -----------------vvvvvvvvvvv
- if (*tok != SYMBOL || p[1] != EOS || (*p | 0x20) != 'x')
- goto badmode;
-
- tok += 2;
- if (*tok++ != ')')
- goto badmode;
-
+ tok += 3;
amode = A65_INDX;
-#else
- if (tok[0] == KW_X)
- amode = A65_INDX;
-
- if ((tok[1] != ')') || (tok[2] != EOL))
- goto badmode;
-
- tok += 2;
-#endif
}
else
goto badmode;
if (*tok == '(')
{
tok++;
-#if 0
- p = string[tok[1]];
-
- if (*tok != SYMBOL || p[1] != EOS || tok[2] != ')' || tok[3] != EOL)
- 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
-#else
if ((tok[1] != ')') || (tok[2] != EOL))
goto badmode;
goto badmode;
tok += 2;
-#endif
zpreq = 1; // Request zeropage optimization
}
else if (*tok == EOL)
break;
default:
- //
- // Short-circuit
- // x,foo
- // y,foo
- //
- p = string[tok[1]];
- // ggn: the following code is effectively disabled as it would make
- // single letter labels not work correctly (would not identify the
- // label properly). And from what I understand it's something to
- // keep compatibility with the coinop assembler which is probably
- // something we don't care about much :D
-#if 0
- 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;
- }
-
-not_coinop:
-#endif
+ // <expr>
+ // <expr>,x
+ // <expr>,y
if (expr(exprbuf, &eval, &eattr, NULL) < 0)
return;
- zpreq = 1;
+ zpreq = 1; // Request zeropage optimization
- if (*tok == EOL)
+ if (tok[0] == EOL)
amode = A65_ABS;
- else if (*tok == ',')
+ else if (tok[0] == ',')
{
tok++;
-#if 0
- 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
if (tok[0] == KW_X)
{
- amode = A65_ABSX;
tok++;
+ amode = A65_ABSX;
}
else if (tok[0] == KW_Y)
{
- amode = A65_ABSY;
tok++;
+ amode = A65_ABSY;
}
-
- if (tok[0] != EOL)
- goto badmode;
-#endif
}
else
goto badmode;
// 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
+ if ((inf[op][amode] == ILLEGAL) // If current op is illegal OR
+ || (zpreq // amode requested a zero-page optimize
+ && (eval < 0x100) // and expr is zero-page
+ && (eattr & DEFINED))) // and the expression is defined
{
- i = abs2zp[amode]; // i = zero-page translation of amode
+ int i = abs2zp[amode]; // Get 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;
}
//
default:
case ILLEGAL:
- for(i=0; i<3; i++)
- D_byte(NOP);
+ D_byte(NOP);
+ D_byte(NOP);
+ D_byte(NOP);
error("illegal 6502 addressing mode");
}
if (sloc > 0x10000L)
fatal("6502 code pointer > 64K");
-//Now why use this instead of at_eol()?
- if (*tok != EOL)
- error(extra_stuff);
+ ErrorIfNotAtEOL();
}
//
// Generate 6502 object output file.
+// ggn: Converted to COM/EXE/XEX output format
//
-// ggn: converted into a com/exe/xex output format
void m6502obj(int ofd)
{
- uint16_t exeheader[3];
- int headsize = 6;
- uint16_t * headpoint = exeheader;
+ uint8_t header[4];
CHUNK * ch = sect[M6502].scode;
- // If no 6502 code was generated, forget it
+ // If no 6502 code was generated, bail out
if ((ch == NULL) || (ch->challoc == 0))
return;
- exeheader[0] = 0xFFFF; // Mandatory for first segment
register uint8_t * p = ch->chptr;
+ // Write out mandatory $FFFF header
+ header[0] = header[1] = 0xFF;
+ uint32_t unused = write(ofd, header, 2);
+
for(uint16_t * l=&orgmap[0][0]; l<currentorg; l+=2)
{
-/*
-Why are we assuming endianness here? This is retarded
-*/
- exeheader[1] = l[0];
- exeheader[2] = l[1] - 1;
-
- // Write header
- size_t unused = write(ofd, headpoint, headsize);
- unused = write(ofd, p + l[0], l[1] - l[0]);
+ SETLE16(header, 0, l[0]);
+ SETLE16(header, 2, l[1] - 1);
- // Skip the $FFFF after first segment, it's not mandatory
- headpoint = &exeheader[1];
- headsize = 4;
+ // Write header for segment
+ unused = write(ofd, header, 4);
+ // Write the segment data
+ unused = write(ofd, p + l[0], l[1] - l[0]);
}
}