1 /*-*- indent-tabs-mode:nil -*- */
2 /* Copyright (C) 2007 Jeremy English <jhe@jeremyenglish.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
12 * Created: 12-April-2007
16 This is a port of the javascript 6502 assembler, compiler and
17 debugger. The orignal code was copyright 2006 by Stian Soreng -
20 I changed the structure of the assembler in this version.
25 /*#include <malloc.h>*/
35 #if defined(HAVE_STDINT_H)
37 #elif defined(HAVE_INTTYPES_H)
38 # include <inttypes.h>
61 |N||V||F||B||D||I||Z||C|
68 CARRY_FL = 0, ZERO_FL = 1, INTERRUPT_FL = 2,
69 DECIMAL_FL = 3, BREAK_FL = 4, FUTURE_FL = 5,
70 OVERFLOW_FL = 6, NEGATIVE_FL = 7
74 typedef BOOL (*CharTest) (char);
76 /* A jump function takes a pointer to the current machine and a
77 opcode. The opcode is needed to figure out the memory mode. */
78 /*typedef void (*JumpFunc) (machine_6502* AddrMode);*/
82 Bit32 value[MAX_PARAM_VALUE];
83 unsigned int vp; /*value pointer, index into the value table.*/
89 Bit32 addr; /* Address of the label */
93 typedef struct AsmLine AsmLine;
95 BOOL labelDecl; /* Does the line have a label declaration? */
99 AsmLine *next; /* in list */
108 /*static void *emalloc(size_t n) {
114 static void *ecalloc(uint32_t nelm, size_t nsize){
115 void *p = calloc(nelm, nsize);
120 /* estrdup() - Allocates memory for a new string a returns a copy of the source sting in it. */
121 static char *estrdup(const char *source){
122 int ln = strlen(source) + 1;
123 char *s = ecalloc(ln, sizeof(char));
124 strncpy(s,source,ln);
128 static void checkAddress(Bit32 address){
129 /* XXX: Do we want to kill the program here? */
130 if (address >= MEM_64K)
131 fprintf(stderr, "Address %d is beyond 64k", address);
135 * stackPush() - Push byte to stack
139 static void stackPush(machine_6502 *machine, Bit8 value ) {
140 if(machine->regSP >= STACK_BOTTOM){
141 machine->memory[machine->regSP--] = value;
144 fprintf(stderr, "The stack is full: %.4x\n", machine->regSP);
145 machine->codeRunning = FALSE;
151 * stackPop() - Pop byte from stack
155 static Bit8 stackPop(machine_6502 *machine) {
156 if (machine->regSP < STACK_TOP){
157 Bit8 value =machine->memory[++machine->regSP];
161 /* fprintf(stderr, "The stack is empty.\n"); xxx */
162 machine->codeRunning = FALSE;
167 static void pushByte(machine_6502 *machine, Bit32 value ) {
168 Bit32 address = machine->defaultCodePC;
169 checkAddress(address);
170 machine->memory[address] = value & 0xff;
172 machine->defaultCodePC++;
176 * pushWord() - Push a word using pushByte twice
180 static void pushWord(machine_6502 *machine, Bit16 value ) {
181 pushByte(machine, value & 0xff );
182 pushByte(machine, (value>>8) & 0xff );
186 * popByte( machine_6502 *machine,) - Pops a byte
190 static Bit8 popByte( machine_6502 *machine) {
191 Bit8 value = machine->memory[machine->regPC];
197 * popWord() - Pops a word using popByte() twice
201 static int popWord(machine_6502 *machine) {
202 return popByte(machine) + (popByte(machine) << 8);
207 * memReadByte() - Peek a byte, don't touch any registers
211 static int memReadByte( machine_6502 *machine, int addr ) {
212 if( addr == 0xfe ) return floor( random()%255 );
213 return machine->memory[addr];
216 static void updateDisplayPixel(machine_6502 *machine, Bit16 addr){
217 Bit8 idx = memReadByte(machine,addr) & 0x0f;
223 machine->plot(x,y,idx,machine->plotterState);
228 * memStoreByte() - Poke a byte, don't touch any registers
232 static void memStoreByte( machine_6502 *machine, int addr, int value ) {
233 machine->memory[ addr ] = (value & 0xff);
234 if( (addr >= 0x200) && (addr<=0x5ff) )
235 updateDisplayPixel(machine, addr );
242 static Bit8 bitOn(Bit8 value,Flags bit){
245 return ((value & mask) > 0);
248 static Bit8 bitOff(Bit8 value, Flags bit){
249 return (! bitOn(value,bit));
252 static Bit8 setBit(Bit8 value, Flags bit, int on){
255 onMask = onMask << bit;
256 offMask = offMask ^ onMask;
257 return ((on) ? value | onMask : value & offMask);
260 static Bit8 nibble(Bit8 value, Side side){
262 case LEFT: return value & 0xf0;
263 case RIGHT: return value & 0xf;
265 fprintf(stderr,"nibble unknown side\n");
271 /* used for tracing. XXX: combined with function getvalue */
272 static BOOL peekValue(machine_6502 *machine, m6502_AddrMode adm, Pointer *pointer, Bit16 PC){
280 case IMMEDIATE_GREAT:
281 case IMMEDIATE_VALUE:
282 pointer->value = memReadByte(machine, PC);
285 zp = memReadByte(machine, PC) + machine->regX;
286 pointer->addr = memReadByte(machine,zp) +
287 (memReadByte(machine,zp+1)<<8);
288 pointer->value = memReadByte(machine, pointer->addr);
291 zp = memReadByte(machine, PC);
292 pointer->addr = memReadByte(machine,zp) +
293 (memReadByte(machine,zp+1)<<8) + machine->regY;
294 pointer->value = memReadByte(machine, pointer->addr);
297 pointer->addr = memReadByte(machine, PC);
298 pointer->value = memReadByte(machine, pointer->addr);
301 pointer->addr = memReadByte(machine, PC) + machine->regX;
302 pointer->value = memReadByte(machine, pointer->addr);
305 pointer->addr = memReadByte(machine, PC) + machine->regY;
306 pointer->value = memReadByte(machine, pointer->addr);
309 pointer->addr = memReadByte(machine, PC);
312 pointer->addr = memReadByte(machine, PC) + (memReadByte(machine, PC+1) << 8);
313 pointer->value = memReadByte(machine, pointer->addr);
317 pointer->addr = (memReadByte(machine, PC) +
318 (memReadByte(machine, PC+1) << 8)) + machine->regX;
319 pointer->value = memReadByte(machine, pointer->addr);
323 pointer->addr = (memReadByte(machine, PC) +
324 (memReadByte(machine, PC+1) << 8)) + machine->regY;
325 pointer->value = memReadByte(machine, pointer->addr);
328 /* Handled elsewhere */
336 /* Figure out how to get the value from the addrmode and get it.*/
337 static BOOL getValue(machine_6502 *machine, m6502_AddrMode adm, Pointer *pointer){
345 case IMMEDIATE_GREAT:
346 case IMMEDIATE_VALUE:
347 pointer->value = popByte(machine);
350 zp = popByte(machine) + machine->regX;
351 pointer->addr = memReadByte(machine,zp) +
352 (memReadByte(machine,zp+1)<<8);
353 pointer->value = memReadByte(machine, pointer->addr);
356 zp = popByte(machine);
357 pointer->addr = memReadByte(machine,zp) +
358 (memReadByte(machine,zp+1)<<8) + machine->regY;
359 pointer->value = memReadByte(machine, pointer->addr);
362 pointer->addr = popByte(machine);
363 pointer->value = memReadByte(machine, pointer->addr);
366 pointer->addr = popByte(machine) + machine->regX;
367 pointer->value = memReadByte(machine, pointer->addr);
370 pointer->addr = popByte(machine) + machine->regY;
371 pointer->value = memReadByte(machine, pointer->addr);
374 pointer->addr = popByte(machine);
377 pointer->addr = popWord(machine);
378 pointer->value = memReadByte(machine, pointer->addr);
382 pointer->addr = popWord(machine) + machine->regX;
383 pointer->value = memReadByte(machine, pointer->addr);
387 pointer->addr = popWord(machine) + machine->regY;
388 pointer->value = memReadByte(machine, pointer->addr);
391 /* Handled elsewhere */
399 static void dismem(machine_6502 *machine, m6502_AddrMode adm, char *output){
407 case IMMEDIATE_GREAT:
408 case IMMEDIATE_VALUE:
409 n = popByte(machine);
410 sprintf(output,"#$%x",n);
413 zp = popByte(machine);
414 n = memReadByte(machine,zp) +
415 (memReadByte(machine,zp+1)<<8);
416 sprintf(output,"($%x,x)",n);
419 zp = popByte(machine);
420 n = memReadByte(machine,zp) +
421 (memReadByte(machine,zp+1)<<8);
422 sprintf(output,"($%x),y",n);
426 n = popByte(machine);
427 sprintf(output,"$%x",n);
430 n = popByte(machine);
431 sprintf(output,"$%x,x",n);
434 n = popByte(machine);
435 sprintf(output,"$%x,y",n);
438 n = popWord(machine);
439 sprintf(output,"$%x",n);
443 n = popWord(machine);
444 sprintf(output,"$%x,x",n);
448 n = popWord(machine);
449 sprintf(output,"$%x,x",n);
458 /* manZeroNeg - Manage the negative and zero flags */
459 static void manZeroNeg(machine_6502 *machine, Bit8 value){
460 machine->regP = setBit(machine->regP, ZERO_FL, (value == 0));
461 machine->regP = setBit(machine->regP, NEGATIVE_FL, bitOn(value,NEGATIVE_FL));
464 static void warnValue(BOOL isValue){
466 fprintf(stderr,"Invalid Value from getValue.\n");
470 static void jmpADC(machine_6502 *machine, m6502_AddrMode adm){
473 Bit8 c = bitOn(machine->regP, CARRY_FL);
474 BOOL isValue = getValue(machine, adm, &ptr);
478 if (bitOn(machine->regA, NEGATIVE_FL) &&
479 bitOn(ptr.value, NEGATIVE_FL))
480 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
482 machine->regP = setBit(machine->regP, OVERFLOW_FL, 1);
484 if (bitOn(machine->regP, DECIMAL_FL)) {
485 tmp = nibble(machine->regA,RIGHT) + nibble(ptr.value,RIGHT ) + c;
486 /* The decimal part is limited to 0 through 9 */
488 tmp = 0x10 | ((tmp + 6) & 0xf);
490 tmp += nibble(machine->regA,LEFT) + nibble(ptr.value,LEFT);
492 machine->regP = setBit(machine->regP,CARRY_FL,1);
493 if (bitOn(machine->regP, OVERFLOW_FL) && tmp >= 0x180)
494 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
498 machine->regP = setBit(machine->regP,CARRY_FL,0);
499 if (bitOn(machine->regP, OVERFLOW_FL) && tmp < 0x80)
500 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
504 tmp = machine->regA + ptr.value + c;
506 machine->regP = setBit(machine->regP,CARRY_FL,1);
507 if (bitOn(machine->regP, OVERFLOW_FL) && tmp >= 0x180)
508 machine->regP =setBit(machine->regP, OVERFLOW_FL, 0);
511 machine->regP = setBit(machine->regP,CARRY_FL,0);
512 if (bitOn(machine->regP, OVERFLOW_FL) && tmp < 0x80)
513 machine->regP =setBit(machine->regP, OVERFLOW_FL, 0);
518 manZeroNeg(machine,machine->regA);
521 static void jmpAND(machine_6502 *machine, m6502_AddrMode adm){
523 BOOL isValue = getValue(machine, adm, &ptr);
525 machine->regA &= ptr.value;
526 manZeroNeg(machine,machine->regA);
529 static void jmpASL(machine_6502 *machine, m6502_AddrMode adm){
531 BOOL isValue = getValue(machine, adm, &ptr);
533 machine->regP = setBit(machine->regP, CARRY_FL, bitOn(ptr.value, NEGATIVE_FL));
534 ptr.value = ptr.value << 1;
535 ptr.value = setBit(ptr.value, CARRY_FL, 0);
536 memStoreByte(machine, ptr.addr, ptr.value);
537 manZeroNeg(machine,ptr.value);
539 else { /* Accumulator */
540 machine->regP = setBit(machine->regP, CARRY_FL, bitOn(machine->regA, NEGATIVE_FL));
541 machine->regA = machine->regA << 1;
542 machine->regA = setBit(machine->regA, CARRY_FL, 0);
543 manZeroNeg(machine,machine->regA);
548 static void jmpBIT(machine_6502 *machine, m6502_AddrMode adm){
550 BOOL isValue = getValue(machine, adm, &ptr);
552 machine->regP = setBit(machine->regP, ZERO_FL, !(ptr.value & machine->regA));
553 machine->regP = setBit(machine->regP, OVERFLOW_FL, bitOn(ptr.value, OVERFLOW_FL));
554 machine->regP = setBit(machine->regP, NEGATIVE_FL, bitOn(ptr.value, NEGATIVE_FL));
558 static void jumpBranch(machine_6502 *machine, Bit16 offset){
560 machine->regPC = machine->regPC - (0x100 - offset);
562 machine->regPC = machine->regPC + offset;
565 static void jmpBPL(machine_6502 *machine, m6502_AddrMode adm){
567 BOOL isValue = getValue(machine, adm, &ptr);
569 if (bitOff(machine->regP,NEGATIVE_FL))
570 jumpBranch(machine, ptr.addr);
574 static void jmpBMI(machine_6502 *machine, m6502_AddrMode adm){
576 BOOL isValue = getValue(machine, adm, &ptr);
578 if (bitOn(machine->regP,NEGATIVE_FL))
579 jumpBranch(machine, ptr.addr);
583 static void jmpBVC(machine_6502 *machine, m6502_AddrMode adm){
585 BOOL isValue = getValue(machine, adm, &ptr);
587 if (bitOff(machine->regP,OVERFLOW_FL))
588 jumpBranch(machine, ptr.addr);
591 static void jmpBVS(machine_6502 *machine, m6502_AddrMode adm){
593 BOOL isValue = getValue(machine, adm, &ptr);
595 if (bitOn(machine->regP,OVERFLOW_FL))
596 jumpBranch(machine, ptr.addr);
599 static void jmpBCC(machine_6502 *machine, m6502_AddrMode adm){
601 BOOL isValue = getValue(machine, adm, &ptr);
603 if (bitOff(machine->regP,CARRY_FL))
604 jumpBranch(machine, ptr.addr);
607 static void jmpBCS(machine_6502 *machine, m6502_AddrMode adm){
609 BOOL isValue = getValue(machine, adm, &ptr);
611 if (bitOn(machine->regP,CARRY_FL))
612 jumpBranch(machine, ptr.addr);
615 static void jmpBNE(machine_6502 *machine, m6502_AddrMode adm){
617 BOOL isValue = getValue(machine, adm, &ptr);
619 if (bitOff(machine->regP, ZERO_FL))
620 jumpBranch(machine, ptr.addr);
623 static void jmpBEQ(machine_6502 *machine, m6502_AddrMode adm){
625 BOOL isValue = getValue(machine, adm, &ptr);
627 if (bitOn(machine->regP, ZERO_FL))
628 jumpBranch(machine, ptr.addr);
631 static void doCompare(machine_6502 *machine, Bit16 reg, Pointer *ptr){
632 machine->regP = setBit(machine->regP,CARRY_FL, ((reg + ptr->value) > 0xff));
633 manZeroNeg(machine,(reg - ptr->value));
636 static void jmpCMP(machine_6502 *machine, m6502_AddrMode adm){
638 BOOL isValue = getValue(machine, adm, &ptr);
640 doCompare(machine,machine->regA,&ptr);
643 static void jmpCPX(machine_6502 *machine, m6502_AddrMode adm){
645 BOOL isValue = getValue(machine, adm, &ptr);
647 doCompare(machine,machine->regX,&ptr);
650 static void jmpCPY(machine_6502 *machine, m6502_AddrMode adm){
652 BOOL isValue = getValue(machine, adm, &ptr);
654 doCompare(machine,machine->regY,&ptr);
657 static void jmpDEC(machine_6502 *machine, m6502_AddrMode adm){
659 BOOL isValue = getValue(machine, adm, &ptr);
665 memStoreByte(machine, ptr.addr, ptr.value);
666 manZeroNeg(machine,ptr.value);
669 static void jmpEOR(machine_6502 *machine, m6502_AddrMode adm){
671 BOOL isValue = getValue(machine, adm, &ptr);
673 machine->regA ^= ptr.value;
674 manZeroNeg(machine, machine->regA);
677 static void jmpCLC(machine_6502 *machine, m6502_AddrMode adm){
678 machine->regP = setBit(machine->regP, CARRY_FL, 0);
681 static void jmpSEC(machine_6502 *machine, m6502_AddrMode adm){
682 machine->regP = setBit(machine->regP, CARRY_FL, 1);
685 static void jmpCLI(machine_6502 *machine, m6502_AddrMode adm){
686 machine->regP = setBit(machine->regP, INTERRUPT_FL, 0);
689 static void jmpSEI(machine_6502 *machine, m6502_AddrMode adm){
690 machine->regP = setBit(machine->regP, INTERRUPT_FL, 1);
693 static void jmpCLV(machine_6502 *machine, m6502_AddrMode adm){
694 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
697 static void jmpCLD(machine_6502 *machine, m6502_AddrMode adm){
698 machine->regP = setBit(machine->regP, DECIMAL_FL, 0);
701 static void jmpSED(machine_6502 *machine, m6502_AddrMode adm){
702 machine->regP = setBit(machine->regP, DECIMAL_FL, 1);
705 static void jmpINC(machine_6502 *machine, m6502_AddrMode adm){
707 BOOL isValue = getValue(machine, adm, &ptr);
709 ptr.value = (ptr.value + 1) & 0xFF;
710 memStoreByte(machine, ptr.addr, ptr.value);
711 manZeroNeg(machine,ptr.value);
714 static void jmpJMP(machine_6502 *machine, m6502_AddrMode adm){
716 BOOL isValue = getValue(machine, adm, &ptr);
718 machine->regPC = ptr.addr;
721 static void jmpJSR(machine_6502 *machine, m6502_AddrMode adm){
723 /* Move past the 2 byte parameter. JSR is always followed by
725 Bit16 currAddr = machine->regPC + 2;
726 BOOL isValue = getValue(machine, adm, &ptr);
728 stackPush(machine, (currAddr >> 8) & 0xff);
729 stackPush(machine, currAddr & 0xff);
730 machine->regPC = ptr.addr;
733 static void jmpLDA(machine_6502 *machine, m6502_AddrMode adm){
735 BOOL isValue = getValue(machine, adm, &ptr);
737 machine->regA = ptr.value;
738 manZeroNeg(machine, machine->regA);
741 static void jmpLDX(machine_6502 *machine, m6502_AddrMode adm){
743 BOOL isValue = getValue(machine, adm, &ptr);
745 machine->regX = ptr.value;
746 manZeroNeg(machine, machine->regX);
749 static void jmpLDY(machine_6502 *machine, m6502_AddrMode adm){
751 BOOL isValue = getValue(machine, adm, &ptr);
753 machine->regY = ptr.value;
754 manZeroNeg(machine, machine->regY);
757 static void jmpLSR(machine_6502 *machine, m6502_AddrMode adm){
759 BOOL isValue = getValue(machine, adm, &ptr);
762 setBit(machine->regP, CARRY_FL,
763 bitOn(ptr.value, CARRY_FL));
764 ptr.value = ptr.value >> 1;
765 ptr.value = setBit(ptr.value,NEGATIVE_FL,0);
766 memStoreByte(machine,ptr.addr,ptr.value);
767 manZeroNeg(machine,ptr.value);
769 else { /* Accumulator */
771 setBit(machine->regP, CARRY_FL,
772 bitOn(machine->regA, CARRY_FL));
773 machine->regA = machine->regA >> 1;
774 machine->regA = setBit(machine->regA,NEGATIVE_FL,0);
775 manZeroNeg(machine,ptr.value);
779 static void jmpNOP(machine_6502 *machine, m6502_AddrMode adm){
783 static void jmpORA(machine_6502 *machine, m6502_AddrMode adm){
785 BOOL isValue = getValue(machine, adm, &ptr);
787 machine->regA |= ptr.value;
788 manZeroNeg(machine,machine->regA);
791 static void jmpTAX(machine_6502 *machine, m6502_AddrMode adm){
792 machine->regX = machine->regA;
793 manZeroNeg(machine,machine->regX);
796 static void jmpTXA(machine_6502 *machine, m6502_AddrMode adm){
797 machine->regA = machine->regX;
798 manZeroNeg(machine,machine->regA);
801 static void jmpDEX(machine_6502 *machine, m6502_AddrMode adm){
802 if (machine->regX > 0)
805 machine->regX = 0xFF;
806 manZeroNeg(machine, machine->regX);
809 static void jmpINX(machine_6502 *machine, m6502_AddrMode adm){
810 Bit16 value = machine->regX + 1;
811 machine->regX = value & 0xFF;
812 manZeroNeg(machine, machine->regX);
815 static void jmpTAY(machine_6502 *machine, m6502_AddrMode adm){
816 machine->regY = machine->regA;
817 manZeroNeg(machine, machine->regY);
820 static void jmpTYA(machine_6502 *machine, m6502_AddrMode adm){
821 machine->regA = machine->regY;
822 manZeroNeg(machine, machine->regA);
825 static void jmpDEY(machine_6502 *machine, m6502_AddrMode adm){
826 if (machine->regY > 0)
829 machine->regY = 0xFF;
830 manZeroNeg(machine, machine->regY);
833 static void jmpINY(machine_6502 *machine, m6502_AddrMode adm){
834 Bit16 value = machine->regY + 1;
835 machine->regY = value & 0xff;
836 manZeroNeg(machine, machine->regY);
839 static void jmpROR(machine_6502 *machine, m6502_AddrMode adm){
842 BOOL isValue = getValue(machine, adm, &ptr);
844 cf = bitOn(machine->regP, CARRY_FL);
846 setBit(machine->regP, CARRY_FL,
847 bitOn(ptr.value, CARRY_FL));
848 ptr.value = ptr.value >> 1;
849 ptr.value = setBit(ptr.value, NEGATIVE_FL, cf);
850 memStoreByte(machine, ptr.addr, ptr.value);
851 manZeroNeg(machine, ptr.value);
854 cf = bitOn(machine->regP, CARRY_FL);
856 setBit(machine->regP, CARRY_FL,
857 bitOn(machine->regA, CARRY_FL));
858 machine->regA = machine->regA >> 1;
859 machine->regA = setBit(machine->regA, NEGATIVE_FL, cf);
860 manZeroNeg(machine, machine->regA);
864 static void jmpROL(machine_6502 *machine, m6502_AddrMode adm){
867 BOOL isValue = getValue(machine, adm, &ptr);
869 cf = bitOn(machine->regP, CARRY_FL);
871 setBit(machine->regP, CARRY_FL,
872 bitOn(ptr.value, NEGATIVE_FL));
873 ptr.value = ptr.value << 1;
874 ptr.value = setBit(ptr.value, CARRY_FL, cf);
875 memStoreByte(machine, ptr.addr, ptr.value);
876 manZeroNeg(machine, ptr.value);
879 cf = bitOn(machine->regP, CARRY_FL);
881 setBit(machine->regP, CARRY_FL,
882 bitOn(machine->regA,NEGATIVE_FL));
883 machine->regA = machine->regA << 1;
884 machine->regA = setBit(machine->regA, CARRY_FL, cf);
885 manZeroNeg(machine, machine->regA);
889 static void jmpRTI(machine_6502 *machine, m6502_AddrMode adm){
890 machine->regP = stackPop(machine);
891 machine->regPC = stackPop(machine);
894 static void jmpRTS(machine_6502 *machine, m6502_AddrMode adm){
896 BOOL isValue = getValue(machine, adm, &ptr);
897 Bit16 nr = stackPop(machine);
898 Bit16 nl = stackPop(machine);
899 warnValue(! isValue);
900 machine->regPC = (nl << 8) | nr;
903 static void jmpSBC(machine_6502 *machine, m6502_AddrMode adm){
906 Bit8 c = bitOn(machine->regP, CARRY_FL);
908 BOOL isValue = getValue(machine, adm, &ptr);
910 /*vflag = (bitOn(machine->regA,NEGATIVE_FL) &&
911 bitOn(ptr.value, NEGATIVE_FL));*/
913 if (bitOn(machine->regP, DECIMAL_FL)) {
914 Bit8 ar = nibble(machine->regA, RIGHT);
915 Bit8 br = nibble(ptr.value, RIGHT);
916 Bit8 al = nibble(machine->regA, LEFT);
917 Bit8 bl = nibble(ptr.value, LEFT);
919 tmp = 0xf + ar - br + c;
930 machine->regP = setBit(machine->regP, CARRY_FL, 0);
931 if (bitOn(machine->regP, OVERFLOW_FL) && w < 0x80)
932 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
936 machine->regP = setBit(machine->regP, CARRY_FL, 1);
937 if (bitOn(machine->regP, OVERFLOW_FL) && w >= 0x180)
938 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
941 } /* end decimal mode */
943 w = 0xff + machine->regA - ptr.value + c;
945 machine->regP = setBit(machine->regP, CARRY_FL, 0);
946 if (bitOn(machine->regP, OVERFLOW_FL) && w < 0x80)
947 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
950 machine->regP = setBit(machine->regP, CARRY_FL, 1);
951 if (bitOn(machine->regP, OVERFLOW_FL) && w >= 0x180)
952 machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
956 manZeroNeg(machine,machine->regA);
959 static void jmpSTA(machine_6502 *machine, m6502_AddrMode adm){
961 BOOL isValue = getValue(machine, adm, &ptr);
963 memStoreByte(machine,ptr.addr,machine->regA);
966 static void jmpTXS(machine_6502 *machine, m6502_AddrMode adm){
967 stackPush(machine,machine->regX);
970 static void jmpTSX(machine_6502 *machine, m6502_AddrMode adm){
971 machine->regX = stackPop(machine);
972 manZeroNeg(machine, machine->regX);
975 static void jmpPHA(machine_6502 *machine, m6502_AddrMode adm){
976 stackPush(machine, machine->regA);
979 static void jmpPLA(machine_6502 *machine, m6502_AddrMode adm){
980 machine->regA = stackPop(machine);
981 manZeroNeg(machine, machine->regA);
984 static void jmpPHP(machine_6502 *machine, m6502_AddrMode adm){
985 stackPush(machine,machine->regP);
988 static void jmpPLP(machine_6502 *machine, m6502_AddrMode adm){
989 machine->regP = stackPop(machine);
990 machine->regP = setBit(machine->regP, FUTURE_FL, 1);
993 static void jmpSTX(machine_6502 *machine, m6502_AddrMode adm){
995 BOOL isValue = getValue(machine, adm, &ptr);
997 memStoreByte(machine,ptr.addr,machine->regX);
1000 static void jmpSTY(machine_6502 *machine, m6502_AddrMode adm){
1002 BOOL isValue = getValue(machine, adm, &ptr);
1004 memStoreByte(machine,ptr.addr,machine->regY);
1010 static void assignOpCodes(m6502_Opcodes *opcodes){
1012 #define SETOP(num, _name, _Imm, _ZP, _ZPX, _ZPY, _ABS, _ABSX, _ABSY, _INDX, _INDY, _SNGL, _BRA, _func) \
1013 {opcodes[num].name[3] = '\0'; \
1014 strncpy(opcodes[num].name, _name, 3); opcodes[num].Imm = _Imm; opcodes[num].ZP = _ZP; \
1015 opcodes[num].ZPX = _ZPX; opcodes[num].ZPY = _ZPY; opcodes[num].ABS = _ABS; \
1016 opcodes[num].ABSX = _ABSX; opcodes[num].ABSY = _ABSY; opcodes[num].INDX = _INDX; \
1017 opcodes[num].INDY = _INDY; opcodes[num].SNGL = _SNGL; opcodes[num].BRA = _BRA; \
1018 opcodes[num].func = _func;}
1020 /* OPCODE Imm ZP ZPX ZPY ABS ABSX ABSY INDX INDY SGNL BRA Jump Function*/
1021 SETOP( 0, "ADC", 0x69, 0x65, 0x75, 0x00, 0x6d, 0x7d, 0x79, 0x61, 0x71, 0x00, 0x00, jmpADC);
1022 SETOP( 1, "AND", 0x29, 0x25, 0x35, 0x31, 0x2d, 0x3d, 0x39, 0x00, 0x00, 0x00, 0x00, jmpAND);
1023 SETOP( 2, "ASL", 0x00, 0x06, 0x16, 0x00, 0x0e, 0x1e, 0x00, 0x00, 0x00, 0x0a, 0x00, jmpASL);
1024 SETOP( 3, "BIT", 0x00, 0x24, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpBIT);
1025 SETOP( 4, "BPL", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, jmpBPL);
1026 SETOP( 5, "BMI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, jmpBMI);
1027 SETOP( 6, "BVC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, jmpBVC);
1028 SETOP( 7, "BVS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, jmpBVS);
1029 SETOP( 8, "BCC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, jmpBCC);
1030 SETOP( 9, "BCS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, jmpBCS);
1031 SETOP(10, "BNE", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, jmpBNE);
1032 SETOP(11, "BEQ", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, jmpBEQ);
1033 SETOP(12, "CMP", 0xc9, 0xc5, 0xd5, 0x00, 0xcd, 0xdd, 0xd9, 0xc1, 0xd1, 0x00, 0x00, jmpCMP);
1034 SETOP(13, "CPX", 0xe0, 0xe4, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpCPX);
1035 SETOP(14, "CPY", 0xc0, 0xc4, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpCPY);
1036 SETOP(15, "DEC", 0x00, 0xc6, 0xd6, 0x00, 0xce, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, jmpDEC);
1037 SETOP(16, "EOR", 0x49, 0x45, 0x55, 0x00, 0x4d, 0x5d, 0x59, 0x41, 0x51, 0x00, 0x00, jmpEOR);
1038 SETOP(17, "CLC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, jmpCLC);
1039 SETOP(18, "SEC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, jmpSEC);
1040 SETOP(19, "CLI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, jmpCLI);
1041 SETOP(20, "SEI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, jmpSEI);
1042 SETOP(21, "CLV", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, jmpCLV);
1043 SETOP(22, "CLD", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, jmpCLD);
1044 SETOP(23, "SED", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, jmpSED);
1045 SETOP(24, "INC", 0x00, 0xe6, 0xf6, 0x00, 0xee, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, jmpINC);
1046 SETOP(25, "JMP", 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpJMP);
1047 SETOP(26, "JSR", 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpJSR);
1048 SETOP(27, "LDA", 0xa9, 0xa5, 0xb5, 0x00, 0xad, 0xbd, 0xb9, 0xa1, 0xb1, 0x00, 0x00, jmpLDA);
1049 SETOP(28, "LDX", 0xa2, 0xa6, 0x00, 0xb6, 0xae, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, jmpLDX);
1050 SETOP(29, "LDY", 0xa0, 0xa4, 0xb4, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, jmpLDY);
1051 SETOP(30, "LSR", 0x00, 0x46, 0x56, 0x00, 0x4e, 0x5e, 0x00, 0x00, 0x00, 0x4a, 0x00, jmpLSR);
1052 SETOP(31, "NOP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, jmpNOP);
1053 SETOP(32, "ORA", 0x09, 0x05, 0x15, 0x00, 0x0d, 0x1d, 0x19, 0x01, 0x11, 0x00, 0x00, jmpORA);
1054 SETOP(33, "TAX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, jmpTAX);
1055 SETOP(34, "TXA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, jmpTXA);
1056 SETOP(35, "DEX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x00, jmpDEX);
1057 SETOP(36, "INX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, jmpINX);
1058 SETOP(37, "TAY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, jmpTAY);
1059 SETOP(38, "TYA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, jmpTYA);
1060 SETOP(39, "DEY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, jmpDEY);
1061 SETOP(40, "INY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, jmpINY);
1062 SETOP(41, "ROR", 0x00, 0x66, 0x76, 0x00, 0x6e, 0x7e, 0x00, 0x00, 0x00, 0x6a, 0x00, jmpROR);
1063 SETOP(42, "ROL", 0x00, 0x26, 0x36, 0x00, 0x2e, 0x3e, 0x00, 0x00, 0x00, 0x2a, 0x00, jmpROL);
1064 SETOP(43, "RTI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, jmpRTI);
1065 SETOP(44, "RTS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, jmpRTS);
1066 SETOP(45, "SBC", 0xe9, 0xe5, 0xf5, 0x00, 0xed, 0xfd, 0xf9, 0xe1, 0xf1, 0x00, 0x00, jmpSBC);
1067 SETOP(46, "STA", 0x00, 0x85, 0x95, 0x00, 0x8d, 0x9d, 0x99, 0x81, 0x91, 0x00, 0x00, jmpSTA);
1068 SETOP(47, "TXS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, jmpTXS);
1069 SETOP(48, "TSX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, jmpTSX);
1070 SETOP(49, "PHA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, jmpPHA);
1071 SETOP(50, "PLA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, jmpPLA);
1072 SETOP(51, "PHP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, jmpPHP);
1073 SETOP(52, "PLP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, jmpPLP);
1074 SETOP(53, "STX", 0x00, 0x86, 0x00, 0x96, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpSTX);
1075 SETOP(54, "STY", 0x00, 0x84, 0x94, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpSTY);
1076 SETOP(55, "---", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, NULL);
1079 static void buildIndexCache(machine_6502 *machine){
1081 for (i = 0; i < NUM_OPCODES; i++) {
1082 if (machine->opcodes[i].Imm != 0x00){
1083 machine->opcache[machine->opcodes[i].Imm].adm = IMMEDIATE_VALUE;
1084 machine->opcache[machine->opcodes[i].Imm].index = i;
1086 if (machine->opcodes[i].ZP != 0x00){
1087 machine->opcache[machine->opcodes[i].ZP].adm = ZERO;
1088 machine->opcache[machine->opcodes[i].ZP].index = i;
1090 if (machine->opcodes[i].ZPX != 0x00){
1091 machine->opcache[machine->opcodes[i].ZPX].adm = ZERO_X;
1092 machine->opcache[machine->opcodes[i].ZPX].index = i;;
1094 if (machine->opcodes[i].ZPY != 0x00){
1095 machine->opcache[machine->opcodes[i].ZPY].adm = ZERO_Y;
1096 machine->opcache[machine->opcodes[i].ZPY].index = i;;
1098 if (machine->opcodes[i].ABS != 0x00){
1099 machine->opcache[machine->opcodes[i].ABS].adm = ABS_VALUE;
1100 machine->opcache[machine->opcodes[i].ABS].index = i;;
1102 if (machine->opcodes[i].ABSX != 0x00){
1103 machine->opcache[machine->opcodes[i].ABSX].adm = ABS_X;
1104 machine->opcache[machine->opcodes[i].ABSX].index = i;;
1106 if (machine->opcodes[i].ABSY != 0x00){
1107 machine->opcache[machine->opcodes[i].ABSY].adm = ABS_Y;
1108 machine->opcache[machine->opcodes[i].ABSY].index = i;;
1110 if (machine->opcodes[i].INDX != 0x00){
1111 machine->opcache[machine->opcodes[i].INDX].adm = INDIRECT_X;
1112 machine->opcache[machine->opcodes[i].INDX].index = i;;
1114 if (machine->opcodes[i].INDY != 0x00){
1115 machine->opcache[machine->opcodes[i].INDY].adm = INDIRECT_Y;
1116 machine->opcache[machine->opcodes[i].INDY].index = i;;
1118 if (machine->opcodes[i].SNGL != 0x00){
1119 machine->opcache[machine->opcodes[i].SNGL].adm = SINGLE;
1120 machine->opcache[machine->opcodes[i].SNGL].index = i;
1122 if (machine->opcodes[i].BRA != 0x00){
1123 machine->opcache[machine->opcodes[i].BRA].adm = ABS_OR_BRANCH;
1124 machine->opcache[machine->opcodes[i].BRA].index = i;
1129 /* opIndex() - Search the opcode table for a match. If found return
1130 the index into the optable and the address mode of the opcode. If
1131 the opcode is not found then return -1. */
1132 static int opIndex(machine_6502 *machine, Bit8 opcode, m6502_AddrMode *adm){
1133 /* XXX could catch errors by setting a addressmode of error or something */
1134 *adm = machine->opcache[opcode].adm;
1135 return machine->opcache[opcode].index;
1139 /* Assembly parser */
1141 static Param *newParam(void){
1145 newp = (Param *) ecalloc(1, sizeof(Param));
1146 newp->type = SINGLE;
1147 for (i = 0; i < MAX_PARAM_VALUE; i++)
1150 newp->label = ecalloc(MAX_LABEL_LEN,sizeof(char));
1155 /* Copy the fields from p2 to p1 */
1156 static void copyParam(Param *p1, Param *p2){
1158 strncpy(p1->label,p2->label,MAX_LABEL_LEN);
1159 for(i = 0; i < MAX_PARAM_VALUE; i++)
1160 p1->value[i] = p2->value[i];
1162 p1->type = p2->type;
1165 static Label *newLabel(void){
1168 newp = (Label *) ecalloc(1, sizeof(Label));
1170 newp->label = ecalloc(MAX_LABEL_LEN,sizeof(char));
1175 static AsmLine *newAsmLine(char *cmd, char *label, BOOL decl, Param *param, int lc)
1179 newp = (AsmLine *) ecalloc(1, sizeof(AsmLine));
1180 newp->labelDecl = decl;
1181 newp->label = newLabel();
1182 strncpy(newp->label->label,label,MAX_LABEL_LEN);
1183 newp->command = estrdup(cmd);
1184 newp->param = newParam();
1185 copyParam(newp->param, param);
1190 static AsmLine *addend(AsmLine *listp, AsmLine *newp)
1195 for (p =listp; p->next != NULL; p = p->next)
1201 static BOOL apply(AsmLine *listp, BOOL(*fn)(AsmLine*, void*), void *arg)
1206 for (p = listp; p != NULL; p = p->next)
1212 static void freeParam(Param *param){
1217 static void freeLabel(Label *label){
1222 static void freeallAsmLine(AsmLine *listp)
1225 for(; listp != NULL; listp = next){
1227 freeParam(listp->param);
1228 freeLabel(listp->label);
1229 free(listp->command);
1234 static BOOL addvalue(Param *param,Bit32 value){
1235 /* jwz: suppress "0 <= unsigned" warning */
1236 if (/*0 <= param->vp &&*/ param->vp < MAX_PARAM_VALUE) {
1237 param->value[param->vp++] = value;
1241 fprintf(stderr,"Wrong number of parameters: %d. The limit is %d\n",param->vp+1, MAX_PARAM_VALUE);
1246 static void parseError(char *s){
1247 fprintf(stderr,"6502 Syntax Error: %s\n", s);
1250 /* stoupper() - Destructivley modifies the string making all letters upper case*/
1251 static void stoupper(char **s){
1253 while((*s)[i] != '\0'){
1254 (*s)[i] = toupper((*s)[i]);
1259 static BOOL isWhite(char c){
1260 return (c == '\r' || c == '\t' || c == ' ');
1263 static void skipSpace(char **s){
1264 for(; isWhite(**s); (*s)++)
1268 /* nullify() - fills a string with upto sourceLength null characters. */
1269 static void nullify(char *token, unsigned int sourceLength){
1271 while (i < sourceLength)
1275 static BOOL isBlank(const char *token){
1276 return (token[0] == '\0');
1279 static BOOL isCommand(machine_6502 *machine, const char *token){
1282 while (i < NUM_OPCODES) {
1283 if (strcmp(machine->opcodes[i].name,token) == 0)
1288 if (strcmp(token, "DCB") == 0) return TRUE;
1292 /* hasChar() - Check to see if the current line has a certain
1294 static BOOL hasChar(char *s, char c){
1295 for(; *s != '\0' && *s != '\n'; s++) {
1302 static BOOL ishexdigit(char c){
1306 char c1 = toupper(c);
1307 return ('A' <= c1 && c1 <= 'F');
1311 /* isCmdChar() - Is this a valid character for a command. All of the
1312 command are alpha except for the entry point code that is "*=" */
1313 static BOOL isCmdChar(char c){
1314 return (isalpha(c) || c == '*' || c == '=');
1318 /* command() - parse a command from the source code. We pass along a
1319 machine so the opcode can be validated. */
1320 static BOOL command(machine_6502 *machine, char **s, char **cmd){
1323 for(;isCmdChar(**s) && i < MAX_CMD_LEN; (*s)++)
1326 return TRUE; /* Could be a blank line. */
1327 else if (strcmp(*cmd,"*=") == 0)
1328 return TRUE; /* This is an entry point. */
1330 return isCommand(machine,*cmd);
1333 static BOOL declareLabel(char **s, char **label){
1336 for(;**s != ':' && **s != '\n' && **s != '\0'; (*s)++){
1339 (*label)[i++] = **s;
1342 return FALSE; /* Current line has to have a label */
1343 else if (**s == ':'){
1344 (*s)++; /* Skip colon */
1351 static BOOL parseHex(char **s, Bit32 *value){
1352 enum { MAX_HEX_LEN = 5 };
1354 char *hex = ecalloc(MAX_HEX_LEN, sizeof(char));
1357 (*s)++; /* move pass $ */
1358 for(; ishexdigit(**s) && i < MAX_HEX_LEN; (*s)++)
1361 *value = strtol(hex,NULL,16);
1369 static BOOL parseDec(char **s, Bit32 *value){
1370 enum { MAX_DEC_LEN = 4 };
1371 char *dec = ecalloc(MAX_DEC_LEN, sizeof(char));
1373 for(i = 0; isdigit(**s) && i < MAX_DEC_LEN; (*s)++)
1387 static BOOL parseValue(char **s, Bit32 *value){
1390 return parseHex(s, value);
1392 return parseDec(s, value);
1395 static BOOL paramLabel(char **s, char **label){
1397 for(i = 0; (isalnum(**s) || **s == '_') && i < MAX_LABEL_LEN; (*s)++)
1398 (*label)[i++] = **s;
1406 static BOOL immediate(char **s, Param *param){
1410 (*s)++; /*Move past hash */
1411 if (**s == '<' || **s == '>'){
1412 char *label = ecalloc(MAX_LABEL_LEN, sizeof(char));
1413 param->type = (**s == '<') ? IMMEDIATE_LESS : IMMEDIATE_GREAT;
1414 (*s)++; /* move past < or > */
1415 if (paramLabel(s, &label)){
1416 int ln = strlen(label) + 1;
1417 strncpy(param->label, label, ln);
1425 if (parseValue(s, &value)){
1427 parseError("Immediate value is too large.");
1430 param->type = IMMEDIATE_VALUE;
1431 return addvalue(param, value);
1437 static BOOL isDirection(char c){
1438 return (c == 'X' || c == 'Y');
1441 static BOOL getDirection(char **s, char *direction){
1446 if (isDirection(**s)){
1455 static BOOL indirect(char **s, Param *param){
1463 if (! parseHex(s,&value))
1466 parseError("Indirect value is too large.");
1469 if (!addvalue(param, value))
1474 if (getDirection(s,&c)) {
1476 param->type = INDIRECT_Y;
1481 else if (getDirection(s, &c)){
1486 param->type = INDIRECT_X;
1494 static BOOL dcbValue(char **s, Param *param){
1496 if (! parseValue(s,&val))
1502 if (!addvalue(param,val))
1505 param->type = DCB_PARAM;
1510 return dcbValue(s, param);
1516 static BOOL value(char **s, Param *param){
1521 if (! parseValue(s,&val))
1525 dir = getDirection(s,&c);
1526 if (!addvalue(param,val))
1531 param->type = ABS_X;
1533 param->type = ABS_Y;
1538 param->type = ABS_VALUE;
1541 param->type = ZERO_X;
1543 param->type = ZERO_Y;
1553 static BOOL label(char **s, Param *param){
1554 char *label = ecalloc(MAX_LABEL_LEN, sizeof(char));
1556 BOOL labelOk = FALSE;
1557 if (paramLabel(s, &label)){
1559 param->type = ABS_OR_BRANCH;
1560 if (getDirection(s, &c)){
1562 param->type = ABS_LABEL_X;
1564 param->type = ABS_LABEL_Y;
1568 strncpy(param->label,label,MAX_LABEL_LEN);
1574 static BOOL parameter(const char *cmd, char **s, Param *param){
1576 if (**s == '\0' || **s == '\n')
1578 else if (**s == '#')
1579 return immediate(s,param);
1580 else if (**s == '(')
1581 return indirect(s,param);
1582 else if (**s == '$' || isdigit(**s)){
1583 if (strcmp(cmd, "DCB") == 0)
1584 return dcbValue(s,param);
1586 return value(s,param);
1588 else if (isalpha(**s))
1589 return label(s ,param);
1591 return FALSE; /* Invalid Parameter */
1594 static void comment(char **s){
1597 for(;**s != '\n' && **s != '\0'; (*s)++)
1601 static void initParam(Param *param){
1603 param->type = SINGLE;
1604 for(i = 0; i < MAX_PARAM_VALUE; i++)
1605 param->value[i] = 0;
1607 nullify(param->label,MAX_LABEL_LEN);
1611 static AsmLine *parseAssembly(machine_6502 *machine, BOOL *codeOk, const char *code){
1613 char *cmd = ecalloc(MAX_CMD_LEN, sizeof(char));
1614 char *label = ecalloc(MAX_LABEL_LEN, sizeof(char));
1615 char *start; /*pointer to the start of the code.*/
1616 unsigned int lc = 1;
1619 AsmLine *listp = NULL;
1627 while(*s != '\0' && *codeOk){
1629 nullify(cmd, MAX_CMD_LEN);
1630 nullify(label, MAX_LABEL_LEN);
1637 continue; /* blank line */
1639 else if (*s == '\0')
1640 continue; /* no newline at the end of the code */
1641 else if (hasChar(s,':')){
1643 if(! declareLabel(&s,&label)){
1649 if(!command(machine, &s, &cmd)){
1655 if(!parameter(cmd, &s, param)){
1661 if (*s == '\n' || *s == '\0'){
1663 asmm = newAsmLine(cmd,label,decl,param,lc);
1664 listp = addend(listp,asmm);
1672 fprintf(stderr,"Syntax error at line %u\n", lc);
1681 /* fileToBuffer() - Allocates a buffer and loads all of the file into memory. */
1682 static char *fileToBuffer(const char *filename){
1683 const int defaultSize = 1024;
1686 int size = defaultSize;
1688 char *buffer = ecalloc(defaultSize,sizeof(char));
1690 if (!buffer) abort();
1692 ifp = fopen(filename, "rb");
1695 while((c = getc(ifp)) != EOF){
1698 size += defaultSize;
1699 buffer = realloc(buffer, size);
1700 if (buffer == NULL) {
1706 buffer = realloc(buffer, i+2);
1707 if (!buffer) abort();
1708 /* Make sure we have a line feed at the end */
1718 /* reset() - Reset CPU and memory. */
1719 static void reset(machine_6502 *machine){
1721 for ( y = 0; y < 32; y++ ){
1722 for (x = 0; x < 32; x++){
1723 machine->screen[x][y] = 0;
1727 for(x=0; x < MEM_64K; x++)
1728 machine->memory[x] = 0;
1730 machine->codeCompiledOK = FALSE;
1734 machine->regP = setBit(machine->regP, FUTURE_FL, 1);
1735 machine->defaultCodePC = machine->regPC = PROG_START;
1736 machine->regSP = STACK_TOP;
1737 machine->runForever = FALSE;
1738 machine->labelPtr = 0;
1739 machine->codeRunning = FALSE;
1742 /* hexDump() - Dump the memory to output */
1743 void m6502_hexDump(machine_6502 *machine, Bit16 start, Bit16 numbytes, FILE *output){
1746 for( i = 0; i < numbytes; i++){
1747 address = start + i;
1748 if ( (i&15) == 0 ) {
1749 fprintf(output,"\n%.4x: ", address);
1751 fprintf(output,"%.2x%s",machine->memory[address], (i & 1) ? " ":"");
1753 fprintf(output,"%s\n",(i&1)?"--":"");
1757 /* void save_program(machine_6502 *machine, char *filename){ */
1759 /* Bit16 pc = PROG_START; */
1760 /* Bit16 end = pc + machine->codeLen; */
1762 /* ofp = fopen(filename, "w"); */
1763 /* if (!ofp) abort(); */
1765 /* fprintf(ofp,"Bit8 prog[%d] =\n{",machine->codeLen); */
1767 /* while(pc < end) */
1768 /* fprintf(ofp,"0x%.2x,%s",machine->memory[pc++],n++%10?" ":"\n"); */
1769 /* fseek(ofp,-2,SEEK_CUR); */
1770 /* fprintf(ofp,"};\n"); */
1775 static BOOL translate(m6502_Opcodes *op,Param *param, machine_6502 *machine){
1776 switch(param->type){
1779 pushByte(machine, op->SNGL);
1781 fprintf(stderr,"%s needs a parameter.\n",op->name);
1785 case IMMEDIATE_VALUE:
1787 pushByte(machine, op->Imm);
1788 pushByte(machine, param->value[0]);
1792 fprintf(stderr,"%s does not take IMMEDIATE_VALUE parameters.\n",op->name);
1795 case IMMEDIATE_GREAT:
1797 pushByte(machine, op->Imm);
1798 pushByte(machine, param->lbladdr >> 8);
1802 fprintf(stderr,"%s does not take IMMEDIATE_GREAT parameters.\n",op->name);
1805 case IMMEDIATE_LESS:
1807 pushByte(machine, op->Imm);
1808 pushByte(machine, param->lbladdr & 0xFF);
1812 fprintf(stderr,"%s does not take IMMEDIATE_LESS parameters.\n",op->name);
1817 pushByte(machine, op->INDX);
1818 pushByte(machine, param->value[0]);
1822 fprintf(stderr,"%s does not take INDIRECT_X parameters.\n",op->name);
1827 pushByte(machine, op->INDY);
1828 pushByte(machine, param->value[0]);
1832 fprintf(stderr,"%s does not take INDIRECT_Y parameters.\n",op->name);
1837 pushByte(machine, op->ZP);
1838 pushByte(machine, param->value[0]);
1842 fprintf(stderr,"%s does not take ZERO parameters.\n",op->name);
1847 pushByte(machine, op->ZPX);
1848 pushByte(machine, param->value[0]);
1852 fprintf(stderr,"%s does not take ZERO_X parameters.\n",op->name);
1857 pushByte(machine, op->ZPY);
1858 pushByte(machine, param->value[0]);
1862 fprintf(stderr,"%s does not take ZERO_Y parameters.\n",op->name);
1867 pushByte(machine, op->ABS);
1868 pushWord(machine, param->value[0]);
1872 fprintf(stderr,"%s does not take ABS_VALUE parameters.\n",op->name);
1877 pushByte(machine, op->ABS);
1878 pushWord(machine, param->lbladdr);
1882 pushByte(machine, op->BRA);
1884 int diff = abs((int)param->lbladdr - (int)machine->defaultCodePC);
1885 int backward = (param->lbladdr < machine->defaultCodePC);
1886 pushByte(machine, (backward) ? 0xff - diff : diff - 1);
1890 fprintf(stderr,"%s does not take BRANCH parameters.\n",op->name);
1897 pushByte(machine, op->ABSX);
1898 pushWord(machine, param->value[0]);
1902 fprintf(stderr,"%s does not take ABS_X parameters.\n",op->name);
1907 pushByte(machine, op->ABSY);
1908 pushWord(machine, param->value[0]);
1912 fprintf(stderr,"%s does not take ABS_Y parameters.\n",op->name);
1917 pushByte(machine, op->ABSX);
1918 pushWord(machine, param->lbladdr);
1922 fprintf(stderr,"%s does not take ABS_LABEL_X parameters.\n",op->name);
1927 pushByte(machine, op->ABSY);
1928 pushWord(machine, param->lbladdr);
1932 fprintf(stderr,"%s does not take ABS_LABEL_Y parameters.\n",op->name);
1936 /* Handled elsewhere */
1942 /* compileLine() - Compile one line of code. Returns
1943 TRUE if it compile successfully. */
1944 static BOOL compileLine(AsmLine *asmline, void *args){
1945 machine_6502 *machine;
1947 if (isBlank(asmline->command)) return TRUE;
1948 if (strcmp("*=",asmline->command) == 0){
1949 machine->defaultCodePC = asmline->param->value[0];
1951 else if (strcmp("DCB",asmline->command) == 0){
1953 for(i = 0; i < asmline->param->vp; i++)
1954 pushByte(machine, asmline->param->value[i]);
1958 char *command = asmline->command;
1960 for(i = 0; i < NUM_OPCODES; i++){
1961 if (strcmp(machine->opcodes[i].name, command) == 0){
1962 op = machine->opcodes[i];
1966 if (i == NUM_OPCODES)
1967 return FALSE; /* unknow upcode */
1969 return translate(&op,asmline->param,machine);
1974 /* indexLabels() - Get the address for each label */
1975 static BOOL indexLabels(AsmLine *asmline, void *arg){
1976 machine_6502 *machine;
1980 oldDefault = machine->defaultCodePC;
1981 thisPC = machine->regPC;
1982 /* Figure out how many bytes this instruction takes */
1983 machine->codeLen = 0;
1985 if ( ! compileLine(asmline, machine) ){
1989 /* If the machine's defaultCodePC has changed then we encountered a
1990 *= which changes the load address. We need to initials our code
1991 *counter with the current default. */
1992 if (oldDefault == machine->defaultCodePC){
1993 machine->regPC += machine->codeLen;
1996 machine->regPC = machine->defaultCodePC;
1997 /*oldDefault = machine->defaultCodePC;*/
2000 if (asmline->labelDecl) {
2001 asmline->label->addr = thisPC;
2006 static BOOL changeParamLabelAddr(AsmLine *asmline, void *label){
2008 if (strcmp(asmline->param->label, la->label) == 0)
2009 asmline->param->lbladdr = la->addr;
2013 static BOOL linkit(AsmLine *asmline, void *asmlist){
2014 apply(asmlist,changeParamLabelAddr,asmline->label);
2018 /* linkLabels - Make sure all of the references to the labels contain
2020 static void linkLabels(AsmLine *asmlist){
2021 apply(asmlist,linkit,asmlist);
2024 /* compileCode() - Compile the current assembly code for the machine */
2025 static BOOL compileCode(machine_6502 *machine, const char *code){
2030 machine->defaultCodePC = machine->regPC = PROG_START;
2031 asmlist = parseAssembly(machine, &codeOk, code);
2034 /* First pass: Find the addresses for the labels */
2035 if (!apply(asmlist, indexLabels, machine))
2037 /* update label references */
2038 linkLabels(asmlist);
2040 #if 0 /* prints out some debugging information */
2043 if(asmlist != NULL){
2044 for (p = asmlist; p != NULL; p = p->next)
2045 fprintf(stderr,"%s lbl: %s addr: %x ParamLbl: %s ParamAddr: %x\n",
2046 p->command, p->label->label, p->label->addr,
2047 p->param->label, p->param->lbladdr);
2053 /* Second pass: translate the instructions */
2054 machine->codeLen = 0;
2055 /* Link label call push_byte which increments defaultCodePC.
2056 We need to reset it so the compiled code goes in the
2058 machine->defaultCodePC = PROG_START;
2059 if (!apply(asmlist, compileLine, machine))
2062 if (machine->defaultCodePC > PROG_START ){
2063 machine->memory[machine->defaultCodePC] = 0x00;
2067 fprintf(stderr,"No Code to run.\n");
2072 fprintf(stderr,"An error occured while parsing the file.\n");
2075 freeallAsmLine(asmlist);
2081 * execute() - Executes one instruction.
2082 * This is the main part of the CPU emulator.
2086 static void execute(machine_6502 *machine){
2091 if(!machine->codeRunning) return;
2093 opcode = popByte(machine);
2095 machine->codeRunning = FALSE;
2097 opidx = opIndex(machine,opcode,&adm);
2099 machine->opcodes[opidx].func(machine, adm);
2101 fprintf(stderr,"Invalid opcode!\n");
2103 if( (machine->regPC == 0) ||
2104 (!machine->codeRunning) ) {
2105 machine->codeRunning = FALSE;
2109 machine_6502 *m6502_build(void){
2110 machine_6502 *machine;
2111 machine = ecalloc(1, sizeof(machine_6502));
2112 assignOpCodes(machine->opcodes);
2113 buildIndexCache(machine);
2118 void m6502_destroy6502(machine_6502 *machine){
2123 void m6502_trace(machine_6502 *machine, FILE *output){
2124 Bit8 opcode = memReadByte(machine,machine->regPC);
2127 int opidx = opIndex(machine,opcode,&adm);
2128 int stacksz = STACK_TOP - machine->regSP;
2130 fprintf(output,"\n NVFBDIZC\nP: %d%d%d%d%d%d%d%d ",
2131 bitOn(machine->regP,NEGATIVE_FL),
2132 bitOn(machine->regP,OVERFLOW_FL),
2133 bitOn(machine->regP,FUTURE_FL),
2134 bitOn(machine->regP,BREAK_FL),
2135 bitOn(machine->regP,DECIMAL_FL),
2136 bitOn(machine->regP,INTERRUPT_FL),
2137 bitOn(machine->regP,ZERO_FL),
2138 bitOn(machine->regP,CARRY_FL));
2139 fprintf(output,"A: %.2x X: %.2x Y: %.2x SP: %.4x PC: %.4x\n",
2140 machine->regA, machine->regX, machine->regY, machine->regSP, machine->regPC);
2142 Bit16 pc = machine->regPC;
2143 fprintf(output,"\n%.4x:\t%s",machine->regPC, machine->opcodes[opidx].name);
2144 if (peekValue(machine, adm, &ptr, pc+1))
2145 fprintf(output,"\tAddress:%.4x\tValue:%.4x\n",
2146 ptr.addr,ptr.value);
2148 fprintf(output,"\n");
2150 fprintf(output,"STACK:");
2151 m6502_hexDump(machine,(STACK_TOP - stacksz) + 1, stacksz, output);
2155 void disassemble(machine_6502 *machine, FILE *output){
2157 increment the program counter
2159 loop until end of program. */
2166 Bit16 opc = machine->regPC;
2167 mem = calloc(20,sizeof(char));
2168 machine->regPC = PROG_START;
2170 addr = machine->regPC;
2171 opcode = popByte(machine);
2172 opidx = opIndex(machine,opcode,&adm);
2173 for (i = 0; i < 20; i++) mem[i] = '\0';
2174 dismem(machine, adm, mem);
2175 fprintf(output,"%x\t%s\t%s\n",
2176 addr,machine->opcodes[opidx].name,mem);
2177 }while((machine->regPC - PROG_START) < machine->codeLen); /*XXX - may need to change since defaultCodePC */
2179 machine->regPC = opc;
2185 void m6502_eval_file(machine_6502 *machine, const char *filename, m6502_Plotter plot, void *plotterState){
2188 machine->plot = plot;
2189 machine->plotterState = plotterState;
2191 code = fileToBuffer(filename);
2193 if (! compileCode(machine, code) ) abort();
2197 machine->defaultCodePC = machine->regPC = PROG_START;
2198 machine->codeRunning = TRUE;
2202 m6502_trace(machine, stdout);
2205 }while(machine->codeRunning);
2208 void m6502_start_eval_file(machine_6502 *machine, const char *filename, m6502_Plotter plot, void *plotterState){
2212 machine->plot = plot;
2213 machine->plotterState = plotterState;
2215 code = fileToBuffer(filename);
2217 if (! compileCode(machine, code) ) abort();
2221 machine->defaultCodePC = machine->regPC = PROG_START;
2222 machine->codeRunning = TRUE;
2225 #endif /* READ_FILES */
2227 void m6502_start_eval_string(machine_6502 *machine, const char *code,
2228 m6502_Plotter plot, void *plotterState){
2231 machine->plot = plot;
2232 machine->plotterState = plotterState;
2234 if (! compileCode(machine, code) ){
2235 fprintf(stderr,"Could not compile code.\n");
2238 machine->defaultCodePC = machine->regPC = PROG_START;
2239 machine->codeRunning = TRUE;
2243 /* void start_eval_binary(machine_6502 *machine, Bit8 *program, */
2244 /* unsigned int proglen, */
2245 /* Plotter plot, void *plotterState){ */
2246 /* unsigned int pc, n; */
2247 /* reset(machine); */
2248 /* machine->plot = plot; */
2249 /* machine->plotterState = plotterState; */
2251 /* machine->regPC = PROG_START; */
2252 /* pc = machine->regPC; */
2253 /* machine->codeLen = proglen; */
2255 /* while (n < proglen){ */
2256 /* machine->memory[pc++] = program[n++]; */
2258 /* machine->codeRunning = TRUE; */
2259 /* execute(machine); */
2262 void m6502_next_eval(machine_6502 *machine, int insno){
2264 for (i = 1; i < insno; i++){
2265 if (machine->codeRunning){
2267 trace(machine, stdout);