/*-*- 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;
}
}