X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fasm6502.c;h=af0a9341b7b94e312032dde29217260414743e89;hb=50be9bb40dc60130c99ffa568e6677779904ff70;hp=aeda48267efaf7b95d0ba5f5fe92d726926cc0e4;hpb=c8c6deae79b408cffbc88043c766b3bc12cf0f13;p=xscreensaver diff --git a/hacks/asm6502.c b/hacks/asm6502.c index aeda4826..af0a9341 100644 --- a/hacks/asm6502.c +++ b/hacks/asm6502.c @@ -1,3 +1,4 @@ +/*-*- indent-tabs-mode:nil -*- */ /* Copyright (C) 2007 Jeremy English * * Permission to use, copy, modify, distribute, and sell this software and its @@ -35,6 +36,10 @@ #include "asm6502.h" +#ifdef DEBUGGER +# define random rand +#endif + typedef enum{ LEFT, RIGHT } Side; @@ -89,45 +94,16 @@ typedef struct { Bit16 value; } Pointer; -/* eprintf - Taken from "Practice of Programming" by Kernighan and Pike */ -static void eprintf(char *fmt, ...){ - va_list args; - - char *progname = "Assembler"; - - fflush(stdout); - if (progname != NULL) - fprintf(stderr, "%s: ", progname); - - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - - if (fmt[0] != '\0' && fmt[strlen(fmt) -1] == ':') - fprintf(stderr, " %s", strerror(errno)); - fprintf(stderr, "\n"); - exit(2); /* conventional value for failed execution */ -} -/* emalloc - Taken from "Practice of Programming" by Kernighan and - Pike. If memory allocatiion fails the program will print a message - an exit. */ static void *emalloc(size_t n) { - void *p; - - p = malloc(n); - if (p == NULL) - eprintf("malloc of %u bytes failed:", n); + void *p = malloc(n); + if (! p) abort(); return p; } -/* ecalloc - Dose the same thing as emalloc just calls calloc instead. */ static void *ecalloc(uint32_t nelm, size_t nsize){ - void *p; - - p = calloc(nelm, nsize); - if (p == NULL) - eprintf("calloc of %u bytes failed:", nelm * nsize); + void *p = calloc(nelm, nsize); + if (!p) abort(); return p; } @@ -179,10 +155,11 @@ static Bit8 stackPop(machine_6502 *machine) { } static void pushByte(machine_6502 *machine, Bit32 value ) { - Bit32 address = 0x600 + machine->codeLen; + Bit32 address = machine->defaultCodePC; checkAddress(address); - machine->memory[0x600 + machine->codeLen] = value & 0xff; + machine->memory[address] = value & 0xff; machine->codeLen++; + machine->defaultCodePC++; } /* @@ -295,9 +272,9 @@ static BOOL peekValue(machine_6502 *machine, AddrMode adm, Pointer *pointer, Bit pointer->value = memReadByte(machine, PC); return TRUE; case INDIRECT_X: - zp = memReadByte(machine, PC); + zp = memReadByte(machine, PC) + machine->regX; pointer->addr = memReadByte(machine,zp) + - (memReadByte(machine,zp+1)<<8) + machine->regX; + (memReadByte(machine,zp+1)<<8); pointer->value = memReadByte(machine, pointer->addr); return TRUE; case INDIRECT_Y: @@ -360,9 +337,9 @@ static BOOL getValue(machine_6502 *machine, AddrMode adm, Pointer *pointer){ pointer->value = popByte(machine); return TRUE; case INDIRECT_X: - zp = popByte(machine); + zp = popByte(machine) + machine->regX; pointer->addr = memReadByte(machine,zp) + - (memReadByte(machine,zp+1)<<8) + machine->regX; + (memReadByte(machine,zp+1)<<8); pointer->value = memReadByte(machine, pointer->addr); return TRUE; case INDIRECT_Y: @@ -408,6 +385,64 @@ static BOOL getValue(machine_6502 *machine, AddrMode adm, Pointer *pointer){ } +static void dismem(machine_6502 *machine, 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; + } +} + /* manZeroNeg - Manage the negative and zero flags */ static void manZeroNeg(machine_6502 *machine, Bit8 value){ machine->regP = setBit(machine->regP, ZERO_FL, (value == 0)); @@ -855,19 +890,19 @@ static void jmpRTS(machine_6502 *machine, AddrMode adm){ static void jmpSBC(machine_6502 *machine, AddrMode adm){ Pointer ptr; - Bit8 vflag; + /*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)); + /*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(machine->regA, LEFT); + Bit8 bl = nibble(ptr.value, LEFT); tmp = 0xf + ar - br + c; if ( tmp < 0x10){ @@ -963,7 +998,7 @@ static void jmpSTY(machine_6502 *machine, AddrMode adm){ static void assignOpCodes(Opcodes *opcodes){ #define SETOP(num, _name, _Imm, _ZP, _ZPX, _ZPY, _ABS, _ABSX, _ABSY, _INDX, _INDY, _SNGL, _BRA, _func) \ -{opcodes[num].name[4] = '\0'; \ +{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; \ @@ -1260,15 +1295,24 @@ static BOOL ishexdigit(char c){ } } +/* 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(;isalpha(**s) && i < MAX_CMD_LEN; (*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); } @@ -1619,7 +1663,7 @@ static AsmLine *parseAssembly(machine_6502 *machine, BOOL *codeOk, const char *c } /* fileToBuffer() - Allocates a buffer and loads all of the file into memory. */ -static char *fileToBuffer(char *filename){ +static char *fileToBuffer(const char *filename){ const int defaultSize = 1024; FILE *ifp; int c; @@ -1627,12 +1671,10 @@ static char *fileToBuffer(char *filename){ int i = 0; char *buffer = ecalloc(defaultSize,sizeof(char)); - if (buffer == NULL) - eprintf("Could not allocate memory for buffer."); + if (!buffer) abort(); ifp = fopen(filename, "rb"); - if (ifp == NULL) - eprintf("Could not open file."); + if (!ifp) return 0; while((c = getc(ifp)) != EOF){ buffer[i++] = c; @@ -1640,15 +1682,13 @@ static char *fileToBuffer(char *filename){ size += defaultSize; buffer = realloc(buffer, size); if (buffer == NULL) { - fclose(ifp); - eprintf("Could not resize buffer."); + abort(); } } } fclose(ifp); buffer = realloc(buffer, i+2); - if (buffer == NULL) - eprintf("Could not resize buffer."); + if (!buffer) abort(); /* Make sure we have a line feed at the end */ buffer[i] = '\n'; buffer[i+1] = '\0'; @@ -1675,7 +1715,7 @@ static void reset(machine_6502 *machine){ machine->regX = 0; machine->regY = 0; machine->regP = setBit(machine->regP, FUTURE_FL, 1); - machine->regPC = 0x600; + machine->defaultCodePC = machine->regPC = PROG_START; machine->regSP = STACK_TOP; machine->runForever = FALSE; machine->labelPtr = 0; @@ -1696,24 +1736,24 @@ void hexDump(machine_6502 *machine, Bit16 start, Bit16 numbytes, FILE *output){ fprintf(output,"%s\n",(i&1)?"--":""); } -void save_program(machine_6502 *machine, char *filename){ - FILE *ofp; - Bit16 pc = 0x600; - Bit16 end = pc + machine->codeLen; - Bit16 n; - ofp = fopen(filename, "w"); - if (ofp == NULL) - eprintf("Could not open file."); +/* 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"); +/* 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); -} +/* fclose(ofp); */ +/* } */ static BOOL translate(Opcodes *op,Param *param, machine_6502 *machine){ switch(param->type){ @@ -1738,7 +1778,7 @@ static BOOL translate(Opcodes *op,Param *param, machine_6502 *machine){ case IMMEDIATE_GREAT: if (op->Imm) { pushByte(machine, op->Imm); - pushByte(machine, param->lbladdr / 0xFF); + pushByte(machine, param->lbladdr >> 8); break; } else { @@ -1823,12 +1863,11 @@ static BOOL translate(Opcodes *op,Param *param, machine_6502 *machine){ else { if (op->BRA) { pushByte(machine, op->BRA); - if (param->lbladdr < (machine->codeLen + 0x600)) - pushByte(machine, - (0xff - (machine->codeLen-param->lbladdr)) & 0xff); - else - pushByte(machine, - (param->lbladdr - machine->codeLen-1) & 0xff); + { + int diff = abs(param->lbladdr - 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); @@ -1889,8 +1928,10 @@ static BOOL compileLine(AsmLine *asmline, void *args){ machine_6502 *machine; machine = args; if (isBlank(asmline->command)) return TRUE; - - if (strcmp("DCB",asmline->command) == 0){ + 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]); @@ -1917,14 +1958,28 @@ static BOOL compileLine(AsmLine *asmline, void *args){ 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; } - machine->regPC += machine->codeLen; + + /* 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; } @@ -1955,7 +2010,7 @@ static BOOL compileCode(machine_6502 *machine, const char *code){ AsmLine *asmlist; reset(machine); - machine->regPC = 0x600; + machine->defaultCodePC = machine->regPC = PROG_START; asmlist = parseAssembly(machine, &codeOk, code); if(codeOk){ @@ -1964,13 +2019,31 @@ static BOOL compileCode(machine_6502 *machine, const char *code){ 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: %d ParamLbl: %s ParamAddr: %d\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->codeLen > 0 ){ - machine->memory[0x600+machine->codeLen] = 0x00; + if (machine->defaultCodePC > PROG_START ){ + machine->memory[machine->defaultCodePC] = 0x00; codeOk = TRUE; } else{ @@ -2011,8 +2084,7 @@ static void execute(machine_6502 *machine){ fprintf(stderr,"Invalid opcode!\n"); } if( (machine->regPC == 0) || - (!machine->codeRunning) || - (machine->regPC > (machine->codeLen+0x600)) ) { + (!machine->codeRunning) ) { machine->codeRunning = FALSE; } } @@ -2060,13 +2132,37 @@ void trace(machine_6502 *machine, FILE *output){ } fprintf(output,"STACK:"); hexDump(machine,(STACK_TOP - stacksz) + 1, stacksz, output); - fprintf(output,"\n================================================================================\n"); } - +void disassemble(machine_6502 *machine, FILE *output){ + /* Read the opcode + increment the program counter + print the opcode + loop until end of program. */ + 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; +} -void eval_file(machine_6502 *machine, char *filename, Plotter plot, void *plotterState){ +void eval_file(machine_6502 *machine, const char *filename, Plotter plot, void *plotterState){ char *code = NULL; machine->plot = plot; @@ -2074,13 +2170,11 @@ void eval_file(machine_6502 *machine, char *filename, Plotter plot, void *plotte code = fileToBuffer(filename); - if (! compileCode(machine, code) ){ - eprintf("Could not compile code.\n"); - } + if (! compileCode(machine, code) ) abort(); free(code); - machine->regPC = 0x600; + machine->defaultCodePC = machine->regPC = PROG_START; machine->codeRunning = TRUE; do{ sleep(0); /* XXX */ @@ -2088,12 +2182,10 @@ void eval_file(machine_6502 *machine, char *filename, Plotter plot, void *plotte trace(machine); #endif execute(machine); - if (!machine->codeRunning) - break; - }while((machine->regPC - 0x600) < machine->codeLen); + }while(machine->codeRunning); } -void start_eval_file(machine_6502 *machine, char *filename, Plotter plot, void *plotterState){ +void start_eval_file(machine_6502 *machine, const char *filename, Plotter plot, void *plotterState){ char *code = NULL; reset(machine); @@ -2102,42 +2194,56 @@ void start_eval_file(machine_6502 *machine, char *filename, Plotter plot, void * code = fileToBuffer(filename); - if (! compileCode(machine, code) ){ - eprintf("Could not compile code.\n"); - } + if (! compileCode(machine, code) ) abort(); free(code); - machine->regPC = 0x600; + machine->defaultCodePC = machine->regPC = PROG_START; machine->codeRunning = TRUE; execute(machine); } -void start_eval_binary(machine_6502 *machine, Bit8 *program, - unsigned int proglen, +void start_eval_string(machine_6502 *machine, const char *code, Plotter plot, void *plotterState){ - unsigned int pc, n; reset(machine); + machine->plot = plot; machine->plotterState = plotterState; - machine->regPC = 0x600; - pc = machine->regPC; - machine->codeLen = proglen; - n = 0; - while (n < proglen){ - machine->memory[pc++] = program[n++]; + 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 next_eval(machine_6502 *machine, int insno){ int i = 0; for (i = 1; i < insno; i++){ - if (machine->codeRunning){/* && ((machine->regPC - 0x600) < machine->codeLen))*/ + if (machine->codeRunning){ #if 0 - trace(machine); + trace(machine, stdout); #endif execute(machine); }