M .gitignore => .gitignore +6 -0
@@ 3,6 3,12 @@
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
+# test files
+madoola.asm
+madoola.lst
+madoola.bin
+variables.asm
+
# User-specific files
*.rsuser
*.suo
M a65.c => a65.c +9 -9
@@ 62,7 62,7 @@ parse the source line and convert it into the object bytes that it represents.
char errcode, line[MAXLINE + 1], title[MAXLINE];
int pass = 0;
-int eject, filesp, forwd, listhex;
+int eject, filesp, forwd, forceabs, listhex;
unsigned address, argattr, bytes, errors, listleft, obj[MAXLINE], pagelen, pc;
FILE *filestk[FILES], *source;
TOKEN token;
@@ 103,7 103,7 @@ void main(int argc, char **argv) {
if (!--argc) { warning(NOHEX); break; }
else ++argv;
}
- hopen(*argv);
+ bopen(*argv);
break;
default:
@@ 130,12 130,12 @@ void main(int argc, char **argv) {
pc = word(pc + bytes);
if (pass == 2) {
lputs();
- for (o = obj; bytes--; hputc(*o++));
+ for (o = obj; bytes--; bputc(*o++));
}
}
}
- fclose(filestk[0]); lclose(); hclose();
+ fclose(filestk[0]); lclose(); bclose();
if (errors) printf("%d Error(s)\n",errors);
else printf("No Errors\n");
@@ 157,7 157,7 @@ static OPCODE *opcod;
static void asm_line() {
SCRATCH int i;
- address = pc; bytes = 0; eject = forwd = listhex = FALSE;
+ address = pc; bytes = 0; eject = forwd = forceabs = listhex = FALSE;
for (i = 0; i < BIGINST; obj[i++] = NOP);
label[0] = '\0';
@@ 317,7 317,7 @@ do_inc_op:
do_indexed_x:
if (argattr & ARGX) opcode += 0x10;
do_zero_page:
- if (!forwd && operand <= 0x00ff) bytes = 2;
+ if (!forceabs && !forwd && (operand <= 0x00ff)) bytes = 2;
else opcode += 0x08;
break;
}
@@ 385,7 385,7 @@ static void pseudo_op() {
else {
done = eject = TRUE;
if (pass == 2 && (lex() -> attr & TYPE) != EOL) {
- unlex(); hseek(address = expr());
+ unlex(); bseek(address = expr());
}
if (ifsp) error('I');
}
@@ 446,7 446,7 @@ static void pseudo_op() {
if (forwd) error('P');
else {
pc = address = u;
- if (pass == 2) hseek(pc);
+ if (pass == 2) bseek(pc);
}
do_label();
break;
@@ 468,7 468,7 @@ static void pseudo_op() {
if (forwd) error('P');
else {
pc = u;
- if (pass == 2) hseek(pc);
+ if (pass == 2) bseek(pc);
}
break;
M a65.h => a65.h +16 -13
@@ 189,18 189,21 @@ typedef struct {
/* Lexical analyzer (A65EVAL.C) operator token values (unlisted ones */
/* use ASCII characters): */
-#define AND 0
-#define GE 1
-#define HIGH 2
-#define LE 3
-#define LOW 4
-#define MOD 5
-#define NE 6
-#define NOT 7
-#define OR 8
-#define SHR 9
-#define SHL 10
-#define XOR 11
+typedef enum {
+ ABS = 0,
+ AND,
+ GE,
+ HIGH,
+ LE,
+ LOW,
+ MOD,
+ NE,
+ NOT,
+ OR,
+ SHR,
+ SHL,
+ XOR,
+} LEX_OP;
/* Lexical analyzer (A65EVAL.C) operator precedence values: */
@@ 241,6 244,6 @@ typedef struct {
/* Utility package (A65UTIL.C) hex file output routines: */
-#define HEXSIZE 32
+#define HEXSIZE 8192
#endif
M a65eval.c => a65eval.c +8 -8
@@ 56,7 56,7 @@ arithmetic expressions.
/* Get access to global mailboxes defined in A65.C: */
extern char line[];
-extern int filesp, forwd, pass;
+extern int filesp, forwd, forceabs, pass;
extern unsigned argattr, pc;
extern FILE *filestk[], *source;
extern TOKEN token;
@@ 123,9 123,8 @@ unsigned do_args() {
argattr = (ARGIND + ARGNUM); trash();
if ((c = popc()) == '\n') return u;
if (c == ',') {
- if (lex() -> attr & TYPE != REG
- || token.valu != 'Y')
- exp_error('S');
+ if (lex() -> attr & TYPE != REG || token.valu != 'Y')
+ exp_error('S');
else argattr += ARGY;
return bad ? 0 : u;
}
@@ 181,10 180,11 @@ static unsigned eval(unsigned pre) {
if (!(token.attr & UNARY)) { exp_error('E'); break; }
u = (op == '*' ? pc : eval((op == '+' || op == '-') ? (unsigned)UOP1 : token.attr & PREC));
switch (op) {
- case '-': u = word(~u + 1); break;
- case NOT: u ^= 0xffff; break;
- case HIGH: u = high(u); break;
- case LOW: u = low(u); break;
+ case '-': u = word(~u + 1); break;
+ case ABS: forceabs = TRUE; break;
+ case NOT: u ^= 0xffff; break;
+ case HIGH: u = high(u); break;
+ case LOW: u = low(u); break;
}
case VAL:
M a65util.c => a65util.c +52 -45
@@ 54,6 54,7 @@ This module contains the following utility packages:
*/
#include <ctype.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ 80,8 81,7 @@ static OPCODE *bsearchtbl(OPCODE *lo, OPCODE *hi, char *nam);
static int ustrcmp(char *s, char *t);
static void list_sym(SYMBOL *sp);
static void check_page();
-static void record(unsigned typ);
-static void putb(unsigned b);
+static void record();
/* Add new symbol to symbol table. Returns pointer to symbol even if */
/* the symbol already exists. If there's not enough memory to store */
@@ 206,6 206,7 @@ OPCODE *find_code(char *nam) {
OPCODE *find_operator(char *nam) {
static OPCODE oprtbl[] = {
{ REG, 'A', "A" },
+ { UNARY + UOP3 + OPR, ABS, "ABS" },
{ BINARY + LOG1 + OPR, AND, "AND" },
{ BINARY + RELAT + OPR, '=', "EQ" },
{ BINARY + RELAT + OPR, GE, "GE" },
@@ 340,35 341,38 @@ static void check_page() {
/* forming without the main routine having to fool with it. */
static FILE *hex = NULL;
+static FILE *outfile = NULL;
static unsigned cnt = 0;
static unsigned addr = 0;
static unsigned sum = 0;
-static unsigned buf[HEXSIZE];
+static uint8_t buf[HEXSIZE];
/* Hex file open routine. If a hex file is already open, a warning */
/* occurs. If the hex file doesn't open correctly, a fatal error */
/* occurs. If no hex file is open, all calls to hputc(), hseek(), and */
/* hclose() have no effect. */
-void hopen(char *nam) {
- FILE *fopen();
- void fatal_error(), warning();
-
- if (hex) warning(TWOHEX);
- else if (!(hex = fopen(nam,"w"))) fatal_error(HEXOPEN);
- return;
+void bopen(char *filename) {
+ if (outfile) {
+ warning(TWOHEX);
+ }
+ else {
+ outfile = fopen(filename, "wb");
+ if (!outfile) {
+ fatal_error(HEXOPEN);
+ }
+ }
}
/* Hex file write routine. The data byte is appended to the current */
/* record. If the record fills up, it gets written to disk. If the */
/* disk fills up, a fatal error occurs. */
-void hputc(unsigned c) {
- if (hex) {
+void bputc(unsigned c) {
+ if (outfile) {
buf[cnt++] = c;
- if (cnt == HEXSIZE) record(0);
- }
- return;
+ if (cnt == HEXSIZE) record();
+ }
}
/* Hex file address set routine. The specified address becomes the */
@@ 376,45 380,48 @@ void hputc(unsigned c) {
/* it gets written to disk. If the disk fills up, a fatal error */
/* occurs. */
-void hseek(unsigned a) {
- if (hex) {
- if (cnt) record(0);
- addr = a;
- }
- return;
+void bseek(unsigned a) {
+ unsigned cursor = addr + cnt;
+ unsigned difference;
+ int i;
+
+ if (outfile) {
+ /* initial ORG statement */
+ if (cursor == 0) {
+ addr = a;
+ }
+ /* don't allow seeking backwards */
+ else if (cursor > a) {
+ fatal_error("Invalid ORG statement");
+ }
+ /* pad the file to make up the difference */
+ else {
+ difference = a - cursor;
+ for (i = 0; i < difference; i++) {
+ bputc(0);
+ }
+ }
+ }
}
/* Hex file close routine. Any open record is written to disk, the */
/* EOF record is added, and file is closed. If the disk fills up, a */
/* fatal error occurs. */
-void hclose() {
- if (hex) {
- if (cnt) record(0);
- record(1);
- if (fclose(hex) == EOF) fatal_error(DSKFULL);
- }
- return;
-}
-
-static void record(unsigned typ) {
- SCRATCH unsigned i;
- putc(':',hex); putb(cnt); putb(high(addr));
- putb(low(addr)); putb(typ);
- for (i = 0; i < cnt; ++i) putb(buf[i]);
- putb(low(~sum + 1)); putc('\n',hex);
-
- addr += cnt; cnt = 0;
-
- if (ferror(hex)) fatal_error(DSKFULL);
- return;
+void bclose() {
+ if (outfile) {
+ if (cnt) record();
+ fclose(outfile);
+ }
}
-static void putb(unsigned b) {
- static char digit[] = "0123456789ABCDEF";
+static void record() {
+ if (fwrite(buf, 1, cnt, outfile) != cnt) {
+ fatal_error(DSKFULL);
+ }
- putc(digit[b >> 4],hex); putc(digit[b & 0x0f],hex);
- sum += b; return;
+ addr += cnt;
+ cnt = 0;
}
/* Error handler routine. If the current error code is non-blank, */
M a65util.h => a65util.h +4 -4
@@ 114,14 114,14 @@ void lclose();
/* occurs. If no hex file is open, all calls to hputc(), hseek(), and */
/* hclose() have no effect. */
-void hopen(char *nam);
+void bopen(char *nam);
/* Hex file write routine. The data byte is appended to the current */
/* record. If the record fills up, it gets written to disk. If the */
/* disk fills up, a fatal error occurs. */
-void hputc(unsigned c);
+void bputc(unsigned c);
/* Hex file address set routine. The specified address becomes the */
@@ 129,14 129,14 @@ void hputc(unsigned c);
/* it gets written to disk. If the disk fills up, a fatal error */
/* occurs. */
-void hseek(unsigned a);
+void bseek(unsigned a);
/* Hex file close routine. Any open record is written to disk, the */
/* EOF record is added, and file is closed. If the disk fills up, a */
/* fatal error occurs. */
-void hclose();
+void bclose();
/* Error handler routine. If the current error code is non-blank, */
M readme.txt => readme.txt +2 -1
@@ 29,9 29,10 @@ your workflow.
- Change "FCB", "FCC", "FDB" to "DB", "DS", "DW" - done
- Change the syntax so "DB" accepts string(s) as arguments - done
- Change the syntax so labels can have colons after them - done
-- Give each .c file its own header file
+- Give each .c file its own header file - done
- Change the assembler to output binary files instead of Intel HEX
- Allow for forcing loads/stores to not be optimized for zero page
+- Add a "MSG" statement that prints out arbitrary strings and symbols
- Print the error messages to stdout instead of the assembler listing
- Add a makefile for our GNU/Linux and Mac OS X using friends
- Update A65.DOC with the new changes