diff options
Diffstat (limited to 'hacks/asm6502.c')
-rw-r--r-- | hacks/asm6502.c | 2275 |
1 files changed, 2275 insertions, 0 deletions
diff --git a/hacks/asm6502.c b/hacks/asm6502.c new file mode 100644 index 0000000..27d2824 --- /dev/null +++ b/hacks/asm6502.c @@ -0,0 +1,2275 @@ +/*-*- indent-tabs-mode:nil -*- */ +/* Copyright (C) 2007 Jeremy English <jhe@jeremyenglish.org> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Created: 12-April-2007 + */ + +/* + This is a port of the javascript 6502 assembler, compiler and + debugger. The orignal code was copyright 2006 by Stian Soreng - + www.6502asm.com + + I changed the structure of the assembler in this version. +*/ + +#include <stdlib.h> +#include <stdio.h> +/*#include <malloc.h>*/ +#include <string.h> +#include <errno.h> +#include <stdarg.h> +#include <assert.h> +#include <ctype.h> +#include <math.h> +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#if defined(HAVE_STDINT_H) +# include <stdint.h> +#elif defined(HAVE_INTTYPES_H) +# include <inttypes.h> +#endif +#include <unistd.h> + +#include "yarandom.h" +#include "asm6502.h" + +/*#ifdef DEBUGGER +# define random rand +#endif*/ + +#ifndef HAVE_MOBILE +# define READ_FILES +#endif + +typedef enum{ + LEFT, RIGHT + } Side; + +/* + +Bit Flags + _ _ _ _ _ _ _ _ + |N||V||F||B||D||I||Z||C| + - - - - - - - - + 7 6 5 4 3 2 1 0 + +*/ + +typedef enum{ + CARRY_FL = 0, ZERO_FL = 1, INTERRUPT_FL = 2, + DECIMAL_FL = 3, BREAK_FL = 4, FUTURE_FL = 5, + OVERFLOW_FL = 6, NEGATIVE_FL = 7 + } Flags; + + +typedef BOOL (*CharTest) (char); + +/* A jump function takes a pointer to the current machine and a + opcode. The opcode is needed to figure out the memory mode. */ +/*typedef void (*JumpFunc) (machine_6502* AddrMode);*/ + +typedef struct { + m6502_AddrMode type; + Bit32 value[MAX_PARAM_VALUE]; + unsigned int vp; /*value pointer, index into the value table.*/ + char *label; + Bit32 lbladdr; +} Param; + +typedef struct { + Bit32 addr; /* Address of the label */ + char *label; +} Label; + +typedef struct AsmLine AsmLine; +struct AsmLine { + BOOL labelDecl; /* Does the line have a label declaration? */ + Label *label; + char *command; + Param *param; + AsmLine *next; /* in list */ +}; + +typedef struct { + Bit16 addr; + Bit16 value; +} Pointer; + + +/*static void *emalloc(size_t n) { + void *p = malloc(n); + if (! p) abort(); + return p; +}*/ + +static void *ecalloc(uint32_t nelm, size_t nsize){ + void *p = calloc(nelm, nsize); + if (!p) abort(); + return p; +} + +/* estrdup() - Allocates memory for a new string a returns a copy of the source sting in it. */ +static char *estrdup(const char *source){ + int ln = strlen(source) + 1; + char *s = ecalloc(ln, sizeof(char)); + strncpy(s,source,ln); + return s; +} + +static void checkAddress(Bit32 address){ + /* XXX: Do we want to kill the program here? */ + if (address >= MEM_64K) + fprintf(stderr, "Address %d is beyond 64k", address); +} + +/* + * stackPush() - Push byte to stack + * + */ + +static void stackPush(machine_6502 *machine, Bit8 value ) { + if(machine->regSP >= STACK_BOTTOM){ + machine->memory[machine->regSP--] = value; + } + else{ + fprintf(stderr, "The stack is full: %.4x\n", machine->regSP); + machine->codeRunning = FALSE; + } +} + + +/* + * stackPop() - Pop byte from stack + * + */ + +static Bit8 stackPop(machine_6502 *machine) { + if (machine->regSP < STACK_TOP){ + Bit8 value =machine->memory[++machine->regSP]; + return value; + } + else { + /* fprintf(stderr, "The stack is empty.\n"); xxx */ + machine->codeRunning = FALSE; + return 0; + } +} + +static void pushByte(machine_6502 *machine, Bit32 value ) { + Bit32 address = machine->defaultCodePC; + checkAddress(address); + machine->memory[address] = value & 0xff; + machine->codeLen++; + machine->defaultCodePC++; +} + +/* + * pushWord() - Push a word using pushByte twice + * + */ + +static void pushWord(machine_6502 *machine, Bit16 value ) { + pushByte(machine, value & 0xff ); + pushByte(machine, (value>>8) & 0xff ); +} + +/* + * popByte( machine_6502 *machine,) - Pops a byte + * + */ + +static Bit8 popByte( machine_6502 *machine) { + Bit8 value = machine->memory[machine->regPC]; + machine->regPC++; + return value; +} + +/* + * popWord() - Pops a word using popByte() twice + * + */ + +static int popWord(machine_6502 *machine) { + return popByte(machine) + (popByte(machine) << 8); +} + + +/* + * memReadByte() - Peek a byte, don't touch any registers + * + */ + +static int memReadByte( machine_6502 *machine, int addr ) { + if( addr == 0xfe ) return floor( random()%255 ); + return machine->memory[addr]; +} + +static void updateDisplayPixel(machine_6502 *machine, Bit16 addr){ + Bit8 idx = memReadByte(machine,addr) & 0x0f; + Bit8 x,y; + addr -= 0x200; + x = addr & 0x1f; + y = (addr >> 5); + if (machine->plot) { + machine->plot(x,y,idx,machine->plotterState); + } +} + +/* + * memStoreByte() - Poke a byte, don't touch any registers + * + */ + +static void memStoreByte( machine_6502 *machine, int addr, int value ) { + machine->memory[ addr ] = (value & 0xff); + if( (addr >= 0x200) && (addr<=0x5ff) ) + updateDisplayPixel(machine, addr ); +} + + + +/* EMULATION CODE */ + +static Bit8 bitOn(Bit8 value,Flags bit){ + Bit8 mask = 1; + mask = mask << bit; + return ((value & mask) > 0); +} + +static Bit8 bitOff(Bit8 value, Flags bit){ + return (! bitOn(value,bit)); +} + +static Bit8 setBit(Bit8 value, Flags bit, int on){ + Bit8 onMask = 1; + Bit8 offMask = 0xff; + onMask = onMask << bit; + offMask = offMask ^ onMask; + return ((on) ? value | onMask : value & offMask); +} + +static Bit8 nibble(Bit8 value, Side side){ + switch(side){ + case LEFT: return value & 0xf0; + case RIGHT: return value & 0xf; + default: + fprintf(stderr,"nibble unknown side\n"); + return 0; + } +} + + +/* used for tracing. XXX: combined with function getvalue */ +static BOOL peekValue(machine_6502 *machine, m6502_AddrMode adm, Pointer *pointer, Bit16 PC){ + Bit8 zp; + pointer->value = 0; + pointer->addr = 0; + switch(adm){ + case SINGLE: + return FALSE; + case IMMEDIATE_LESS: + case IMMEDIATE_GREAT: + case IMMEDIATE_VALUE: + pointer->value = memReadByte(machine, PC); + return TRUE; + case INDIRECT_X: + zp = memReadByte(machine, PC) + machine->regX; + pointer->addr = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case INDIRECT_Y: + zp = memReadByte(machine, PC); + pointer->addr = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO: + pointer->addr = memReadByte(machine, PC); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO_X: + pointer->addr = memReadByte(machine, PC) + machine->regX; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO_Y: + pointer->addr = memReadByte(machine, PC) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_OR_BRANCH: + pointer->addr = memReadByte(machine, PC); + return TRUE; + case ABS_VALUE: + pointer->addr = memReadByte(machine, PC) + (memReadByte(machine, PC+1) << 8); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_LABEL_X: + case ABS_X: + pointer->addr = (memReadByte(machine, PC) + + (memReadByte(machine, PC+1) << 8)) + machine->regX; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_LABEL_Y: + case ABS_Y: + pointer->addr = (memReadByte(machine, PC) + + (memReadByte(machine, PC+1) << 8)) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case DCB_PARAM: + /* Handled elsewhere */ + break; + } + return FALSE; + +} + + +/* Figure out how to get the value from the addrmode and get it.*/ +static BOOL getValue(machine_6502 *machine, m6502_AddrMode adm, Pointer *pointer){ + Bit8 zp; + pointer->value = 0; + pointer->addr = 0; + switch(adm){ + case SINGLE: + return FALSE; + case IMMEDIATE_LESS: + case IMMEDIATE_GREAT: + case IMMEDIATE_VALUE: + pointer->value = popByte(machine); + return TRUE; + case INDIRECT_X: + zp = popByte(machine) + machine->regX; + pointer->addr = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case INDIRECT_Y: + zp = popByte(machine); + pointer->addr = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO: + pointer->addr = popByte(machine); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO_X: + pointer->addr = popByte(machine) + machine->regX; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ZERO_Y: + pointer->addr = popByte(machine) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_OR_BRANCH: + pointer->addr = popByte(machine); + return TRUE; + case ABS_VALUE: + pointer->addr = popWord(machine); + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_LABEL_X: + case ABS_X: + pointer->addr = popWord(machine) + machine->regX; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case ABS_LABEL_Y: + case ABS_Y: + pointer->addr = popWord(machine) + machine->regY; + pointer->value = memReadByte(machine, pointer->addr); + return TRUE; + case DCB_PARAM: + /* Handled elsewhere */ + break; + } + return FALSE; + +} + +#if 0 +static void dismem(machine_6502 *machine, m6502_AddrMode adm, char *output){ + Bit8 zp; + Bit16 n; + switch(adm){ + case SINGLE: + *output = 0; + break; + case IMMEDIATE_LESS: + case IMMEDIATE_GREAT: + case IMMEDIATE_VALUE: + n = popByte(machine); + sprintf(output,"#$%x",n); + break; + case INDIRECT_X: + zp = popByte(machine); + n = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8); + sprintf(output,"($%x,x)",n); + break; + case INDIRECT_Y: + zp = popByte(machine); + n = memReadByte(machine,zp) + + (memReadByte(machine,zp+1)<<8); + sprintf(output,"($%x),y",n); + break; + case ABS_OR_BRANCH: + case ZERO: + n = popByte(machine); + sprintf(output,"$%x",n); + break; + case ZERO_X: + n = popByte(machine); + sprintf(output,"$%x,x",n); + break; + case ZERO_Y: + n = popByte(machine); + sprintf(output,"$%x,y",n); + break; + case ABS_VALUE: + n = popWord(machine); + sprintf(output,"$%x",n); + break; + case ABS_LABEL_X: + case ABS_X: + n = popWord(machine); + sprintf(output,"$%x,x",n); + break; + case ABS_LABEL_Y: + case ABS_Y: + n = popWord(machine); + sprintf(output,"$%x,x",n); + break; + case DCB_PARAM: + *output = 0; + break; + } +} +#endif + +/* manZeroNeg - Manage the negative and zero flags */ +static void manZeroNeg(machine_6502 *machine, Bit8 value){ + machine->regP = setBit(machine->regP, ZERO_FL, (value == 0)); + machine->regP = setBit(machine->regP, NEGATIVE_FL, bitOn(value,NEGATIVE_FL)); +} + +static void warnValue(BOOL isValue){ + if (! isValue){ + fprintf(stderr,"Invalid Value from getValue.\n"); + } +} + +static void jmpADC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + Bit16 tmp; + Bit8 c = bitOn(machine->regP, CARRY_FL); + BOOL isValue = getValue(machine, adm, &ptr); + + warnValue(isValue); + + if (bitOn(machine->regA, NEGATIVE_FL) && + bitOn(ptr.value, NEGATIVE_FL)) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + else + machine->regP = setBit(machine->regP, OVERFLOW_FL, 1); + + if (bitOn(machine->regP, DECIMAL_FL)) { + tmp = nibble(machine->regA,RIGHT) + nibble(ptr.value,RIGHT ) + c; + /* The decimal part is limited to 0 through 9 */ + if (tmp >= 10){ + tmp = 0x10 | ((tmp + 6) & 0xf); + } + tmp += nibble(machine->regA,LEFT) + nibble(ptr.value,LEFT); + if (tmp >= 160){ + machine->regP = setBit(machine->regP,CARRY_FL,1); + if (bitOn(machine->regP, OVERFLOW_FL) && tmp >= 0x180) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + tmp += 0x60; + } + else { + machine->regP = setBit(machine->regP,CARRY_FL,0); + if (bitOn(machine->regP, OVERFLOW_FL) && tmp < 0x80) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + } + } /* end decimal */ + else { + tmp = machine->regA + ptr.value + c; + if ( tmp >= 0x100 ){ + machine->regP = setBit(machine->regP,CARRY_FL,1); + if (bitOn(machine->regP, OVERFLOW_FL) && tmp >= 0x180) + machine->regP =setBit(machine->regP, OVERFLOW_FL, 0); + } + else { + machine->regP = setBit(machine->regP,CARRY_FL,0); + if (bitOn(machine->regP, OVERFLOW_FL) && tmp < 0x80) + machine->regP =setBit(machine->regP, OVERFLOW_FL, 0); + } + } + + machine->regA = tmp; + manZeroNeg(machine,machine->regA); +} + +static void jmpAND(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regA &= ptr.value; + manZeroNeg(machine,machine->regA); +} + +static void jmpASL(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + if (isValue){ + machine->regP = setBit(machine->regP, CARRY_FL, bitOn(ptr.value, NEGATIVE_FL)); + ptr.value = ptr.value << 1; + ptr.value = setBit(ptr.value, CARRY_FL, 0); + memStoreByte(machine, ptr.addr, ptr.value); + manZeroNeg(machine,ptr.value); + } + else { /* Accumulator */ + machine->regP = setBit(machine->regP, CARRY_FL, bitOn(machine->regA, NEGATIVE_FL)); + machine->regA = machine->regA << 1; + machine->regA = setBit(machine->regA, CARRY_FL, 0); + manZeroNeg(machine,machine->regA); + } + +} + +static void jmpBIT(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regP = setBit(machine->regP, ZERO_FL, !(ptr.value & machine->regA)); + machine->regP = setBit(machine->regP, OVERFLOW_FL, bitOn(ptr.value, OVERFLOW_FL)); + machine->regP = setBit(machine->regP, NEGATIVE_FL, bitOn(ptr.value, NEGATIVE_FL)); + +} + +static void jumpBranch(machine_6502 *machine, Bit16 offset){ + if ( offset > 0x7f ) + machine->regPC = machine->regPC - (0x100 - offset); + else + machine->regPC = machine->regPC + offset; +} + +static void jmpBPL(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOff(machine->regP,NEGATIVE_FL)) + jumpBranch(machine, ptr.addr); + +} + +static void jmpBMI(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOn(machine->regP,NEGATIVE_FL)) + jumpBranch(machine, ptr.addr); + +} + +static void jmpBVC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOff(machine->regP,OVERFLOW_FL)) + jumpBranch(machine, ptr.addr); +} + +static void jmpBVS(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOn(machine->regP,OVERFLOW_FL)) + jumpBranch(machine, ptr.addr); +} + +static void jmpBCC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOff(machine->regP,CARRY_FL)) + jumpBranch(machine, ptr.addr); +} + +static void jmpBCS(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOn(machine->regP,CARRY_FL)) + jumpBranch(machine, ptr.addr); +} + +static void jmpBNE(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOff(machine->regP, ZERO_FL)) + jumpBranch(machine, ptr.addr); +} + +static void jmpBEQ(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (bitOn(machine->regP, ZERO_FL)) + jumpBranch(machine, ptr.addr); +} + +static void doCompare(machine_6502 *machine, Bit16 reg, Pointer *ptr){ + machine->regP = setBit(machine->regP,CARRY_FL, ((reg + ptr->value) > 0xff)); + manZeroNeg(machine,(reg - ptr->value)); +} + +static void jmpCMP(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + doCompare(machine,machine->regA,&ptr); +} + +static void jmpCPX(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + doCompare(machine,machine->regX,&ptr); +} + +static void jmpCPY(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + doCompare(machine,machine->regY,&ptr); +} + +static void jmpDEC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + if (ptr.value > 0) + ptr.value--; + else + ptr.value = 0xFF; + memStoreByte(machine, ptr.addr, ptr.value); + manZeroNeg(machine,ptr.value); +} + +static void jmpEOR(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regA ^= ptr.value; + manZeroNeg(machine, machine->regA); +} + +static void jmpCLC(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, CARRY_FL, 0); +} + +static void jmpSEC(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, CARRY_FL, 1); +} + +static void jmpCLI(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, INTERRUPT_FL, 0); +} + +static void jmpSEI(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, INTERRUPT_FL, 1); +} + +static void jmpCLV(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); +} + +static void jmpCLD(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, DECIMAL_FL, 0); +} + +static void jmpSED(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = setBit(machine->regP, DECIMAL_FL, 1); +} + +static void jmpINC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + ptr.value = (ptr.value + 1) & 0xFF; + memStoreByte(machine, ptr.addr, ptr.value); + manZeroNeg(machine,ptr.value); +} + +static void jmpJMP(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regPC = ptr.addr; +} + +static void jmpJSR(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + /* Move past the 2 byte parameter. JSR is always followed by + absolute address. */ + Bit16 currAddr = machine->regPC + 2; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + stackPush(machine, (currAddr >> 8) & 0xff); + stackPush(machine, currAddr & 0xff); + machine->regPC = ptr.addr; +} + +static void jmpLDA(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regA = ptr.value; + manZeroNeg(machine, machine->regA); +} + +static void jmpLDX(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regX = ptr.value; + manZeroNeg(machine, machine->regX); +} + +static void jmpLDY(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regY = ptr.value; + manZeroNeg(machine, machine->regY); +} + +static void jmpLSR(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + if (isValue){ + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(ptr.value, CARRY_FL)); + ptr.value = ptr.value >> 1; + ptr.value = setBit(ptr.value,NEGATIVE_FL,0); + memStoreByte(machine,ptr.addr,ptr.value); + manZeroNeg(machine,ptr.value); + } + else { /* Accumulator */ + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(machine->regA, CARRY_FL)); + machine->regA = machine->regA >> 1; + machine->regA = setBit(machine->regA,NEGATIVE_FL,0); + manZeroNeg(machine,ptr.value); + } +} + +static void jmpNOP(machine_6502 *machine, m6502_AddrMode adm){ + /* no operation */ +} + +static void jmpORA(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + machine->regA |= ptr.value; + manZeroNeg(machine,machine->regA); +} + +static void jmpTAX(machine_6502 *machine, m6502_AddrMode adm){ + machine->regX = machine->regA; + manZeroNeg(machine,machine->regX); +} + +static void jmpTXA(machine_6502 *machine, m6502_AddrMode adm){ + machine->regA = machine->regX; + manZeroNeg(machine,machine->regA); +} + +static void jmpDEX(machine_6502 *machine, m6502_AddrMode adm){ + if (machine->regX > 0) + machine->regX--; + else + machine->regX = 0xFF; + manZeroNeg(machine, machine->regX); +} + +static void jmpINX(machine_6502 *machine, m6502_AddrMode adm){ + Bit16 value = machine->regX + 1; + machine->regX = value & 0xFF; + manZeroNeg(machine, machine->regX); +} + +static void jmpTAY(machine_6502 *machine, m6502_AddrMode adm){ + machine->regY = machine->regA; + manZeroNeg(machine, machine->regY); +} + +static void jmpTYA(machine_6502 *machine, m6502_AddrMode adm){ + machine->regA = machine->regY; + manZeroNeg(machine, machine->regA); +} + +static void jmpDEY(machine_6502 *machine, m6502_AddrMode adm){ + if (machine->regY > 0) + machine->regY--; + else + machine->regY = 0xFF; + manZeroNeg(machine, machine->regY); +} + +static void jmpINY(machine_6502 *machine, m6502_AddrMode adm){ + Bit16 value = machine->regY + 1; + machine->regY = value & 0xff; + manZeroNeg(machine, machine->regY); +} + +static void jmpROR(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + Bit8 cf; + BOOL isValue = getValue(machine, adm, &ptr); + if (isValue) { + cf = bitOn(machine->regP, CARRY_FL); + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(ptr.value, CARRY_FL)); + ptr.value = ptr.value >> 1; + ptr.value = setBit(ptr.value, NEGATIVE_FL, cf); + memStoreByte(machine, ptr.addr, ptr.value); + manZeroNeg(machine, ptr.value); + } + else { /* Implied */ + cf = bitOn(machine->regP, CARRY_FL); + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(machine->regA, CARRY_FL)); + machine->regA = machine->regA >> 1; + machine->regA = setBit(machine->regA, NEGATIVE_FL, cf); + manZeroNeg(machine, machine->regA); + } +} + +static void jmpROL(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + Bit8 cf; + BOOL isValue = getValue(machine, adm, &ptr); + if (isValue) { + cf = bitOn(machine->regP, CARRY_FL); + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(ptr.value, NEGATIVE_FL)); + ptr.value = ptr.value << 1; + ptr.value = setBit(ptr.value, CARRY_FL, cf); + memStoreByte(machine, ptr.addr, ptr.value); + manZeroNeg(machine, ptr.value); + } + else { /* Implied */ + cf = bitOn(machine->regP, CARRY_FL); + machine->regP = + setBit(machine->regP, CARRY_FL, + bitOn(machine->regA,NEGATIVE_FL)); + machine->regA = machine->regA << 1; + machine->regA = setBit(machine->regA, CARRY_FL, cf); + manZeroNeg(machine, machine->regA); + } +} + +static void jmpRTI(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = stackPop(machine); + machine->regPC = stackPop(machine); +} + +static void jmpRTS(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + Bit16 nr = stackPop(machine); + Bit16 nl = stackPop(machine); + warnValue(! isValue); + machine->regPC = (nl << 8) | nr; +} + +static void jmpSBC(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + /*Bit8 vflag;*/ + Bit8 c = bitOn(machine->regP, CARRY_FL); + Bit16 tmp, w; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + /*vflag = (bitOn(machine->regA,NEGATIVE_FL) && + bitOn(ptr.value, NEGATIVE_FL));*/ + + if (bitOn(machine->regP, DECIMAL_FL)) { + Bit8 ar = nibble(machine->regA, RIGHT); + Bit8 br = nibble(ptr.value, RIGHT); + Bit8 al = nibble(machine->regA, LEFT); + Bit8 bl = nibble(ptr.value, LEFT); + + tmp = 0xf + ar - br + c; + if ( tmp < 0x10){ + w = 0; + tmp -= 6; + } + else { + w = 0x10; + tmp -= 0x10; + } + w += 0xf0 + al - bl; + if ( w < 0x100) { + machine->regP = setBit(machine->regP, CARRY_FL, 0); + if (bitOn(machine->regP, OVERFLOW_FL) && w < 0x80) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + w -= 0x60; + } + else { + machine->regP = setBit(machine->regP, CARRY_FL, 1); + if (bitOn(machine->regP, OVERFLOW_FL) && w >= 0x180) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + } + w += tmp; + } /* end decimal mode */ + else { + w = 0xff + machine->regA - ptr.value + c; + if ( w < 0x100 ){ + machine->regP = setBit(machine->regP, CARRY_FL, 0); + if (bitOn(machine->regP, OVERFLOW_FL) && w < 0x80) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + } + else { + machine->regP = setBit(machine->regP, CARRY_FL, 1); + if (bitOn(machine->regP, OVERFLOW_FL) && w >= 0x180) + machine->regP = setBit(machine->regP, OVERFLOW_FL, 0); + } + } + machine->regA = w; + manZeroNeg(machine,machine->regA); +} + +static void jmpSTA(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + memStoreByte(machine,ptr.addr,machine->regA); +} + +static void jmpTXS(machine_6502 *machine, m6502_AddrMode adm){ + stackPush(machine,machine->regX); +} + +static void jmpTSX(machine_6502 *machine, m6502_AddrMode adm){ + machine->regX = stackPop(machine); + manZeroNeg(machine, machine->regX); +} + +static void jmpPHA(machine_6502 *machine, m6502_AddrMode adm){ + stackPush(machine, machine->regA); +} + +static void jmpPLA(machine_6502 *machine, m6502_AddrMode adm){ + machine->regA = stackPop(machine); + manZeroNeg(machine, machine->regA); +} + +static void jmpPHP(machine_6502 *machine, m6502_AddrMode adm){ + stackPush(machine,machine->regP); +} + +static void jmpPLP(machine_6502 *machine, m6502_AddrMode adm){ + machine->regP = stackPop(machine); + machine->regP = setBit(machine->regP, FUTURE_FL, 1); +} + +static void jmpSTX(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + memStoreByte(machine,ptr.addr,machine->regX); +} + +static void jmpSTY(machine_6502 *machine, m6502_AddrMode adm){ + Pointer ptr; + BOOL isValue = getValue(machine, adm, &ptr); + warnValue(isValue); + memStoreByte(machine,ptr.addr,machine->regY); +} + + + +/* OPCODES */ +static void assignOpCodes(m6502_Opcodes *opcodes){ + + #define SETOP(num, _name, _Imm, _ZP, _ZPX, _ZPY, _ABS, _ABSX, _ABSY, _INDX, _INDY, _SNGL, _BRA, _func) \ +{opcodes[num].name[3] = '\0'; \ + strncpy(opcodes[num].name, _name, 3); opcodes[num].Imm = _Imm; opcodes[num].ZP = _ZP; \ + opcodes[num].ZPX = _ZPX; opcodes[num].ZPY = _ZPY; opcodes[num].ABS = _ABS; \ + opcodes[num].ABSX = _ABSX; opcodes[num].ABSY = _ABSY; opcodes[num].INDX = _INDX; \ + opcodes[num].INDY = _INDY; opcodes[num].SNGL = _SNGL; opcodes[num].BRA = _BRA; \ + opcodes[num].func = _func;} + + /* OPCODE Imm ZP ZPX ZPY ABS ABSX ABSY INDX INDY SGNL BRA Jump Function*/ + SETOP( 0, "ADC", 0x69, 0x65, 0x75, 0x00, 0x6d, 0x7d, 0x79, 0x61, 0x71, 0x00, 0x00, jmpADC); + SETOP( 1, "AND", 0x29, 0x25, 0x35, 0x31, 0x2d, 0x3d, 0x39, 0x00, 0x00, 0x00, 0x00, jmpAND); + SETOP( 2, "ASL", 0x00, 0x06, 0x16, 0x00, 0x0e, 0x1e, 0x00, 0x00, 0x00, 0x0a, 0x00, jmpASL); + SETOP( 3, "BIT", 0x00, 0x24, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpBIT); + SETOP( 4, "BPL", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, jmpBPL); + SETOP( 5, "BMI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, jmpBMI); + SETOP( 6, "BVC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, jmpBVC); + SETOP( 7, "BVS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, jmpBVS); + SETOP( 8, "BCC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, jmpBCC); + SETOP( 9, "BCS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, jmpBCS); + SETOP(10, "BNE", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, jmpBNE); + SETOP(11, "BEQ", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, jmpBEQ); + SETOP(12, "CMP", 0xc9, 0xc5, 0xd5, 0x00, 0xcd, 0xdd, 0xd9, 0xc1, 0xd1, 0x00, 0x00, jmpCMP); + SETOP(13, "CPX", 0xe0, 0xe4, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpCPX); + SETOP(14, "CPY", 0xc0, 0xc4, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpCPY); + SETOP(15, "DEC", 0x00, 0xc6, 0xd6, 0x00, 0xce, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, jmpDEC); + SETOP(16, "EOR", 0x49, 0x45, 0x55, 0x00, 0x4d, 0x5d, 0x59, 0x41, 0x51, 0x00, 0x00, jmpEOR); + SETOP(17, "CLC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, jmpCLC); + SETOP(18, "SEC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, jmpSEC); + SETOP(19, "CLI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, jmpCLI); + SETOP(20, "SEI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, jmpSEI); + SETOP(21, "CLV", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, jmpCLV); + SETOP(22, "CLD", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, jmpCLD); + SETOP(23, "SED", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, jmpSED); + SETOP(24, "INC", 0x00, 0xe6, 0xf6, 0x00, 0xee, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, jmpINC); + SETOP(25, "JMP", 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpJMP); + SETOP(26, "JSR", 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpJSR); + SETOP(27, "LDA", 0xa9, 0xa5, 0xb5, 0x00, 0xad, 0xbd, 0xb9, 0xa1, 0xb1, 0x00, 0x00, jmpLDA); + SETOP(28, "LDX", 0xa2, 0xa6, 0x00, 0xb6, 0xae, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, jmpLDX); + SETOP(29, "LDY", 0xa0, 0xa4, 0xb4, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, jmpLDY); + SETOP(30, "LSR", 0x00, 0x46, 0x56, 0x00, 0x4e, 0x5e, 0x00, 0x00, 0x00, 0x4a, 0x00, jmpLSR); + SETOP(31, "NOP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, jmpNOP); + SETOP(32, "ORA", 0x09, 0x05, 0x15, 0x00, 0x0d, 0x1d, 0x19, 0x01, 0x11, 0x00, 0x00, jmpORA); + SETOP(33, "TAX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, jmpTAX); + SETOP(34, "TXA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, jmpTXA); + SETOP(35, "DEX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x00, jmpDEX); + SETOP(36, "INX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, jmpINX); + SETOP(37, "TAY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, jmpTAY); + SETOP(38, "TYA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, jmpTYA); + SETOP(39, "DEY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, jmpDEY); + SETOP(40, "INY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, jmpINY); + SETOP(41, "ROR", 0x00, 0x66, 0x76, 0x00, 0x6e, 0x7e, 0x00, 0x00, 0x00, 0x6a, 0x00, jmpROR); + SETOP(42, "ROL", 0x00, 0x26, 0x36, 0x00, 0x2e, 0x3e, 0x00, 0x00, 0x00, 0x2a, 0x00, jmpROL); + SETOP(43, "RTI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, jmpRTI); + SETOP(44, "RTS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, jmpRTS); + SETOP(45, "SBC", 0xe9, 0xe5, 0xf5, 0x00, 0xed, 0xfd, 0xf9, 0xe1, 0xf1, 0x00, 0x00, jmpSBC); + SETOP(46, "STA", 0x00, 0x85, 0x95, 0x00, 0x8d, 0x9d, 0x99, 0x81, 0x91, 0x00, 0x00, jmpSTA); + SETOP(47, "TXS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, jmpTXS); + SETOP(48, "TSX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, jmpTSX); + SETOP(49, "PHA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, jmpPHA); + SETOP(50, "PLA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, jmpPLA); + SETOP(51, "PHP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, jmpPHP); + SETOP(52, "PLP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, jmpPLP); + SETOP(53, "STX", 0x00, 0x86, 0x00, 0x96, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpSTX); + SETOP(54, "STY", 0x00, 0x84, 0x94, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpSTY); + SETOP(55, "---", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, NULL); +} + +static void buildIndexCache(machine_6502 *machine){ + unsigned int i; + for (i = 0; i < NUM_OPCODES; i++) { + if (machine->opcodes[i].Imm != 0x00){ + machine->opcache[machine->opcodes[i].Imm].adm = IMMEDIATE_VALUE; + machine->opcache[machine->opcodes[i].Imm].index = i; + } + if (machine->opcodes[i].ZP != 0x00){ + machine->opcache[machine->opcodes[i].ZP].adm = ZERO; + machine->opcache[machine->opcodes[i].ZP].index = i; + } + if (machine->opcodes[i].ZPX != 0x00){ + machine->opcache[machine->opcodes[i].ZPX].adm = ZERO_X; + machine->opcache[machine->opcodes[i].ZPX].index = i;; + } + if (machine->opcodes[i].ZPY != 0x00){ + machine->opcache[machine->opcodes[i].ZPY].adm = ZERO_Y; + machine->opcache[machine->opcodes[i].ZPY].index = i;; + } + if (machine->opcodes[i].ABS != 0x00){ + machine->opcache[machine->opcodes[i].ABS].adm = ABS_VALUE; + machine->opcache[machine->opcodes[i].ABS].index = i;; + } + if (machine->opcodes[i].ABSX != 0x00){ + machine->opcache[machine->opcodes[i].ABSX].adm = ABS_X; + machine->opcache[machine->opcodes[i].ABSX].index = i;; + } + if (machine->opcodes[i].ABSY != 0x00){ + machine->opcache[machine->opcodes[i].ABSY].adm = ABS_Y; + machine->opcache[machine->opcodes[i].ABSY].index = i;; + } + if (machine->opcodes[i].INDX != 0x00){ + machine->opcache[machine->opcodes[i].INDX].adm = INDIRECT_X; + machine->opcache[machine->opcodes[i].INDX].index = i;; + } + if (machine->opcodes[i].INDY != 0x00){ + machine->opcache[machine->opcodes[i].INDY].adm = INDIRECT_Y; + machine->opcache[machine->opcodes[i].INDY].index = i;; + } + if (machine->opcodes[i].SNGL != 0x00){ + machine->opcache[machine->opcodes[i].SNGL].adm = SINGLE; + machine->opcache[machine->opcodes[i].SNGL].index = i; + } + if (machine->opcodes[i].BRA != 0x00){ + machine->opcache[machine->opcodes[i].BRA].adm = ABS_OR_BRANCH; + machine->opcache[machine->opcodes[i].BRA].index = i; + } + } +} + +/* opIndex() - Search the opcode table for a match. If found return + the index into the optable and the address mode of the opcode. If + the opcode is not found then return -1. */ +static int opIndex(machine_6502 *machine, Bit8 opcode, m6502_AddrMode *adm){ + /* XXX could catch errors by setting a addressmode of error or something */ + *adm = machine->opcache[opcode].adm; + return machine->opcache[opcode].index; +} + + +/* Assembly parser */ + +static Param *newParam(void){ + Param *newp; + int i = 0; + + newp = (Param *) ecalloc(1, sizeof(Param)); + newp->type = SINGLE; + for (i = 0; i < MAX_PARAM_VALUE; i++) + newp->value[i] = 0; + newp->vp = 0; + newp->label = ecalloc(MAX_LABEL_LEN,sizeof(char)); + newp->lbladdr = 0; + return newp; +} + +/* Copy the fields from p2 to p1 */ +static void copyParam(Param *p1, Param *p2){ + int i = 0; + strncpy(p1->label,p2->label,MAX_LABEL_LEN); + for(i = 0; i < MAX_PARAM_VALUE; i++) + p1->value[i] = p2->value[i]; + p1->vp = p2->vp; + p1->type = p2->type; +} + +static Label *newLabel(void){ + Label *newp; + + newp = (Label *) ecalloc(1, sizeof(Label)); + newp->addr = 0; + newp->label = ecalloc(MAX_LABEL_LEN,sizeof(char)); + + return newp; +} + +static AsmLine *newAsmLine(char *cmd, char *label, BOOL decl, Param *param, int lc) +{ + AsmLine *newp; + + newp = (AsmLine *) ecalloc(1, sizeof(AsmLine)); + newp->labelDecl = decl; + newp->label = newLabel(); + strncpy(newp->label->label,label,MAX_LABEL_LEN); + newp->command = estrdup(cmd); + newp->param = newParam(); + copyParam(newp->param, param); + newp->next = NULL; + return newp; +} + +static AsmLine *addend(AsmLine *listp, AsmLine *newp) +{ + AsmLine *p; + if(listp == NULL) + return newp; + for (p =listp; p->next != NULL; p = p->next) + ; + p->next = newp; + return listp; +} + +static BOOL apply(AsmLine *listp, BOOL(*fn)(AsmLine*, void*), void *arg) +{ + AsmLine *p; + if(listp == NULL) + return FALSE; + for (p = listp; p != NULL; p = p->next) + if (! fn(p,arg) ) + return FALSE; + return TRUE; +} + +static void freeParam(Param *param){ + free(param->label); + free(param); +} + +static void freeLabel(Label *label){ + free(label->label); + free(label); +} + +static void freeallAsmLine(AsmLine *listp) +{ + AsmLine *next; + for(; listp != NULL; listp = next){ + next = listp->next; + freeParam(listp->param); + freeLabel(listp->label); + free(listp->command); + free(listp); + } +} + +static BOOL addvalue(Param *param,Bit32 value){ + /* jwz: suppress "0 <= unsigned" warning */ + if (/*0 <= param->vp &&*/ param->vp < MAX_PARAM_VALUE) { + param->value[param->vp++] = value; + return TRUE; + } + else { + fprintf(stderr,"Wrong number of parameters: %d. The limit is %d\n",param->vp+1, MAX_PARAM_VALUE); + return FALSE; + } +} + +static void parseError(char *s){ + fprintf(stderr,"6502 Syntax Error: %s\n", s); +} + +/* stoupper() - Destructivley modifies the string making all letters upper case*/ +static void stoupper(char **s){ + int i = 0; + while((*s)[i] != '\0'){ + (*s)[i] = toupper((*s)[i]); + i++; + } +} + +static BOOL isWhite(char c){ + return (c == '\r' || c == '\t' || c == ' '); +} + +static void skipSpace(char **s){ + for(; isWhite(**s); (*s)++) + ; +} + +/* nullify() - fills a string with upto sourceLength null characters. */ +static void nullify(char *token, unsigned int sourceLength){ + unsigned int i = 0; + while (i < sourceLength) + token[i++] = '\0'; +} + +static BOOL isBlank(const char *token){ + return (token[0] == '\0'); +} + +static BOOL isCommand(machine_6502 *machine, const char *token){ + int i = 0; + + while (i < NUM_OPCODES) { + if (strcmp(machine->opcodes[i].name,token) == 0) + return TRUE; + i++; + } + + if (strcmp(token, "DCB") == 0) return TRUE; + return FALSE; +} + +/* hasChar() - Check to see if the current line has a certain + charater */ +static BOOL hasChar(char *s, char c){ + for(; *s != '\0' && *s != '\n'; s++) { + if (*s == c) + return TRUE; + } + return FALSE; +} + +static BOOL ishexdigit(char c){ + if (isdigit(c)) + return TRUE; + else { + char c1 = toupper(c); + return ('A' <= c1 && c1 <= 'F'); + } +} + +/* isCmdChar() - Is this a valid character for a command. All of the + command are alpha except for the entry point code that is "*=" */ +static BOOL isCmdChar(char c){ + return (isalpha(c) || c == '*' || c == '='); +} + + +/* command() - parse a command from the source code. We pass along a + machine so the opcode can be validated. */ +static BOOL command(machine_6502 *machine, char **s, char **cmd){ + int i = 0; + skipSpace(s); + for(;isCmdChar(**s) && i < MAX_CMD_LEN; (*s)++) + (*cmd)[i++] = **s; + if (i == 0) + return TRUE; /* Could be a blank line. */ + else if (strcmp(*cmd,"*=") == 0) + return TRUE; /* This is an entry point. */ + else + return isCommand(machine,*cmd); +} + +static BOOL declareLabel(char **s, char **label){ + int i = 0; + skipSpace(s); + for(;**s != ':' && **s != '\n' && **s != '\0'; (*s)++){ + if (isWhite(**s)) + continue; + (*label)[i++] = **s; + } + if (i == 0) + return FALSE; /* Current line has to have a label */ + else if (**s == ':'){ + (*s)++; /* Skip colon */ + return TRUE; + } + else + return FALSE; +} + +static BOOL parseHex(char **s, Bit32 *value){ + enum { MAX_HEX_LEN = 5 }; + if (**s == '$') { + char *hex = ecalloc(MAX_HEX_LEN, sizeof(char)); + int i = 0; + + (*s)++; /* move pass $ */ + for(; ishexdigit(**s) && i < MAX_HEX_LEN; (*s)++) + hex[i++] = **s; + + *value = strtol(hex,NULL,16); + free(hex); + return TRUE; + } + else + return FALSE; +} + +static BOOL parseDec(char **s, Bit32 *value){ + enum { MAX_DEC_LEN = 4 }; + char *dec = ecalloc(MAX_DEC_LEN, sizeof(char)); + int i; + for(i = 0; isdigit(**s) && i < MAX_DEC_LEN; (*s)++) + dec[i++] = **s; + + if (i > 0){ + *value = atoi(dec); + free(dec); + return TRUE; + } + else{ + free(dec); + return FALSE; + } +} + +static BOOL parseValue(char **s, Bit32 *value){ + skipSpace(s); + if (**s == '$') + return parseHex(s, value); + else + return parseDec(s, value); +} + +static BOOL paramLabel(char **s, char **label){ + int i; + for(i = 0; (isalnum(**s) || **s == '_') && i < MAX_LABEL_LEN; (*s)++) + (*label)[i++] = **s; + + if (i > 0) + return TRUE; + else + return FALSE; +} + +static BOOL immediate(char **s, Param *param){ + if (**s != '#') + return FALSE; + + (*s)++; /*Move past hash */ + if (**s == '<' || **s == '>'){ + char *label = ecalloc(MAX_LABEL_LEN, sizeof(char)); + param->type = (**s == '<') ? IMMEDIATE_LESS : IMMEDIATE_GREAT; + (*s)++; /* move past < or > */ + if (paramLabel(s, &label)){ + int ln = strlen(label) + 1; + strncpy(param->label, label, ln); + free(label); + return TRUE; + } + free(label); + } + else { + Bit32 value; + if (parseValue(s, &value)){ + if (value > 0xFF){ + parseError("Immediate value is too large."); + return FALSE; + } + param->type = IMMEDIATE_VALUE; + return addvalue(param, value); + } + } + return FALSE; +} + +static BOOL isDirection(char c){ + return (c == 'X' || c == 'Y'); +} + +static BOOL getDirection(char **s, char *direction){ + skipSpace(s); + if (**s == ','){ + (*s)++; + skipSpace(s); + if (isDirection(**s)){ + *direction = **s; + (*s)++; + return TRUE; + } + } + return FALSE; +} + +static BOOL indirect(char **s, Param *param){ + Bit32 value; + char c; + if (**s == '(') + (*s)++; + else + return FALSE; + + if (! parseHex(s,&value)) + return FALSE; + if (value > 0xFF) { + parseError("Indirect value is too large."); + return FALSE; + } + if (!addvalue(param, value)) + return FALSE; + skipSpace(s); + if (**s == ')'){ + (*s)++; + if (getDirection(s,&c)) { + if (c == 'Y'){ + param->type = INDIRECT_Y; + return TRUE; + } + } + } + else if (getDirection(s, &c)){ + if (c == 'X'){ + skipSpace(s); + if (**s == ')'){ + (*s)++; + param->type = INDIRECT_X; + return TRUE; + } + } + } + return FALSE; +} + +static BOOL dcbValue(char **s, Param *param){ + Bit32 val; + if (! parseValue(s,&val)) + return FALSE; + + if (val > 0xFF) + return FALSE; + + if (!addvalue(param,val)) + return FALSE; + + param->type = DCB_PARAM; + + skipSpace(s); + if(**s == ','){ + (*s)++; + return dcbValue(s, param); + } + else + return TRUE; +} + +static BOOL value(char **s, Param *param){ + Bit32 val; + BOOL abs; + BOOL dir; + char c = '\0'; + if (! parseValue(s,&val)) + return FALSE; + + abs = (val > 0xFF); + dir = getDirection(s,&c); + if (!addvalue(param,val)) + return FALSE; + + if(abs && dir){ + if (c == 'X') + param->type = ABS_X; + else if (c == 'Y') + param->type = ABS_Y; + else + return FALSE; + } + else if (abs) + param->type = ABS_VALUE; + else if (dir){ + if (c == 'X') + param->type = ZERO_X; + else if (c == 'Y') + param->type = ZERO_Y; + else + return FALSE; + } + else + param->type = ZERO; + + return TRUE; +} + +static BOOL label(char **s, Param *param){ + char *label = ecalloc(MAX_LABEL_LEN, sizeof(char)); + char c; + BOOL labelOk = FALSE; + if (paramLabel(s, &label)){ + labelOk = TRUE; + param->type = ABS_OR_BRANCH; + if (getDirection(s, &c)){ + if (c == 'X') + param->type = ABS_LABEL_X; + else if (c == 'Y') + param->type = ABS_LABEL_Y; + else + labelOk = FALSE; + } + strncpy(param->label,label,MAX_LABEL_LEN); + } + free(label); + return labelOk; +} + +static BOOL parameter(const char *cmd, char **s, Param *param){ + skipSpace(s); + if (**s == '\0' || **s == '\n') + return TRUE; + else if (**s == '#') + return immediate(s,param); + else if (**s == '(') + return indirect(s,param); + else if (**s == '$' || isdigit(**s)){ + if (strcmp(cmd, "DCB") == 0) + return dcbValue(s,param); + else + return value(s,param); + } + else if (isalpha(**s)) + return label(s ,param); + else + return FALSE; /* Invalid Parameter */ +} + +static void comment(char **s){ + skipSpace(s); + if (**s == ';') + for(;**s != '\n' && **s != '\0'; (*s)++) + ; +} + +static void initParam(Param *param){ + int i; + param->type = SINGLE; + for(i = 0; i < MAX_PARAM_VALUE; i++) + param->value[i] = 0; + param->vp = 0; + nullify(param->label,MAX_LABEL_LEN); +} + + +static AsmLine *parseAssembly(machine_6502 *machine, BOOL *codeOk, const char *code){ + char *s; + char *cmd = ecalloc(MAX_CMD_LEN, sizeof(char)); + char *label = ecalloc(MAX_LABEL_LEN, sizeof(char)); + char *start; /*pointer to the start of the code.*/ + unsigned int lc = 1; + Param *param; + BOOL decl; + AsmLine *listp = NULL; + + *codeOk = TRUE; + param = newParam(); + s = estrdup(code); + start = s; + stoupper(&s); + + while(*s != '\0' && *codeOk){ + initParam(param); + nullify(cmd, MAX_CMD_LEN); + nullify(label, MAX_LABEL_LEN); + decl = FALSE; + skipSpace(&s); + comment(&s); + if (*s == '\n'){ + lc++; + s++; + continue; /* blank line */ + } + else if (*s == '\0') + continue; /* no newline at the end of the code */ + else if (hasChar(s,':')){ + decl = TRUE; + if(! declareLabel(&s,&label)){ + *codeOk = FALSE; + break; + } + skipSpace(&s); + } + if(!command(machine, &s, &cmd)){ + *codeOk = FALSE; + break; + } + skipSpace(&s); + comment(&s); + if(!parameter(cmd, &s, param)){ + *codeOk = FALSE; + break; + } + skipSpace(&s); + comment(&s); + if (*s == '\n' || *s == '\0'){ + AsmLine *asmm; + asmm = newAsmLine(cmd,label,decl,param,lc); + listp = addend(listp,asmm); + } + else { + *codeOk = FALSE; + break; + } + } + if (! *codeOk) + fprintf(stderr,"Syntax error at line %u\n", lc); + free(start); + free(cmd); + free(label); + freeParam(param); + return listp; +} + +#ifdef READ_FILES +/* fileToBuffer() - Allocates a buffer and loads all of the file into memory. */ +static char *fileToBuffer(const char *filename){ + const int defaultSize = 1024; + FILE *ifp; + int c; + int size = defaultSize; + int i = 0; + char *buffer = ecalloc(defaultSize,sizeof(char)); + + if (!buffer) abort(); + + ifp = fopen(filename, "rb"); + if (!ifp) abort(); + + while((c = getc(ifp)) != EOF){ + buffer[i++] = c; + if (i == size){ + size += defaultSize; + buffer = realloc(buffer, size); + if (buffer == NULL) { + abort(); + } + } + } + fclose(ifp); + buffer = realloc(buffer, i+2); + if (!buffer) abort(); + /* Make sure we have a line feed at the end */ + buffer[i] = '\n'; + buffer[i+1] = '\0'; + return buffer; +} +#endif + + +/* Routines */ + +/* reset() - Reset CPU and memory. */ +static void reset(machine_6502 *machine){ + int x, y; + for ( y = 0; y < 32; y++ ){ + for (x = 0; x < 32; x++){ + machine->screen[x][y] = 0; + } + } + + for(x=0; x < MEM_64K; x++) + machine->memory[x] = 0; + + machine->codeCompiledOK = FALSE; + machine->regA = 0; + machine->regX = 0; + machine->regY = 0; + machine->regP = setBit(machine->regP, FUTURE_FL, 1); + machine->defaultCodePC = machine->regPC = PROG_START; + machine->regSP = STACK_TOP; + machine->runForever = FALSE; + machine->labelPtr = 0; + machine->codeRunning = FALSE; +} + +/* hexDump() - Dump the memory to output */ +void m6502_hexDump(machine_6502 *machine, Bit16 start, Bit16 numbytes, FILE *output){ + Bit32 address; + Bit32 i; + for( i = 0; i < numbytes; i++){ + address = start + i; + if ( (i&15) == 0 ) { + fprintf(output,"\n%.4x: ", address); + } + fprintf(output,"%.2x%s",machine->memory[address], (i & 1) ? " ":""); + } + fprintf(output,"%s\n",(i&1)?"--":""); +} + +/* XXX */ +/* void save_program(machine_6502 *machine, char *filename){ */ +/* FILE *ofp; */ +/* Bit16 pc = PROG_START; */ +/* Bit16 end = pc + machine->codeLen; */ +/* Bit16 n; */ +/* ofp = fopen(filename, "w"); */ +/* if (!ofp) abort(); */ + +/* fprintf(ofp,"Bit8 prog[%d] =\n{",machine->codeLen); */ +/* n = 1; */ +/* while(pc < end) */ +/* fprintf(ofp,"0x%.2x,%s",machine->memory[pc++],n++%10?" ":"\n"); */ +/* fseek(ofp,-2,SEEK_CUR); */ +/* fprintf(ofp,"};\n"); */ + +/* fclose(ofp); */ +/* } */ + +static BOOL translate(m6502_Opcodes *op,Param *param, machine_6502 *machine){ + switch(param->type){ + case SINGLE: + if (op->SNGL) + pushByte(machine, op->SNGL); + else { + fprintf(stderr,"%s needs a parameter.\n",op->name); + return FALSE; + } + break; + case IMMEDIATE_VALUE: + if (op->Imm) { + pushByte(machine, op->Imm); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take IMMEDIATE_VALUE parameters.\n",op->name); + return FALSE; + } + case IMMEDIATE_GREAT: + if (op->Imm) { + pushByte(machine, op->Imm); + pushByte(machine, param->lbladdr >> 8); + break; + } + else { + fprintf(stderr,"%s does not take IMMEDIATE_GREAT parameters.\n",op->name); + return FALSE; + } + case IMMEDIATE_LESS: + if (op->Imm) { + pushByte(machine, op->Imm); + pushByte(machine, param->lbladdr & 0xFF); + break; + } + else { + fprintf(stderr,"%s does not take IMMEDIATE_LESS parameters.\n",op->name); + return FALSE; + } + case INDIRECT_X: + if (op->INDX) { + pushByte(machine, op->INDX); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take INDIRECT_X parameters.\n",op->name); + return FALSE; + } + case INDIRECT_Y: + if (op->INDY) { + pushByte(machine, op->INDY); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take INDIRECT_Y parameters.\n",op->name); + return FALSE; + } + case ZERO: + if (op->ZP) { + pushByte(machine, op->ZP); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ZERO parameters.\n",op->name); + return FALSE; + } + case ZERO_X: + if (op->ZPX) { + pushByte(machine, op->ZPX); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ZERO_X parameters.\n",op->name); + return FALSE; + } + case ZERO_Y: + if (op->ZPY) { + pushByte(machine, op->ZPY); + pushByte(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ZERO_Y parameters.\n",op->name); + return FALSE; + } + case ABS_VALUE: + if (op->ABS) { + pushByte(machine, op->ABS); + pushWord(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ABS_VALUE parameters.\n",op->name); + return FALSE; + } + case ABS_OR_BRANCH: + if (op->ABS > 0){ + pushByte(machine, op->ABS); + pushWord(machine, param->lbladdr); + } + else { + if (op->BRA) { + pushByte(machine, op->BRA); + { + int diff = abs((int)param->lbladdr - (int)machine->defaultCodePC); + int backward = (param->lbladdr < machine->defaultCodePC); + pushByte(machine, (backward) ? 0xff - diff : diff - 1); + } + } + else { + fprintf(stderr,"%s does not take BRANCH parameters.\n",op->name); + return FALSE; + } + } + break; + case ABS_X: + if (op->ABSX) { + pushByte(machine, op->ABSX); + pushWord(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ABS_X parameters.\n",op->name); + return FALSE; + } + case ABS_Y: + if (op->ABSY) { + pushByte(machine, op->ABSY); + pushWord(machine, param->value[0]); + break; + } + else { + fprintf(stderr,"%s does not take ABS_Y parameters.\n",op->name); + return FALSE; + } + case ABS_LABEL_X: + if (op->ABSX) { + pushByte(machine, op->ABSX); + pushWord(machine, param->lbladdr); + break; + } + else { + fprintf(stderr,"%s does not take ABS_LABEL_X parameters.\n",op->name); + return FALSE; + } + case ABS_LABEL_Y: + if (op->ABSY) { + pushByte(machine, op->ABSY); + pushWord(machine, param->lbladdr); + break; + } + else { + fprintf(stderr,"%s does not take ABS_LABEL_Y parameters.\n",op->name); + return FALSE; + } + case DCB_PARAM: + /* Handled elsewhere */ + break; + } + return TRUE; +} + +/* compileLine() - Compile one line of code. Returns + TRUE if it compile successfully. */ +static BOOL compileLine(AsmLine *asmline, void *args){ + machine_6502 *machine; + machine = args; + if (isBlank(asmline->command)) return TRUE; + if (strcmp("*=",asmline->command) == 0){ + machine->defaultCodePC = asmline->param->value[0]; + } + else if (strcmp("DCB",asmline->command) == 0){ + int i; + for(i = 0; i < asmline->param->vp; i++) + pushByte(machine, asmline->param->value[i]); + } + else{ + int i; + char *command = asmline->command; + m6502_Opcodes op; + for(i = 0; i < NUM_OPCODES; i++){ + if (strcmp(machine->opcodes[i].name, command) == 0){ + op = machine->opcodes[i]; + break; + } + } + if (i == NUM_OPCODES) + return FALSE; /* unknow upcode */ + else + return translate(&op,asmline->param,machine); + } + return TRUE; +} + +/* indexLabels() - Get the address for each label */ +static BOOL indexLabels(AsmLine *asmline, void *arg){ + machine_6502 *machine; + int thisPC; + Bit16 oldDefault; + machine = arg; + oldDefault = machine->defaultCodePC; + thisPC = machine->regPC; + /* Figure out how many bytes this instruction takes */ + machine->codeLen = 0; + + if ( ! compileLine(asmline, machine) ){ + return FALSE; + } + + /* If the machine's defaultCodePC has changed then we encountered a + *= which changes the load address. We need to initials our code + *counter with the current default. */ + if (oldDefault == machine->defaultCodePC){ + machine->regPC += machine->codeLen; + } + else { + machine->regPC = machine->defaultCodePC; + /*oldDefault = machine->defaultCodePC;*/ + } + + if (asmline->labelDecl) { + asmline->label->addr = thisPC; + } + return TRUE; +} + +static BOOL changeParamLabelAddr(AsmLine *asmline, void *label){ + Label *la = label; + if (strcmp(asmline->param->label, la->label) == 0) + asmline->param->lbladdr = la->addr; + return TRUE; +} + +static BOOL linkit(AsmLine *asmline, void *asmlist){ + apply(asmlist,changeParamLabelAddr,asmline->label); + return TRUE; +} + +/* linkLabels - Make sure all of the references to the labels contain + the right address*/ +static void linkLabels(AsmLine *asmlist){ + apply(asmlist,linkit,asmlist); +} + +/* compileCode() - Compile the current assembly code for the machine */ +static BOOL compileCode(machine_6502 *machine, const char *code){ + BOOL codeOk; + AsmLine *asmlist; + + reset(machine); + machine->defaultCodePC = machine->regPC = PROG_START; + asmlist = parseAssembly(machine, &codeOk, code); + + if(codeOk){ + /* First pass: Find the addresses for the labels */ + if (!apply(asmlist, indexLabels, machine)) + return FALSE; + /* update label references */ + linkLabels(asmlist); + +#if 0 /* prints out some debugging information */ + { + AsmLine *p; + if(asmlist != NULL){ + for (p = asmlist; p != NULL; p = p->next) + fprintf(stderr,"%s lbl: %s addr: %x ParamLbl: %s ParamAddr: %x\n", + p->command, p->label->label, p->label->addr, + p->param->label, p->param->lbladdr); + } + } + +#endif + + /* Second pass: translate the instructions */ + machine->codeLen = 0; + /* Link label call push_byte which increments defaultCodePC. + We need to reset it so the compiled code goes in the + correct spot. */ + machine->defaultCodePC = PROG_START; + if (!apply(asmlist, compileLine, machine)) + return FALSE; + + if (machine->defaultCodePC > PROG_START ){ + machine->memory[machine->defaultCodePC] = 0x00; + codeOk = TRUE; + } + else{ + fprintf(stderr,"No Code to run.\n"); + codeOk = FALSE; + } + } + else{ + fprintf(stderr,"An error occured while parsing the file.\n"); + codeOk = FALSE; + } + freeallAsmLine(asmlist); + return codeOk; +} + + +/* + * execute() - Executes one instruction. + * This is the main part of the CPU emulator. + * + */ + +static void execute(machine_6502 *machine){ + Bit8 opcode; + m6502_AddrMode adm; + int opidx; + + if(!machine->codeRunning) return; + + opcode = popByte(machine); + if (opcode == 0x00) + machine->codeRunning = FALSE; + else { + opidx = opIndex(machine,opcode,&adm); + if(opidx > -1) + machine->opcodes[opidx].func(machine, adm); + else + fprintf(stderr,"Invalid opcode!\n"); + } + if( (machine->regPC == 0) || + (!machine->codeRunning) ) { + machine->codeRunning = FALSE; + } +} + +machine_6502 *m6502_build(void){ + machine_6502 *machine; + machine = ecalloc(1, sizeof(machine_6502)); + assignOpCodes(machine->opcodes); + buildIndexCache(machine); + reset(machine); + return machine; +} + +void m6502_destroy6502(machine_6502 *machine){ + free(machine); + machine = NULL; +} + +void m6502_trace(machine_6502 *machine, FILE *output){ + Bit8 opcode = memReadByte(machine,machine->regPC); + m6502_AddrMode adm; + Pointer ptr; + int opidx = opIndex(machine,opcode,&adm); + int stacksz = STACK_TOP - machine->regSP; + + fprintf(output,"\n NVFBDIZC\nP: %d%d%d%d%d%d%d%d ", + bitOn(machine->regP,NEGATIVE_FL), + bitOn(machine->regP,OVERFLOW_FL), + bitOn(machine->regP,FUTURE_FL), + bitOn(machine->regP,BREAK_FL), + bitOn(machine->regP,DECIMAL_FL), + bitOn(machine->regP,INTERRUPT_FL), + bitOn(machine->regP,ZERO_FL), + bitOn(machine->regP,CARRY_FL)); + fprintf(output,"A: %.2x X: %.2x Y: %.2x SP: %.4x PC: %.4x\n", + machine->regA, machine->regX, machine->regY, machine->regSP, machine->regPC); + if (opidx > -1){ + Bit16 pc = machine->regPC; + fprintf(output,"\n%.4x:\t%s",machine->regPC, machine->opcodes[opidx].name); + if (peekValue(machine, adm, &ptr, pc+1)) + fprintf(output,"\tAddress:%.4x\tValue:%.4x\n", + ptr.addr,ptr.value); + else + fprintf(output,"\n"); + } + fprintf(output,"STACK:"); + m6502_hexDump(machine,(STACK_TOP - stacksz) + 1, stacksz, output); +} + +#if 0 +void disassemble(machine_6502 *machine, FILE *output){ + /* Read the opcode + increment the program counter + print the opcode + loop until end of program. */ + m6502_AddrMode adm; + Bit16 addr; + Bit8 opcode; + int opidx; + char *mem; + int i; + Bit16 opc = machine->regPC; + mem = calloc(20,sizeof(char)); + machine->regPC = PROG_START; + do{ + addr = machine->regPC; + opcode = popByte(machine); + opidx = opIndex(machine,opcode,&adm); + for (i = 0; i < 20; i++) mem[i] = '\0'; + dismem(machine, adm, mem); + fprintf(output,"%x\t%s\t%s\n", + addr,machine->opcodes[opidx].name,mem); + }while((machine->regPC - PROG_START) < machine->codeLen); /*XXX - may need to change since defaultCodePC */ + free(mem); + machine->regPC = opc; +} +#endif + + +#ifdef READ_FILES +void m6502_eval_file(machine_6502 *machine, const char *filename, m6502_Plotter plot, void *plotterState){ + char *code = NULL; + + machine->plot = plot; + machine->plotterState = plotterState; + + code = fileToBuffer(filename); + + if (! compileCode(machine, code) ) abort(); + + free(code); + + machine->defaultCodePC = machine->regPC = PROG_START; + machine->codeRunning = TRUE; + do{ + sleep(0); /* XXX */ +#if 0 + m6502_trace(machine, stdout); +#endif + execute(machine); + }while(machine->codeRunning); +} + +void m6502_start_eval_file(machine_6502 *machine, const char *filename, m6502_Plotter plot, void *plotterState){ + char *code = NULL; + reset(machine); + + machine->plot = plot; + machine->plotterState = plotterState; + + code = fileToBuffer(filename); + + if (! compileCode(machine, code) ) abort(); + + free(code); + + machine->defaultCodePC = machine->regPC = PROG_START; + machine->codeRunning = TRUE; + execute(machine); +} +#endif /* READ_FILES */ + +void m6502_start_eval_string(machine_6502 *machine, const char *code, + m6502_Plotter plot, void *plotterState){ + reset(machine); + + machine->plot = plot; + machine->plotterState = plotterState; + + if (! compileCode(machine, code) ){ + fprintf(stderr,"Could not compile code.\n"); + } + + machine->defaultCodePC = machine->regPC = PROG_START; + machine->codeRunning = TRUE; + execute(machine); +} + +/* void start_eval_binary(machine_6502 *machine, Bit8 *program, */ +/* unsigned int proglen, */ +/* Plotter plot, void *plotterState){ */ +/* unsigned int pc, n; */ +/* reset(machine); */ +/* machine->plot = plot; */ +/* machine->plotterState = plotterState; */ + +/* machine->regPC = PROG_START; */ +/* pc = machine->regPC; */ +/* machine->codeLen = proglen; */ +/* n = 0; */ +/* while (n < proglen){ */ +/* machine->memory[pc++] = program[n++]; */ +/* } */ +/* machine->codeRunning = TRUE; */ +/* execute(machine); */ +/* } */ + +void m6502_next_eval(machine_6502 *machine, int insno){ + int i = 0; + for (i = 1; i < insno; i++){ + if (machine->codeRunning){ +#if 0 + trace(machine, stdout); +#endif + execute(machine); + } + else + break; + } +} + |