~ndiddy/a65

16192d47aa03db9cc19f555590842c9bbab8c5ce — Nathan Misner 4 months ago 36c6e05
binary output and forced absolute addressing implemented
6 files changed, 45 insertions(+), 46 deletions(-)

M a65.c
M a65.h
M a65eval.c
M a65util.c
M a65util.h
M readme.txt
M a65.c => a65.c +1 -1
@@ 274,7 274,7 @@ static void normal_op() {

	case STXY:  
		if ((argattr & (opcode == 0x86 ? ~ARGY : ~ARGX)) != ARGNUM) { 
			error ('A');
			error('A');
			return;
		}
		if (argattr & (ARGX + ARGY)) {

M a65.h => a65.h +10 -8
@@ 167,13 167,16 @@ typedef struct {

/*  Lexical analyzer (A65EVAL.C) token attribute values:		*/

#define	EOL		0	/*  end of line				*/
#define	SEP		1	/*  field separator			*/
#define	OPR		2	/*  operator				*/
#define	STR		3	/*  character string			*/
#define	VAL		4	/*  value				*/
#define	IMM		5	/*  immediate designator		*/
#define	REG		6	/*  register designator			*/
typedef enum {
	EOL = 0,		/* end of line */
	SEP,			/* field separator */
	OPR,			/* operator */
	STR,			/* character string */
	VAL,			/* value */
	IMM,			/* immediate designator */
	REG,			/* register designator */
	ABS,			/* force absolute addressing */
};

/*  Lexical analyzer (A65EVAL.C) token attribute word flag masks:	*/



@@ 190,7 193,6 @@ typedef struct {
/*  use ASCII characters):						*/

typedef enum {
	ABS = 0,
	AND,
	GE,
	HIGH,

M a65eval.c => a65eval.c +10 -3
@@ 102,6 102,11 @@ unsigned do_args() {
		argattr = ARGIMM + ARGNUM;
		return expr();

	case ABS:
		argattr = ARGNUM;
		forceabs = TRUE;
		return expr();

	case SEP:   
		u = 0;  goto have_number;



@@ 172,6 177,7 @@ static unsigned eval(unsigned pre) {
	for (;;) {
		u = op = lex()->valu;
		switch (token.attr & TYPE) {
		case ABS:
		case REG:
		case IMM:   exp_error('S');  break;



@@ 183,7 189,6 @@ static unsigned eval(unsigned pre) {
			u = (op == '*' ? pc : eval((op == '+' || op == '-') ? (unsigned)UOP1 : token.attr & PREC));
			switch (op) {
				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;


@@ 320,6 325,9 @@ num:		    pops(token.sval);
	case '#':   token.attr = IMM;
				break;

	case '!':	token.attr = ABS;
				break;

	case '(':   token.attr = UNARY + LPREN + OPR;
				goto opr1;



@@ 392,8 400,7 @@ static void make_number(unsigned base) {
}

int isalph(char c) {
    return (c >= 'A' && c <= '~') || c == '!' ||
		c == '&' || c == '.' || c == ':' || c == '?';
    return (c >= 'A' && c <= '~') || c == '&' || c == '.' || c == ':' || c == '?';
}

static int isnum(char c) {

M a65util.c => a65util.c +12 -18
@@ 206,7 206,6 @@ 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"	},


@@ 336,21 335,20 @@ static void check_page() {
    return;
}

/*  Buffer storage for hex output file.  This allows the hex file	*/
/*  Buffer storage for binary output file.  This allows the file	*/
/*  output routines to do all of the required buffering and record	*/
/*  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 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.						*/
/*  Binary file open routine.  If the file is already open, a warning	*/
/*  occurs.  If the file doesn't open correctly, a fatal error occurs.	*/
/*  If no binary file is open, all calls to bputc(), bseek(), and		*/
/*  bclose() have no effect.											*/

void bopen(char *filename) {
	if (outfile) {


@@ 364,9 362,8 @@ void bopen(char *filename) {
	}
}

/*  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.				*/
/*  Binary file write routine.  The data byte is appended to the output	*/
/*  buffer.  If the buffer fills up, it gets written to disk. 			*/

void bputc(unsigned c) {
	if (outfile) {


@@ 375,10 372,8 @@ void bputc(unsigned c) {
	}
}

/*  Hex file address set routine.  The specified address becomes the	*/
/*  load address of the next record.  If a record is currently open,	*/
/*  it gets written to disk.  If the disk fills up, a fatal error	*/
/*  occurs.								*/
/*  Binary file address set routine. Note that this can only be used to */
/*  seek forwards in the file. Seeking backwards will cause an error.	*/

void bseek(unsigned a) {
	unsigned cursor = addr + cnt;


@@ 392,7 387,7 @@ void bseek(unsigned a) {
		}
		/* don't allow seeking backwards */
		else if (cursor > a) {
			fatal_error("Invalid ORG statement");
			error('S');
		}
		/* pad the file to make up the difference */
		else {


@@ 404,9 399,8 @@ 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.							*/
/*  Binary file close routine. All buffered data is written to disk,	*/
/*  and the output file is closed.										*/

void bclose() {
	if (outfile) {

M a65util.h => a65util.h +10 -14
@@ 109,32 109,28 @@ void lputs();
void lclose();


/*  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.											*/
/*  Binary file open routine.  If the file is already open, a warning	*/
/*  occurs.  If the file doesn't open correctly, a fatal error occurs.	*/
/*  If no binary file is open, all calls to bputc(), bseek(), and		*/
/*  bclose() have no effect.											*/

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.								*/
/*  Binary file write routine.  The data byte is appended to the output	*/
/*  buffer.  If the buffer fills up, it gets written to disk. 			*/

void bputc(unsigned c);


/*  Hex file address set routine.  The specified address becomes the	*/
/*  load address of the next record.  If a record is currently open,	*/
/*  it gets written to disk.  If the disk fills up, a fatal error		*/
/*  occurs.																*/
/*  Binary file address set routine. Note that this can only be used to */
/*  seek forwards in the file. Seeking backwards will cause an error.	*/

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.													*/
/*  Binary file close routine. All buffered data is written to disk,	*/
/*  and the output file is closed.										*/

void bclose();


M readme.txt => readme.txt +2 -2
@@ 30,8 30,8 @@ your workflow.
- 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 - done
- Change the assembler to output binary files instead of Intel HEX
- Allow for forcing loads/stores to not be optimized for zero page
- Change the assembler to output binary files instead of Intel HEX - done
- Allow for forcing loads/stores to not be optimized for zero page - done (! operator)
- 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