~ndiddy/a65

fe162364f5545fd8445d31c2cc13cb12447869f1 — Nathan Misner 4 months ago d3f7472
in-progress commit
7 files changed, 97 insertions(+), 80 deletions(-)

M .gitignore
M a65.c
M a65.h
M a65eval.c
M a65util.c
M a65util.h
M readme.txt
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