summaryrefslogtreecommitdiffstats
path: root/hacks/asm6502.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/asm6502.c')
-rw-r--r--hacks/asm6502.c2275
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;
+ }
+}
+