1 /* Copyright (C) 2007 Jeremy English <jhe@jeremyenglish.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * Created: 12-April-2007
15 This is a port of the javascript 6502 assembler, compiler and
16 debugger. The orignal code was copyright 2006 by Stian Soreng -
19 I changed the structure of the assembler in this version.
22 #define NDEBUG /* Uncomment when done with debugging */
26 /*#include <malloc.h>*/
46 |N||V||F||B||D||I||Z||C|
53 CARRY_FL = 0, ZERO_FL = 1, INTERRUPT_FL = 2,
54 DECIMAL_FL = 3, BREAK_FL = 4, FUTURE_FL = 5,
55 OVERFLOW_FL = 6, NEGATIVE_FL = 7
59 typedef BOOL (*CharTest) (char);
61 /* A jump function takes a pointer to the current machine and a
62 opcode. The opcode is needed to figure out the memory mode. */
63 /*typedef void (*JumpFunc) (machine_6502* AddrMode);*/
67 Bit32 value[MAX_PARAM_VALUE];
68 unsigned int vp; /*value pointer, index into the value table.*/
74 Bit32 addr; /* Address of the label */
78 typedef struct AsmLine AsmLine;
80 BOOL labelDecl; /* Does the line have a label declaration? */
84 AsmLine *next; /* in list */
92 /* eprintf - Taken from "Practice of Programming" by Kernighan and Pike */
93 static void eprintf(char *fmt, ...){
96 char *progname = "Assembler";
100 fprintf(stderr, "%s: ", progname);
103 vfprintf(stderr, fmt, args);
106 if (fmt[0] != '\0' && fmt[strlen(fmt) -1] == ':')
107 fprintf(stderr, " %s", strerror(errno));
108 fprintf(stderr, "\n");
109 exit(2); /* conventional value for failed execution */
112 /* emalloc - Taken from "Practice of Programming" by Kernighan and
113 Pike. If memory allocatiion fails the program will print a message
115 static void *emalloc(size_t n) {
120 eprintf("malloc of %u bytes failed:", n);
124 /* ecalloc - Dose the same thing as emalloc just calls calloc instead. */
125 static void *ecalloc(uint32_t nelm, size_t nsize){
128 p = calloc(nelm, nsize);
130 eprintf("calloc of %u bytes failed:", nelm * nsize);
134 /* estrdup() - Allocates memory for a new string a returns a copy of the source sting in it. */
135 static char *estrdup(const char *source){
136 int ln = strlen(source) + 1;
137 char *s = ecalloc(ln, sizeof(char));
138 strncpy(s,source,ln);
142 static void checkAddress(Bit32 address){
143 /* XXX: Do we want to kill the program here? */
144 if (address >= MEM_64K)
145 fprintf(stderr, "Address %d is beyond 64k", address);
149 * stackPush() - Push byte to stack
153 static void stackPush(machine_6502 *machine, Bit8 value ) {
154 if(machine->regSP >= STACK_BOTTOM){
155 machine->memory[machine->regSP--] = value;
158 fprintf(stderr, "The stack is full: %.4x\n", machine->regSP);
159 machine->codeRunning = FALSE;
165 * stackPop() - Pop byte from stack
169 static Bit8 stackPop(machine_6502 *machine) {
170 if (machine->regSP < STACK_TOP){
171 Bit8 value =machine->memory[++machine->regSP];
175 /* fprintf(stderr, "The stack is empty.\n"); xxx */
176 machine->codeRunning = FALSE;
181 static void pushByte(machine_6502 *machine, Bit32 value ) {
182 Bit32 address = 0x600 + machine->codeLen;
183 checkAddress(address);
184 machine->memory[0x600 + machine->codeLen] = value & 0xff;
189 * pushWord() - Push a word using pushByte twice
193 static void pushWord(machine_6502 *machine, Bit16 value ) {
194 pushByte(machine, value & 0xff );
195 pushByte(machine, (value>>8) & 0xff );
199 * popByte( machine_6502 *machine,) - Pops a byte
203 static Bit8 popByte( machine_6502 *machine) {
204 Bit8 value = machine->memory[machine->regPC];
210 * popWord() - Pops a word using popByte() twice
214 static int popWord(machine_6502 *machine) {
215 return popByte(machine) + (popByte(machine) << 8);
220 * memReadByte() - Peek a byte, don't touch any registers
224 static int memReadByte( machine_6502 *machine, int addr ) {
225 if( addr == 0xfe ) return floor( random()%255 );
226 return machine->memory[addr];
229 static void updateDisplayPixel(machine_6502 *machine, Bit16 addr){
230 Bit8 idx = memReadByte(machine,addr) & 0x0f;
236 machine->plot(x,y,idx,machine->plotterState);
241 * memStoreByte() - Poke a byte, don't touch any registers
245 static void memStoreByte( machine_6502 *machine, int addr, int value ) {
246 machine->memory[ addr ] = (value & 0xff);
247 if( (addr >= 0x200) && (addr<=0x5ff) )
248 updateDisplayPixel(machine, addr );
255 static Bit8 bitOn(Bit8 value,Flags bit){
258 return ((value & mask) > 0);
261 static Bit8 bitOff(Bit8 value, Flags bit){
262 return (! bitOn(value,bit));
265 static Bit8 setBit(Bit8 value, Flags bit, int on){
268 onMask = onMask << bit;
269 offMask = offMask ^ onMask;
270 return ((on) ? value | onMask : value & offMask);
273 static Bit8 nibble(Bit8 value, Side side){
275 case LEFT: return value & 0xf0;
276 case RIGHT: return value & 0xf;
278 fprintf(stderr,"nibble unknown side\n");
284 /* used for tracing. XXX: combined with function getvalue */
285 static BOOL peekValue(machine_6502 *machine, AddrMode adm, Pointer *pointer, Bit16 PC){
293 case IMMEDIATE_GREAT:
294 case IMMEDIATE_VALUE:
295 pointer->value = memReadByte(machine, PC);
298 zp = memReadByte(machine, PC);
299 pointer->addr = memReadByte(machine,zp) +
300 (memReadByte(machine,zp+1)<<8) + machine->regX;
301 pointer->value = memReadByte(machine, pointer->addr);
304 zp = memReadByte(machine, PC);
305 pointer->addr = memReadByte(machine,zp) +
306 (memReadByte(machine,zp+1)<<8) + machine->regY;
307 pointer->value = memReadByte(machine, pointer->addr);
310 pointer->addr = memReadByte(machine, PC);
311 pointer->value = memReadByte(machine, pointer->addr);
314 pointer->addr = memReadByte(machine, PC) + machine->regX;
315 pointer->value = memReadByte(machine, pointer->addr);
318 pointer->addr = memReadByte(machine, PC) + machine->regY;
319 pointer->value = memReadByte(machine, pointer->addr);
322 pointer->addr = memReadByte(machine, PC);
325 pointer->addr = memReadByte(machine, PC) + (memReadByte(machine, PC+1) << 8);
326 pointer->value = memReadByte(machine, pointer->addr);
330 pointer->addr = (memReadByte(machine, PC) +
331 (memReadByte(machine, PC+1) << 8)) + machine->regX;
332 pointer->value = memReadByte(machine, pointer->addr);
336 pointer->addr = (memReadByte(machine, PC) +
337 (memReadByte(machine, PC+1) << 8)) + machine->regY;
338 pointer->value = memReadByte(machine, pointer->addr);
341 /* Handled elsewhere */
349 /* Figure out how to get the value from the addrmode and get it.*/
350 static BOOL getValue(machine_6502 *machine, AddrMode adm, Pointer *pointer){
358 case IMMEDIATE_GREAT:
359 case IMMEDIATE_VALUE:
360 pointer->value = popByte(machine);
363 zp = popByte(machine);
364 pointer->addr = memReadByte(machine,zp) +
365 (memReadByte(machine,zp+1)<<8) + machine->regX;
366 pointer->value = memReadByte(machine, pointer->addr);
369 zp = popByte(machine);
370 pointer->addr = memReadByte(machine,zp) +
371 (memReadByte(machine,zp+1)<<8) + machine->regY;
372 pointer->value = memReadByte(machine, pointer->addr);
375 pointer->addr = popByte(machine);
376 pointer->value = memReadByte(machine, pointer->addr);
379 pointer->addr = popByte(machine) + machine->regX;
380 pointer->value = memReadByte(machine, pointer->addr);
383 pointer->addr = popByte(machine) + machine->regY;
384 pointer->value = memReadByte(machine, pointer->addr);
387 pointer->addr = popByte(machine);
390 pointer->addr = popWord(machine);
391 pointer->value = memReadByte(machine, pointer->addr);
395 pointer->addr = popWord(machine) + machine->regX;
396 pointer->value = memReadByte(machine, pointer->addr);
400 pointer->addr = popWord(machine) + machine->regY;
401 pointer->value = memReadByte(machine, pointer->addr);
404 /* Handled elsewhere */
411 /* manZeroNeg - Manage the negative and zero flags */
412 static void manZeroNeg(machine_6502 *machine, Bit8 value){
413 machine->regP = setBit(machine->regP, ZERO_FL, (value == 0));
414 machine->regP = setBit(machine->regP, NEGATIVE_FL, bitOn(value,NEGATIVE_FL));
417 static void warnValue(BOOL isValue){
419 fprintf(stderr,"Invalid Value from getValue.\n");
423 static void jmpADC(machine_6502 *machine, AddrMode adm){
426 Bit8 c = bitOn(machine->regP, CARRY_FL);
427 BOOL isValue = getValue(machine, adm, &ptr);
431 if (bitOn(machine->regA, NEGATIVE_FL) &&
432 bitOn(ptr.value, NEGATIVE_FL))
433 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
435 machine->regP = setBit(machine->regP, OVERFLOW_FL, 1);
437 if (bitOn(machine->regP, DECIMAL_FL)) {
438 tmp = nibble(machine->regA,RIGHT) + nibble(ptr.value,RIGHT ) + c;
439 /* The decimal part is limited to 0 through 9 */
441 tmp = 0x10 | ((tmp + 6) & 0xf);
443 tmp += nibble(machine->regA,LEFT) + nibble(ptr.value,LEFT);
445 machine->regP = setBit(machine->regP,CARRY_FL,1);
446 if (bitOn(machine->regP, OVERFLOW_FL) && tmp >= 0x180)
447 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
451 machine->regP = setBit(machine->regP,CARRY_FL,0);
452 if (bitOn(machine->regP, OVERFLOW_FL) && tmp < 0x80)
453 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
457 tmp = machine->regA + ptr.value + c;
459 machine->regP = setBit(machine->regP,CARRY_FL,1);
460 if (bitOn(machine->regP, OVERFLOW_FL) && tmp >= 0x180)
461 machine->regP =setBit(machine->regP, OVERFLOW_FL, 0);
464 machine->regP = setBit(machine->regP,CARRY_FL,0);
465 if (bitOn(machine->regP, OVERFLOW_FL) && tmp < 0x80)
466 machine->regP =setBit(machine->regP, OVERFLOW_FL, 0);
471 manZeroNeg(machine,machine->regA);
474 static void jmpAND(machine_6502 *machine, AddrMode adm){
476 BOOL isValue = getValue(machine, adm, &ptr);
478 machine->regA &= ptr.value;
479 manZeroNeg(machine,machine->regA);
482 static void jmpASL(machine_6502 *machine, AddrMode adm){
484 BOOL isValue = getValue(machine, adm, &ptr);
486 machine->regP = setBit(machine->regP, CARRY_FL, bitOn(ptr.value, NEGATIVE_FL));
487 ptr.value = ptr.value << 1;
488 ptr.value = setBit(ptr.value, CARRY_FL, 0);
489 memStoreByte(machine, ptr.addr, ptr.value);
490 manZeroNeg(machine,ptr.value);
492 else { /* Accumulator */
493 machine->regP = setBit(machine->regP, CARRY_FL, bitOn(machine->regA, NEGATIVE_FL));
494 machine->regA = machine->regA << 1;
495 machine->regA = setBit(machine->regA, CARRY_FL, 0);
496 manZeroNeg(machine,machine->regA);
501 static void jmpBIT(machine_6502 *machine, AddrMode adm){
503 BOOL isValue = getValue(machine, adm, &ptr);
505 machine->regP = setBit(machine->regP, ZERO_FL, (ptr.value & machine->regA));
506 machine->regP = setBit(machine->regP, OVERFLOW_FL, bitOn(ptr.value, OVERFLOW_FL));
507 machine->regP = setBit(machine->regP, NEGATIVE_FL, bitOn(ptr.value, NEGATIVE_FL));
511 static void jumpBranch(machine_6502 *machine, Bit16 offset){
513 machine->regPC = machine->regPC - (0x100 - offset);
515 machine->regPC = machine->regPC + offset;
518 static void jmpBPL(machine_6502 *machine, AddrMode adm){
520 BOOL isValue = getValue(machine, adm, &ptr);
522 if (bitOff(machine->regP,NEGATIVE_FL))
523 jumpBranch(machine, ptr.addr);
527 static void jmpBMI(machine_6502 *machine, AddrMode adm){
529 BOOL isValue = getValue(machine, adm, &ptr);
531 if (bitOn(machine->regP,NEGATIVE_FL))
532 jumpBranch(machine, ptr.addr);
536 static void jmpBVC(machine_6502 *machine, AddrMode adm){
538 BOOL isValue = getValue(machine, adm, &ptr);
540 if (bitOff(machine->regP,OVERFLOW_FL))
541 jumpBranch(machine, ptr.addr);
544 static void jmpBVS(machine_6502 *machine, AddrMode adm){
546 BOOL isValue = getValue(machine, adm, &ptr);
548 if (bitOn(machine->regP,OVERFLOW_FL))
549 jumpBranch(machine, ptr.addr);
552 static void jmpBCC(machine_6502 *machine, AddrMode adm){
554 BOOL isValue = getValue(machine, adm, &ptr);
556 if (bitOff(machine->regP,CARRY_FL))
557 jumpBranch(machine, ptr.addr);
560 static void jmpBCS(machine_6502 *machine, AddrMode adm){
562 BOOL isValue = getValue(machine, adm, &ptr);
564 if (bitOn(machine->regP,CARRY_FL))
565 jumpBranch(machine, ptr.addr);
568 static void jmpBNE(machine_6502 *machine, AddrMode adm){
570 BOOL isValue = getValue(machine, adm, &ptr);
572 if (bitOff(machine->regP, ZERO_FL))
573 jumpBranch(machine, ptr.addr);
576 static void jmpBEQ(machine_6502 *machine, AddrMode adm){
578 BOOL isValue = getValue(machine, adm, &ptr);
580 if (bitOn(machine->regP, ZERO_FL))
581 jumpBranch(machine, ptr.addr);
584 static void doCompare(machine_6502 *machine, Bit16 reg, Pointer *ptr){
585 machine->regP = setBit(machine->regP,CARRY_FL, ((reg + ptr->value) > 0xff));
586 manZeroNeg(machine,(reg - ptr->value));
589 static void jmpCMP(machine_6502 *machine, AddrMode adm){
591 BOOL isValue = getValue(machine, adm, &ptr);
593 doCompare(machine,machine->regA,&ptr);
596 static void jmpCPX(machine_6502 *machine, AddrMode adm){
598 BOOL isValue = getValue(machine, adm, &ptr);
600 doCompare(machine,machine->regX,&ptr);
603 static void jmpCPY(machine_6502 *machine, AddrMode adm){
605 BOOL isValue = getValue(machine, adm, &ptr);
607 doCompare(machine,machine->regY,&ptr);
610 static void jmpDEC(machine_6502 *machine, AddrMode adm){
612 BOOL isValue = getValue(machine, adm, &ptr);
618 memStoreByte(machine, ptr.addr, ptr.value);
619 manZeroNeg(machine,ptr.value);
622 static void jmpEOR(machine_6502 *machine, AddrMode adm){
624 BOOL isValue = getValue(machine, adm, &ptr);
626 machine->regA ^= ptr.value;
627 manZeroNeg(machine, machine->regA);
630 static void jmpCLC(machine_6502 *machine, AddrMode adm){
631 machine->regP = setBit(machine->regP, CARRY_FL, 0);
634 static void jmpSEC(machine_6502 *machine, AddrMode adm){
635 machine->regP = setBit(machine->regP, CARRY_FL, 1);
638 static void jmpCLI(machine_6502 *machine, AddrMode adm){
639 machine->regP = setBit(machine->regP, INTERRUPT_FL, 0);
642 static void jmpSEI(machine_6502 *machine, AddrMode adm){
643 machine->regP = setBit(machine->regP, INTERRUPT_FL, 1);
646 static void jmpCLV(machine_6502 *machine, AddrMode adm){
647 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
650 static void jmpCLD(machine_6502 *machine, AddrMode adm){
651 machine->regP = setBit(machine->regP, DECIMAL_FL, 0);
654 static void jmpSED(machine_6502 *machine, AddrMode adm){
655 machine->regP = setBit(machine->regP, DECIMAL_FL, 1);
658 static void jmpINC(machine_6502 *machine, AddrMode adm){
660 BOOL isValue = getValue(machine, adm, &ptr);
662 ptr.value = (ptr.value + 1) & 0xFF;
663 memStoreByte(machine, ptr.addr, ptr.value);
664 manZeroNeg(machine,ptr.value);
667 static void jmpJMP(machine_6502 *machine, AddrMode adm){
669 BOOL isValue = getValue(machine, adm, &ptr);
671 machine->regPC = ptr.addr;
674 static void jmpJSR(machine_6502 *machine, AddrMode adm){
676 /* Move past the 2 byte parameter. JSR is always followed by
678 Bit16 currAddr = machine->regPC + 2;
679 BOOL isValue = getValue(machine, adm, &ptr);
681 stackPush(machine, (currAddr >> 8) & 0xff);
682 stackPush(machine, currAddr & 0xff);
683 machine->regPC = ptr.addr;
686 static void jmpLDA(machine_6502 *machine, AddrMode adm){
688 BOOL isValue = getValue(machine, adm, &ptr);
690 machine->regA = ptr.value;
691 manZeroNeg(machine, machine->regA);
694 static void jmpLDX(machine_6502 *machine, AddrMode adm){
696 BOOL isValue = getValue(machine, adm, &ptr);
698 machine->regX = ptr.value;
699 manZeroNeg(machine, machine->regX);
702 static void jmpLDY(machine_6502 *machine, AddrMode adm){
704 BOOL isValue = getValue(machine, adm, &ptr);
706 machine->regY = ptr.value;
707 manZeroNeg(machine, machine->regY);
710 static void jmpLSR(machine_6502 *machine, AddrMode adm){
712 BOOL isValue = getValue(machine, adm, &ptr);
715 setBit(machine->regP, CARRY_FL,
716 bitOn(ptr.value, CARRY_FL));
717 ptr.value = ptr.value >> 1;
718 ptr.value = setBit(ptr.value,NEGATIVE_FL,0);
719 memStoreByte(machine,ptr.addr,ptr.value);
720 manZeroNeg(machine,ptr.value);
722 else { /* Accumulator */
724 setBit(machine->regP, CARRY_FL,
725 bitOn(machine->regA, CARRY_FL));
726 machine->regA = machine->regA >> 1;
727 machine->regA = setBit(machine->regA,NEGATIVE_FL,0);
728 manZeroNeg(machine,ptr.value);
732 static void jmpNOP(machine_6502 *machine, AddrMode adm){
736 static void jmpORA(machine_6502 *machine, AddrMode adm){
738 BOOL isValue = getValue(machine, adm, &ptr);
740 machine->regA |= ptr.value;
741 manZeroNeg(machine,machine->regA);
744 static void jmpTAX(machine_6502 *machine, AddrMode adm){
745 machine->regX = machine->regA;
746 manZeroNeg(machine,machine->regX);
749 static void jmpTXA(machine_6502 *machine, AddrMode adm){
750 machine->regA = machine->regX;
751 manZeroNeg(machine,machine->regA);
754 static void jmpDEX(machine_6502 *machine, AddrMode adm){
755 if (machine->regX > 0)
758 machine->regX = 0xFF;
759 manZeroNeg(machine, machine->regX);
762 static void jmpINX(machine_6502 *machine, AddrMode adm){
763 Bit16 value = machine->regX + 1;
764 machine->regX = value & 0xFF;
765 manZeroNeg(machine, machine->regX);
768 static void jmpTAY(machine_6502 *machine, AddrMode adm){
769 machine->regY = machine->regA;
770 manZeroNeg(machine, machine->regY);
773 static void jmpTYA(machine_6502 *machine, AddrMode adm){
774 machine->regA = machine->regY;
775 manZeroNeg(machine, machine->regA);
778 static void jmpDEY(machine_6502 *machine, AddrMode adm){
779 if (machine->regY > 0)
782 machine->regY = 0xFF;
783 manZeroNeg(machine, machine->regY);
786 static void jmpINY(machine_6502 *machine, AddrMode adm){
787 Bit16 value = machine->regY + 1;
788 machine->regY = value & 0xff;
789 manZeroNeg(machine, machine->regY);
792 static void jmpROR(machine_6502 *machine, AddrMode adm){
795 BOOL isValue = getValue(machine, adm, &ptr);
797 cf = bitOn(machine->regP, CARRY_FL);
799 setBit(machine->regP, CARRY_FL,
800 bitOn(ptr.value, CARRY_FL));
801 ptr.value = ptr.value >> 1;
802 ptr.value = setBit(ptr.value, NEGATIVE_FL, cf);
803 memStoreByte(machine, ptr.addr, ptr.value);
804 manZeroNeg(machine, ptr.value);
807 cf = bitOn(machine->regP, CARRY_FL);
809 setBit(machine->regP, CARRY_FL,
810 bitOn(machine->regA, CARRY_FL));
811 machine->regA = machine->regA >> 1;
812 machine->regA = setBit(machine->regA, NEGATIVE_FL, cf);
813 manZeroNeg(machine, machine->regA);
817 static void jmpROL(machine_6502 *machine, AddrMode adm){
820 BOOL isValue = getValue(machine, adm, &ptr);
822 cf = bitOn(machine->regP, CARRY_FL);
824 setBit(machine->regP, CARRY_FL,
825 bitOn(ptr.value, NEGATIVE_FL));
826 ptr.value = ptr.value << 1;
827 ptr.value = setBit(ptr.value, CARRY_FL, cf);
828 memStoreByte(machine, ptr.addr, ptr.value);
829 manZeroNeg(machine, ptr.value);
832 cf = bitOn(machine->regP, CARRY_FL);
834 setBit(machine->regP, CARRY_FL,
835 bitOn(machine->regA,NEGATIVE_FL));
836 machine->regA = machine->regA << 1;
837 machine->regA = setBit(machine->regA, CARRY_FL, cf);
838 manZeroNeg(machine, machine->regA);
842 static void jmpRTI(machine_6502 *machine, AddrMode adm){
843 machine->regP = stackPop(machine);
844 machine->regPC = stackPop(machine);
847 static void jmpRTS(machine_6502 *machine, AddrMode adm){
849 BOOL isValue = getValue(machine, adm, &ptr);
850 Bit16 nr = stackPop(machine);
851 Bit16 nl = stackPop(machine);
852 warnValue(! isValue);
853 machine->regPC = (nl << 8) | nr;
856 static void jmpSBC(machine_6502 *machine, AddrMode adm){
859 Bit8 c = bitOn(machine->regP, CARRY_FL);
861 BOOL isValue = getValue(machine, adm, &ptr);
863 vflag = (bitOn(machine->regA,NEGATIVE_FL) &&
864 bitOn(ptr.value, NEGATIVE_FL));
866 if (bitOn(machine->regP, DECIMAL_FL)) {
867 Bit8 ar = nibble(machine->regA, RIGHT);
868 Bit8 br = nibble(ptr.value, RIGHT);
869 Bit8 al = nibble(machine->regA, LEFT);
870 Bit8 bl = nibble(machine->regA, LEFT);
872 tmp = 0xf + ar - br + c;
883 machine->regP = setBit(machine->regP, CARRY_FL, 0);
884 if (bitOn(machine->regP, OVERFLOW_FL) && w < 0x80)
885 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
889 machine->regP = setBit(machine->regP, CARRY_FL, 1);
890 if (bitOn(machine->regP, OVERFLOW_FL) && w >= 0x180)
891 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
894 } /* end decimal mode */
896 w = 0xff + machine->regA - ptr.value + c;
898 machine->regP = setBit(machine->regP, CARRY_FL, 0);
899 if (bitOn(machine->regP, OVERFLOW_FL) && w < 0x80)
900 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
903 machine->regP = setBit(machine->regP, CARRY_FL, 1);
904 if (bitOn(machine->regP, OVERFLOW_FL) && w >= 0x180)
905 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
909 manZeroNeg(machine,machine->regA);
912 static void jmpSTA(machine_6502 *machine, AddrMode adm){
914 BOOL isValue = getValue(machine, adm, &ptr);
916 memStoreByte(machine,ptr.addr,machine->regA);
919 static void jmpTXS(machine_6502 *machine, AddrMode adm){
920 stackPush(machine,machine->regX);
923 static void jmpTSX(machine_6502 *machine, AddrMode adm){
924 machine->regX = stackPop(machine);
925 manZeroNeg(machine, machine->regX);
928 static void jmpPHA(machine_6502 *machine, AddrMode adm){
929 stackPush(machine, machine->regA);
932 static void jmpPLA(machine_6502 *machine, AddrMode adm){
933 machine->regA = stackPop(machine);
934 manZeroNeg(machine, machine->regA);
937 static void jmpPHP(machine_6502 *machine, AddrMode adm){
938 stackPush(machine,machine->regP);
941 static void jmpPLP(machine_6502 *machine, AddrMode adm){
942 machine->regP = stackPop(machine);
943 machine->regP = setBit(machine->regP, FUTURE_FL, 1);
946 static void jmpSTX(machine_6502 *machine, AddrMode adm){
948 BOOL isValue = getValue(machine, adm, &ptr);
950 memStoreByte(machine,ptr.addr,machine->regX);
953 static void jmpSTY(machine_6502 *machine, AddrMode adm){
955 BOOL isValue = getValue(machine, adm, &ptr);
957 memStoreByte(machine,ptr.addr,machine->regY);
963 static void assignOpCodes(Opcodes *opcodes){
965 #define SETOP(num, _name, _Imm, _ZP, _ZPX, _ZPY, _ABS, _ABSX, _ABSY, _INDX, _INDY, _SNGL, _BRA, _func) \
966 {opcodes[num].name[4] = '\0'; \
967 strncpy(opcodes[num].name, _name, 3); opcodes[num].Imm = _Imm; opcodes[num].ZP = _ZP; \
968 opcodes[num].ZPX = _ZPX; opcodes[num].ZPY = _ZPY; opcodes[num].ABS = _ABS; \
969 opcodes[num].ABSX = _ABSX; opcodes[num].ABSY = _ABSY; opcodes[num].INDX = _INDX; \
970 opcodes[num].INDY = _INDY; opcodes[num].SNGL = _SNGL; opcodes[num].BRA = _BRA; \
971 opcodes[num].func = _func;}
973 /* OPCODE Imm ZP ZPX ZPY ABS ABSX ABSY INDX INDY SGNL BRA Jump Function*/
974 SETOP( 0, "ADC", 0x69, 0x65, 0x75, 0x00, 0x6d, 0x7d, 0x79, 0x61, 0x71, 0x00, 0x00, jmpADC);
975 SETOP( 1, "AND", 0x29, 0x25, 0x35, 0x31, 0x2d, 0x3d, 0x39, 0x00, 0x00, 0x00, 0x00, jmpAND);
976 SETOP( 2, "ASL", 0x00, 0x06, 0x16, 0x00, 0x0e, 0x1e, 0x00, 0x00, 0x00, 0x0a, 0x00, jmpASL);
977 SETOP( 3, "BIT", 0x00, 0x24, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpBIT);
978 SETOP( 4, "BPL", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, jmpBPL);
979 SETOP( 5, "BMI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, jmpBMI);
980 SETOP( 6, "BVC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, jmpBVC);
981 SETOP( 7, "BVS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, jmpBVS);
982 SETOP( 8, "BCC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, jmpBCC);
983 SETOP( 9, "BCS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, jmpBCS);
984 SETOP(10, "BNE", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, jmpBNE);
985 SETOP(11, "BEQ", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, jmpBEQ);
986 SETOP(12, "CMP", 0xc9, 0xc5, 0xd5, 0x00, 0xcd, 0xdd, 0xd9, 0xc1, 0xd1, 0x00, 0x00, jmpCMP);
987 SETOP(13, "CPX", 0xe0, 0xe4, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpCPX);
988 SETOP(14, "CPY", 0xc0, 0xc4, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpCPY);
989 SETOP(15, "DEC", 0x00, 0xc6, 0xd6, 0x00, 0xce, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, jmpDEC);
990 SETOP(16, "EOR", 0x49, 0x45, 0x55, 0x00, 0x4d, 0x5d, 0x59, 0x41, 0x51, 0x00, 0x00, jmpEOR);
991 SETOP(17, "CLC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, jmpCLC);
992 SETOP(18, "SEC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, jmpSEC);
993 SETOP(19, "CLI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, jmpCLI);
994 SETOP(20, "SEI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, jmpSEI);
995 SETOP(21, "CLV", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, jmpCLV);
996 SETOP(22, "CLD", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, jmpCLD);
997 SETOP(23, "SED", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, jmpSED);
998 SETOP(24, "INC", 0x00, 0xe6, 0xf6, 0x00, 0xee, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, jmpINC);
999 SETOP(25, "JMP", 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpJMP);
1000 SETOP(26, "JSR", 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpJSR);
1001 SETOP(27, "LDA", 0xa9, 0xa5, 0xb5, 0x00, 0xad, 0xbd, 0xb9, 0xa1, 0xb1, 0x00, 0x00, jmpLDA);
1002 SETOP(28, "LDX", 0xa2, 0xa6, 0x00, 0xb6, 0xae, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, jmpLDX);
1003 SETOP(29, "LDY", 0xa0, 0xa4, 0xb4, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, jmpLDY);
1004 SETOP(30, "LSR", 0x00, 0x46, 0x56, 0x00, 0x4e, 0x5e, 0x00, 0x00, 0x00, 0x4a, 0x00, jmpLSR);
1005 SETOP(31, "NOP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, jmpNOP);
1006 SETOP(32, "ORA", 0x09, 0x05, 0x15, 0x00, 0x0d, 0x1d, 0x19, 0x01, 0x11, 0x00, 0x00, jmpORA);
1007 SETOP(33, "TAX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, jmpTAX);
1008 SETOP(34, "TXA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, jmpTXA);
1009 SETOP(35, "DEX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x00, jmpDEX);
1010 SETOP(36, "INX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, jmpINX);
1011 SETOP(37, "TAY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, jmpTAY);
1012 SETOP(38, "TYA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, jmpTYA);
1013 SETOP(39, "DEY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, jmpDEY);
1014 SETOP(40, "INY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, jmpINY);
1015 SETOP(41, "ROR", 0x00, 0x66, 0x76, 0x00, 0x6e, 0x7e, 0x00, 0x00, 0x00, 0x6a, 0x00, jmpROR);
1016 SETOP(42, "ROL", 0x00, 0x26, 0x36, 0x00, 0x2e, 0x3e, 0x00, 0x00, 0x00, 0x2a, 0x00, jmpROL);
1017 SETOP(43, "RTI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, jmpRTI);
1018 SETOP(44, "RTS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, jmpRTS);
1019 SETOP(45, "SBC", 0xe9, 0xe5, 0xf5, 0x00, 0xed, 0xfd, 0xf9, 0xe1, 0xf1, 0x00, 0x00, jmpSBC);
1020 SETOP(46, "STA", 0x00, 0x85, 0x95, 0x00, 0x8d, 0x9d, 0x99, 0x81, 0x91, 0x00, 0x00, jmpSTA);
1021 SETOP(47, "TXS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, jmpTXS);
1022 SETOP(48, "TSX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, jmpTSX);
1023 SETOP(49, "PHA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, jmpPHA);
1024 SETOP(50, "PLA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, jmpPLA);
1025 SETOP(51, "PHP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, jmpPHP);
1026 SETOP(52, "PLP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, jmpPLP);
1027 SETOP(53, "STX", 0x00, 0x86, 0x00, 0x96, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpSTX);
1028 SETOP(54, "STY", 0x00, 0x84, 0x94, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpSTY);
1029 SETOP(55, "---", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, NULL);
1032 static void buildIndexCache(machine_6502 *machine){
1034 for (i = 0; i < NUM_OPCODES; i++) {
1035 if (machine->opcodes[i].Imm != 0x00){
1036 machine->opcache[machine->opcodes[i].Imm].adm = IMMEDIATE_VALUE;
1037 machine->opcache[machine->opcodes[i].Imm].index = i;
1039 if (machine->opcodes[i].ZP != 0x00){
1040 machine->opcache[machine->opcodes[i].ZP].adm = ZERO;
1041 machine->opcache[machine->opcodes[i].ZP].index = i;
1043 if (machine->opcodes[i].ZPX != 0x00){
1044 machine->opcache[machine->opcodes[i].ZPX].adm = ZERO_X;
1045 machine->opcache[machine->opcodes[i].ZPX].index = i;;
1047 if (machine->opcodes[i].ZPY != 0x00){
1048 machine->opcache[machine->opcodes[i].ZPY].adm = ZERO_Y;
1049 machine->opcache[machine->opcodes[i].ZPY].index = i;;
1051 if (machine->opcodes[i].ABS != 0x00){
1052 machine->opcache[machine->opcodes[i].ABS].adm = ABS_VALUE;
1053 machine->opcache[machine->opcodes[i].ABS].index = i;;
1055 if (machine->opcodes[i].ABSX != 0x00){
1056 machine->opcache[machine->opcodes[i].ABSX].adm = ABS_X;
1057 machine->opcache[machine->opcodes[i].ABSX].index = i;;
1059 if (machine->opcodes[i].ABSY != 0x00){
1060 machine->opcache[machine->opcodes[i].ABSY].adm = ABS_Y;
1061 machine->opcache[machine->opcodes[i].ABSY].index = i;;
1063 if (machine->opcodes[i].INDX != 0x00){
1064 machine->opcache[machine->opcodes[i].INDX].adm = INDIRECT_X;
1065 machine->opcache[machine->opcodes[i].INDX].index = i;;
1067 if (machine->opcodes[i].INDY != 0x00){
1068 machine->opcache[machine->opcodes[i].INDY].adm = INDIRECT_Y;
1069 machine->opcache[machine->opcodes[i].INDY].index = i;;
1071 if (machine->opcodes[i].SNGL != 0x00){
1072 machine->opcache[machine->opcodes[i].SNGL].adm = SINGLE;
1073 machine->opcache[machine->opcodes[i].SNGL].index = i;
1075 if (machine->opcodes[i].BRA != 0x00){
1076 machine->opcache[machine->opcodes[i].BRA].adm = ABS_OR_BRANCH;
1077 machine->opcache[machine->opcodes[i].BRA].index = i;
1082 /* opIndex() - Search the opcode table for a match. If found return
1083 the index into the optable and the address mode of the opcode. If
1084 the opcode is not found then return -1. */
1085 static int opIndex(machine_6502 *machine, Bit8 opcode, AddrMode *adm){
1086 /* XXX could catch errors by setting a addressmode of error or something */
1087 *adm = machine->opcache[opcode].adm;
1088 return machine->opcache[opcode].index;
1092 /* Assembly parser */
1094 static Param *newParam(void){
1098 newp = (Param *) emalloc(sizeof(Param));
1099 newp->type = SINGLE;
1100 for (i = 0; i < MAX_PARAM_VALUE; i++)
1103 newp->label = ecalloc(MAX_LABEL_LEN,sizeof(char));
1108 /* Copy the fields from p2 to p1 */
1109 static void copyParam(Param *p1, Param *p2){
1111 strncpy(p1->label,p2->label,MAX_LABEL_LEN);
1112 for(i = 0; i < MAX_PARAM_VALUE; i++)
1113 p1->value[i] = p2->value[i];
1115 p1->type = p2->type;
1118 static Label *newLabel(void){
1121 newp = (Label *) emalloc(sizeof(Label));
1123 newp->label = ecalloc(MAX_LABEL_LEN,sizeof(char));
1128 static AsmLine *newAsmLine(char *cmd, char *label, BOOL decl, Param *param, int lc)
1132 newp = (AsmLine *) emalloc(sizeof(AsmLine));
1133 newp->labelDecl = decl;
1134 newp->label = newLabel();
1135 strncpy(newp->label->label,label,MAX_LABEL_LEN);
1136 newp->command = estrdup(cmd);
1137 newp->param = newParam();
1138 copyParam(newp->param, param);
1143 static AsmLine *addend(AsmLine *listp, AsmLine *newp)
1148 for (p =listp; p->next != NULL; p = p->next)
1154 static BOOL apply(AsmLine *listp, BOOL(*fn)(AsmLine*, void*), void *arg)
1159 for (p = listp; p != NULL; p = p->next)
1165 static void freeParam(Param *param){
1170 static void freeLabel(Label *label){
1175 static void freeallAsmLine(AsmLine *listp)
1178 for(; listp != NULL; listp = next){
1180 freeParam(listp->param);
1181 freeLabel(listp->label);
1182 free(listp->command);
1187 static BOOL addvalue(Param *param,Bit32 value){
1188 if (0 <= param->vp && param->vp < MAX_PARAM_VALUE) {
1189 param->value[param->vp++] = value;
1193 fprintf(stderr,"Wrong number of parameters: %d. The limit is %d\n",param->vp+1, MAX_PARAM_VALUE);
1198 static void parseError(char *s){
1199 fprintf(stderr,"6502 Syntax Error: %s\n", s);
1202 /* stoupper() - Destructivley modifies the string making all letters upper case*/
1203 static void stoupper(char **s){
1205 while((*s)[i] != '\0'){
1206 (*s)[i] = toupper((*s)[i]);
1211 static BOOL isWhite(char c){
1212 return (c == '\r' || c == '\t' || c == ' ');
1215 static void skipSpace(char **s){
1216 for(; isWhite(**s); (*s)++)
1220 /* nullify() - fills a string with upto sourceLength null characters. */
1221 static void nullify(char *token, unsigned int sourceLength){
1223 while (i < sourceLength)
1227 static BOOL isBlank(const char *token){
1228 return (token[0] == '\0');
1231 static BOOL isCommand(machine_6502 *machine, const char *token){
1234 while (i < NUM_OPCODES) {
1235 if (strcmp(machine->opcodes[i].name,token) == 0)
1240 if (strcmp(token, "DCB") == 0) return TRUE;
1244 /* hasChar() - Check to see if the current line has a certain
1246 static BOOL hasChar(char *s, char c){
1247 for(; *s != '\0' && *s != '\n'; s++) {
1254 static BOOL ishexdigit(char c){
1258 char c1 = toupper(c);
1259 return ('A' <= c1 && c1 <= 'F');
1263 /* command() - parse a command from the source code. We pass along a
1264 machine so the opcode can be validated. */
1265 static BOOL command(machine_6502 *machine, char **s, char **cmd){
1268 for(;isalpha(**s) && i < MAX_CMD_LEN; (*s)++)
1271 return TRUE; /* Could be a blank line. */
1273 return isCommand(machine,*cmd);
1276 static BOOL declareLabel(char **s, char **label){
1279 for(;**s != ':' && **s != '\n' && **s != '\0'; (*s)++){
1282 (*label)[i++] = **s;
1285 return FALSE; /* Current line has to have a label */
1286 else if (**s == ':'){
1287 (*s)++; /* Skip colon */
1294 static BOOL parseHex(char **s, Bit32 *value){
1295 enum { MAX_HEX_LEN = 5 };
1297 char *hex = ecalloc(MAX_HEX_LEN, sizeof(char));
1300 (*s)++; /* move pass $ */
1301 for(; ishexdigit(**s) && i < MAX_HEX_LEN; (*s)++)
1304 *value = strtol(hex,NULL,16);
1312 static BOOL parseDec(char **s, Bit32 *value){
1313 enum { MAX_DEC_LEN = 4 };
1314 char *dec = ecalloc(MAX_DEC_LEN, sizeof(char));
1316 for(i = 0; isdigit(**s) && i < MAX_DEC_LEN; (*s)++)
1328 static BOOL parseValue(char **s, Bit32 *value){
1331 return parseHex(s, value);
1333 return parseDec(s, value);
1336 static BOOL paramLabel(char **s, char **label){
1338 for(i = 0; (isalnum(**s) || **s == '_') && i < MAX_LABEL_LEN; (*s)++)
1339 (*label)[i++] = **s;
1347 static BOOL immediate(char **s, Param *param){
1351 (*s)++; /*Move past hash */
1352 if (**s == '<' || **s == '>'){
1353 char *label = ecalloc(MAX_LABEL_LEN, sizeof(char));
1354 param->type = (**s == '<') ? IMMEDIATE_LESS : IMMEDIATE_GREAT;
1355 (*s)++; /* move past < or > */
1356 if (paramLabel(s, &label)){
1357 int ln = strlen(label) + 1;
1358 strncpy(param->label, label, ln);
1366 if (parseValue(s, &value)){
1368 parseError("Immediate value is too large.");
1371 param->type = IMMEDIATE_VALUE;
1372 return addvalue(param, value);
1378 static BOOL isDirection(char c){
1379 return (c == 'X' || c == 'Y');
1382 static BOOL getDirection(char **s, char *direction){
1387 if (isDirection(**s)){
1396 static BOOL indirect(char **s, Param *param){
1404 if (! parseHex(s,&value))
1407 parseError("Indirect value is too large.");
1410 if (!addvalue(param, value))
1415 if (getDirection(s,&c)) {
1417 param->type = INDIRECT_Y;
1422 else if (getDirection(s, &c)){
1427 param->type = INDIRECT_X;
1435 static BOOL dcbValue(char **s, Param *param){
1437 if (! parseValue(s,&val))
1443 if (!addvalue(param,val))
1446 param->type = DCB_PARAM;
1451 return dcbValue(s, param);
1457 static BOOL value(char **s, Param *param){
1462 if (! parseValue(s,&val))
1466 dir = getDirection(s,&c);
1467 if (!addvalue(param,val))
1472 param->type = ABS_X;
1474 param->type = ABS_Y;
1479 param->type = ABS_VALUE;
1482 param->type = ZERO_X;
1484 param->type = ZERO_Y;
1494 static BOOL label(char **s, Param *param){
1495 char *label = ecalloc(MAX_LABEL_LEN, sizeof(char));
1497 BOOL labelOk = FALSE;
1498 if (paramLabel(s, &label)){
1500 param->type = ABS_OR_BRANCH;
1501 if (getDirection(s, &c)){
1503 param->type = ABS_LABEL_X;
1505 param->type = ABS_LABEL_Y;
1509 strncpy(param->label,label,MAX_LABEL_LEN);
1515 static BOOL parameter(const char *cmd, char **s, Param *param){
1517 if (**s == '\0' || **s == '\n')
1519 else if (**s == '#')
1520 return immediate(s,param);
1521 else if (**s == '(')
1522 return indirect(s,param);
1523 else if (**s == '$' || isdigit(**s)){
1524 if (strcmp(cmd, "DCB") == 0)
1525 return dcbValue(s,param);
1527 return value(s,param);
1529 else if (isalpha(**s))
1530 return label(s ,param);
1532 return FALSE; /* Invalid Parameter */
1535 static void comment(char **s){
1538 for(;**s != '\n' && **s != '\0'; (*s)++)
1542 static void initParam(Param *param){
1544 param->type = SINGLE;
1545 for(i = 0; i < MAX_PARAM_VALUE; i++)
1546 param->value[i] = 0;
1548 nullify(param->label,MAX_LABEL_LEN);
1552 static AsmLine *parseAssembly(machine_6502 *machine, BOOL *codeOk, const char *code){
1554 char *cmd = ecalloc(MAX_CMD_LEN, sizeof(char));
1555 char *label = ecalloc(MAX_LABEL_LEN, sizeof(char));
1556 char *start; /*pointer to the start of the code.*/
1557 unsigned int lc = 1;
1560 AsmLine *listp = NULL;
1568 while(*s != '\0' && *codeOk){
1570 nullify(cmd, MAX_CMD_LEN);
1571 nullify(label, MAX_LABEL_LEN);
1578 continue; /* blank line */
1580 else if (*s == '\0')
1581 continue; /* no newline at the end of the code */
1582 else if (hasChar(s,':')){
1584 if(! declareLabel(&s,&label)){
1590 if(!command(machine, &s, &cmd)){
1596 if(!parameter(cmd, &s, param)){
1602 if (*s == '\n' || *s == '\0'){
1604 asmm = newAsmLine(cmd,label,decl,param,lc);
1605 listp = addend(listp,asmm);
1613 fprintf(stderr,"Syntax error at line %u\n", lc);
1621 /* fileToBuffer() - Allocates a buffer and loads all of the file into memory. */
1622 static char *fileToBuffer(char *filename){
1623 const int defaultSize = 1024;
1626 int size = defaultSize;
1628 char *buffer = ecalloc(defaultSize,sizeof(char));
1631 eprintf("Could not allocate memory for buffer.");
1633 ifp = fopen(filename, "rb");
1635 eprintf("Could not open file.");
1637 while((c = getc(ifp)) != EOF){
1640 size += defaultSize;
1641 buffer = realloc(buffer, size);
1642 if (buffer == NULL) {
1644 eprintf("Could not resize buffer.");
1649 buffer = realloc(buffer, i+2);
1651 eprintf("Could not resize buffer.");
1652 /* Make sure we have a line feed at the end */
1661 /* reset() - Reset CPU and memory. */
1662 static void reset(machine_6502 *machine){
1664 for ( y = 0; y < 32; y++ ){
1665 for (x = 0; x < 32; x++){
1666 machine->screen[x][y] = 0;
1670 for(x=0; x < MEM_64K; x++)
1671 machine->memory[x] = 0;
1673 machine->codeCompiledOK = FALSE;
1677 machine->regP = setBit(machine->regP, FUTURE_FL, 1);
1678 machine->regPC = 0x600;
1679 machine->regSP = STACK_TOP;
1680 machine->runForever = FALSE;
1681 machine->labelPtr = 0;
1682 machine->codeRunning = FALSE;
1685 /* hexDump() - Dump the memory to output */
1686 void hexDump(machine_6502 *machine, Bit16 start, Bit16 numbytes, FILE *output){
1689 for( i = 0; i < numbytes; i++){
1690 address = start + i;
1691 if ( (i&15) == 0 ) {
1692 fprintf(output,"\n%.4x: ", address);
1694 fprintf(output,"%.2x%s",machine->memory[address], (i & 1) ? " ":"");
1696 fprintf(output,"%s\n",(i&1)?"--":"");
1699 void save_program(machine_6502 *machine, char *filename){
1702 Bit16 end = pc + machine->codeLen;
1704 ofp = fopen(filename, "w");
1706 eprintf("Could not open file.");
1708 fprintf(ofp,"Bit8 prog[%d] =\n{",machine->codeLen);
1711 fprintf(ofp,"0x%.2x,%s",machine->memory[pc++],n++%10?" ":"\n");
1712 fseek(ofp,-2,SEEK_CUR);
1713 fprintf(ofp,"};\n");
1718 static BOOL translate(Opcodes *op,Param *param, machine_6502 *machine){
1719 switch(param->type){
1722 pushByte(machine, op->SNGL);
1724 fprintf(stderr,"%s needs a parameter.\n",op->name);
1728 case IMMEDIATE_VALUE:
1730 pushByte(machine, op->Imm);
1731 pushByte(machine, param->value[0]);
1735 fprintf(stderr,"%s does not take IMMEDIATE_VALUE parameters.\n",op->name);
1738 case IMMEDIATE_GREAT:
1740 pushByte(machine, op->Imm);
1741 pushByte(machine, param->lbladdr / 0xFF);
1745 fprintf(stderr,"%s does not take IMMEDIATE_GREAT parameters.\n",op->name);
1748 case IMMEDIATE_LESS:
1750 pushByte(machine, op->Imm);
1751 pushByte(machine, param->lbladdr & 0xFF);
1755 fprintf(stderr,"%s does not take IMMEDIATE_LESS parameters.\n",op->name);
1760 pushByte(machine, op->INDX);
1761 pushByte(machine, param->value[0]);
1765 fprintf(stderr,"%s does not take INDIRECT_X parameters.\n",op->name);
1770 pushByte(machine, op->INDY);
1771 pushByte(machine, param->value[0]);
1775 fprintf(stderr,"%s does not take INDIRECT_Y parameters.\n",op->name);
1780 pushByte(machine, op->ZP);
1781 pushByte(machine, param->value[0]);
1785 fprintf(stderr,"%s does not take ZERO parameters.\n",op->name);
1790 pushByte(machine, op->ZPX);
1791 pushByte(machine, param->value[0]);
1795 fprintf(stderr,"%s does not take ZERO_X parameters.\n",op->name);
1800 pushByte(machine, op->ZPY);
1801 pushByte(machine, param->value[0]);
1805 fprintf(stderr,"%s does not take ZERO_Y parameters.\n",op->name);
1810 pushByte(machine, op->ABS);
1811 pushWord(machine, param->value[0]);
1815 fprintf(stderr,"%s does not take ABS_VALUE parameters.\n",op->name);
1820 pushByte(machine, op->ABS);
1821 pushWord(machine, param->lbladdr);
1825 pushByte(machine, op->BRA);
1826 if (param->lbladdr < (machine->codeLen + 0x600))
1828 (0xff - (machine->codeLen-param->lbladdr)) & 0xff);
1831 (param->lbladdr - machine->codeLen-1) & 0xff);
1834 fprintf(stderr,"%s does not take BRANCH parameters.\n",op->name);
1841 pushByte(machine, op->ABSX);
1842 pushWord(machine, param->value[0]);
1846 fprintf(stderr,"%s does not take ABS_X parameters.\n",op->name);
1851 pushByte(machine, op->ABSY);
1852 pushWord(machine, param->value[0]);
1856 fprintf(stderr,"%s does not take ABS_Y parameters.\n",op->name);
1861 pushByte(machine, op->ABSX);
1862 pushWord(machine, param->lbladdr);
1866 fprintf(stderr,"%s does not take ABS_LABEL_X parameters.\n",op->name);
1871 pushByte(machine, op->ABSY);
1872 pushWord(machine, param->lbladdr);
1876 fprintf(stderr,"%s does not take ABS_LABEL_Y parameters.\n",op->name);
1880 /* Handled elsewhere */
1886 /* compileLine() - Compile one line of code. Returns
1887 TRUE if it compile successfully. */
1888 static BOOL compileLine(AsmLine *asmline, void *args){
1889 machine_6502 *machine;
1891 if (isBlank(asmline->command)) return TRUE;
1893 if (strcmp("DCB",asmline->command) == 0){
1895 for(i = 0; i < asmline->param->vp; i++)
1896 pushByte(machine, asmline->param->value[i]);
1900 char *command = asmline->command;
1902 for(i = 0; i < NUM_OPCODES; i++){
1903 if (strcmp(machine->opcodes[i].name, command) == 0){
1904 op = machine->opcodes[i];
1908 if (i == NUM_OPCODES)
1909 return FALSE; /* unknow upcode */
1911 return translate(&op,asmline->param,machine);
1916 /* indexLabels() - Get the address for each label */
1917 static BOOL indexLabels(AsmLine *asmline, void *arg){
1918 machine_6502 *machine;
1921 thisPC = machine->regPC;
1922 /* Figure out how many bytes this instruction takes */
1923 machine->codeLen = 0;
1924 if ( ! compileLine(asmline, machine) ){
1927 machine->regPC += machine->codeLen;
1928 if (asmline->labelDecl) {
1929 asmline->label->addr = thisPC;
1934 static BOOL changeParamLabelAddr(AsmLine *asmline, void *label){
1936 if (strcmp(asmline->param->label, la->label) == 0)
1937 asmline->param->lbladdr = la->addr;
1941 static BOOL linkit(AsmLine *asmline, void *asmlist){
1942 apply(asmlist,changeParamLabelAddr,asmline->label);
1946 /* linkLabels - Make sure all of the references to the labels contain
1948 static void linkLabels(AsmLine *asmlist){
1949 apply(asmlist,linkit,asmlist);
1952 /* compileCode() - Compile the current assembly code for the machine */
1953 static BOOL compileCode(machine_6502 *machine, const char *code){
1958 machine->regPC = 0x600;
1959 asmlist = parseAssembly(machine, &codeOk, code);
1962 /* First pass: Find the addresses for the labels */
1963 if (!apply(asmlist, indexLabels, machine))
1965 /* update label references */
1966 linkLabels(asmlist);
1967 /* Second pass: translate the instructions */
1968 machine->codeLen = 0;
1969 if (!apply(asmlist, compileLine, machine))
1972 if (machine->codeLen > 0 ){
1973 machine->memory[0x600+machine->codeLen] = 0x00;
1977 fprintf(stderr,"No Code to run.\n");
1982 fprintf(stderr,"An error occured while parsing the file.\n");
1985 freeallAsmLine(asmlist);
1991 * execute() - Executes one instruction.
1992 * This is the main part of the CPU emulator.
1996 static void execute(machine_6502 *machine){
2001 if(!machine->codeRunning) return;
2003 opcode = popByte(machine);
2005 machine->codeRunning = FALSE;
2007 opidx = opIndex(machine,opcode,&adm);
2009 machine->opcodes[opidx].func(machine, adm);
2011 fprintf(stderr,"Invalid opcode!\n");
2013 if( (machine->regPC == 0) ||
2014 (!machine->codeRunning) ||
2015 (machine->regPC > (machine->codeLen+0x600)) ) {
2016 machine->codeRunning = FALSE;
2020 machine_6502 *build6502(){
2021 machine_6502 *machine;
2022 machine = emalloc(sizeof(machine_6502));
2023 assignOpCodes(machine->opcodes);
2024 buildIndexCache(machine);
2029 void destroy6502(machine_6502 *machine){
2034 void trace(machine_6502 *machine, FILE *output){
2035 Bit8 opcode = memReadByte(machine,machine->regPC);
2038 int opidx = opIndex(machine,opcode,&adm);
2039 int stacksz = STACK_TOP - machine->regSP;
2041 fprintf(output,"\n NVFBDIZC\nP: %d%d%d%d%d%d%d%d ",
2042 bitOn(machine->regP,NEGATIVE_FL),
2043 bitOn(machine->regP,OVERFLOW_FL),
2044 bitOn(machine->regP,FUTURE_FL),
2045 bitOn(machine->regP,BREAK_FL),
2046 bitOn(machine->regP,DECIMAL_FL),
2047 bitOn(machine->regP,INTERRUPT_FL),
2048 bitOn(machine->regP,ZERO_FL),
2049 bitOn(machine->regP,CARRY_FL));
2050 fprintf(output,"A: %.2x X: %.2x Y: %.2x SP: %.4x PC: %.4x\n",
2051 machine->regA, machine->regX, machine->regY, machine->regSP, machine->regPC);
2053 Bit16 pc = machine->regPC;
2054 fprintf(output,"\n%.4x:\t%s",machine->regPC, machine->opcodes[opidx].name);
2055 if (peekValue(machine, adm, &ptr, pc+1))
2056 fprintf(output,"\tAddress:%.4x\tValue:%.4x\n",
2057 ptr.addr,ptr.value);
2059 fprintf(output,"\n");
2061 fprintf(output,"STACK:");
2062 hexDump(machine,(STACK_TOP - stacksz) + 1, stacksz, output);
2063 fprintf(output,"\n================================================================================\n");
2069 void eval_file(machine_6502 *machine, char *filename, Plotter plot, void *plotterState){
2072 machine->plot = plot;
2073 machine->plotterState = plotterState;
2075 code = fileToBuffer(filename);
2077 if (! compileCode(machine, code) ){
2078 eprintf("Could not compile code.\n");
2083 machine->regPC = 0x600;
2084 machine->codeRunning = TRUE;
2091 if (!machine->codeRunning)
2093 }while((machine->regPC - 0x600) < machine->codeLen);
2096 void start_eval_file(machine_6502 *machine, char *filename, Plotter plot, void *plotterState){
2100 machine->plot = plot;
2101 machine->plotterState = plotterState;
2103 code = fileToBuffer(filename);
2105 if (! compileCode(machine, code) ){
2106 eprintf("Could not compile code.\n");
2111 machine->regPC = 0x600;
2112 machine->codeRunning = TRUE;
2116 void start_eval_binary(machine_6502 *machine, Bit8 *program,
2117 unsigned int proglen,
2118 Plotter plot, void *plotterState){
2121 machine->plot = plot;
2122 machine->plotterState = plotterState;
2124 machine->regPC = 0x600;
2125 pc = machine->regPC;
2126 machine->codeLen = proglen;
2128 while (n < proglen){
2129 machine->memory[pc++] = program[n++];
2131 machine->codeRunning = TRUE;
2135 void next_eval(machine_6502 *machine, int insno){
2137 for (i = 1; i < insno; i++){
2138 if (machine->codeRunning){/* && ((machine->regPC - 0x600) < machine->codeLen))*/