From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / hacks / asm6502.c
1 /*-*- indent-tabs-mode:nil -*- */
2 /* Copyright (C) 2007 Jeremy English <jhe@jeremyenglish.org>
3  * 
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 
10  * implied warranty.
11  * 
12  * Created: 12-April-2007 
13  */ 
14
15 /*
16       This is a port of the javascript 6502 assembler, compiler and
17       debugger. The orignal code was copyright 2006 by Stian Soreng -
18       www.6502asm.com
19
20       I changed the structure of the assembler in this version.
21 */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 /*#include <malloc.h>*/
26 #include <string.h>
27 #include <errno.h>
28 #include <stdarg.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <math.h>
32 #include <inttypes.h>
33 #include <unistd.h>
34
35 #include "yarandom.h"
36 #include "asm6502.h"
37
38 /*#ifdef DEBUGGER
39 #  define random rand
40 #endif*/
41
42 #ifndef HAVE_MOBILE
43 # define READ_FILES
44 #endif
45
46 typedef enum{
47   LEFT, RIGHT
48     } Side;
49
50 /* 
51
52 Bit Flags
53    _  _  _  _  _  _  _  _ 
54   |N||V||F||B||D||I||Z||C|
55    -  -  -  -  -  -  -  - 
56    7  6  5  4  3  2  1  0
57
58 */
59
60 typedef enum{
61       CARRY_FL = 0, ZERO_FL = 1, INTERRUPT_FL = 2, 
62         DECIMAL_FL = 3, BREAK_FL = 4, FUTURE_FL = 5,
63         OVERFLOW_FL = 6, NEGATIVE_FL = 7
64         } Flags;
65         
66
67 typedef BOOL (*CharTest) (char);
68
69 /* A jump function takes a pointer to the current machine and a
70    opcode. The opcode is needed to figure out the memory mode. */
71 /*typedef void (*JumpFunc) (machine_6502* AddrMode);*/
72
73 typedef struct {
74   m6502_AddrMode type;
75   Bit32 value[MAX_PARAM_VALUE];
76   unsigned int vp; /*value pointer, index into the value table.*/
77   char *label;
78   Bit32 lbladdr;
79 } Param;
80
81 typedef struct {
82   Bit32 addr; /* Address of the label */  
83   char *label; 
84 } Label;  
85
86 typedef struct AsmLine AsmLine;
87 struct AsmLine {
88   BOOL labelDecl; /* Does the line have a label declaration? */
89   Label *label;
90   char *command;
91   Param *param;
92   AsmLine *next; /* in list */
93 };
94
95 typedef struct {
96   Bit16 addr;
97   Bit16 value;
98 } Pointer;
99
100
101 /*static void *emalloc(size_t n) {
102   void *p = malloc(n);
103   if (! p) abort();
104   return p;
105 }*/
106
107 static void *ecalloc(uint32_t nelm, size_t nsize){
108   void *p = calloc(nelm, nsize);
109   if (!p) abort();
110   return p;
111 }
112
113 /* estrdup() - Allocates memory for a new string a returns a copy of the source sting in it. */
114 static char *estrdup(const char *source){
115   int ln = strlen(source) + 1;
116   char *s = ecalloc(ln, sizeof(char));
117   strncpy(s,source,ln);
118   return s;
119 }
120
121 static void checkAddress(Bit32 address){
122   /* XXX: Do we want to kill the program here? */
123   if (address >= MEM_64K)
124     fprintf(stderr, "Address %d is beyond 64k", address);
125 }
126
127 /*
128  *  stackPush() - Push byte to stack
129  *
130  */
131
132 static void stackPush(machine_6502 *machine, Bit8 value ) {
133   if(machine->regSP >= STACK_BOTTOM){
134     machine->memory[machine->regSP--] = value;
135   }
136   else{
137     fprintf(stderr, "The stack is full: %.4x\n", machine->regSP);
138     machine->codeRunning = FALSE;
139   }
140 }
141
142
143 /*
144  *  stackPop() - Pop byte from stack
145  *
146  */
147
148 static Bit8 stackPop(machine_6502 *machine) {
149   if (machine->regSP < STACK_TOP){
150     Bit8 value =machine->memory[++machine->regSP];
151     return value;
152   }
153   else {
154     /*    fprintf(stderr, "The stack is empty.\n"); xxx */
155     machine->codeRunning = FALSE;
156     return 0;
157   }
158 }
159
160 static void pushByte(machine_6502 *machine, Bit32 value ) {
161   Bit32 address = machine->defaultCodePC;
162   checkAddress(address);
163   machine->memory[address] = value & 0xff;
164   machine->codeLen++;
165   machine->defaultCodePC++;
166 }
167
168 /*
169  * pushWord() - Push a word using pushByte twice
170  *
171  */
172
173 static void pushWord(machine_6502 *machine, Bit16 value ) {
174   pushByte(machine, value & 0xff );
175   pushByte(machine, (value>>8) & 0xff );
176 }
177
178 /*
179  * popByte( machine_6502 *machine,) - Pops a byte
180  *
181  */
182
183 static Bit8 popByte( machine_6502 *machine) {
184   Bit8 value = machine->memory[machine->regPC];
185   machine->regPC++;
186   return value;
187 }
188
189 /*
190  * popWord() - Pops a word using popByte() twice
191  *
192  */
193
194 static int popWord(machine_6502 *machine) {
195   return popByte(machine) + (popByte(machine) << 8);
196 }
197
198
199 /*
200  * memReadByte() - Peek a byte, don't touch any registers
201  *
202  */
203
204 static int memReadByte( machine_6502 *machine, int addr ) {
205   if( addr == 0xfe ) return floor( random()%255 );
206   return machine->memory[addr];
207 }
208
209 static void updateDisplayPixel(machine_6502 *machine, Bit16 addr){
210   Bit8 idx = memReadByte(machine,addr) & 0x0f;
211   Bit8 x,y;
212   addr -= 0x200;
213   x = addr & 0x1f;
214   y = (addr >> 5);
215   if (machine->plot) {
216     machine->plot(x,y,idx,machine->plotterState);
217   }
218 }
219
220 /*
221  * memStoreByte() - Poke a byte, don't touch any registers
222  *
223  */
224
225 static void memStoreByte( machine_6502 *machine, int addr, int value ) {
226   machine->memory[ addr ] = (value & 0xff);
227   if( (addr >= 0x200) && (addr<=0x5ff) )
228     updateDisplayPixel(machine, addr );
229 }
230
231
232 \f
233 /* EMULATION CODE */
234
235 static Bit8 bitOn(Bit8 value,Flags bit){
236   Bit8 mask = 1;
237   mask = mask << bit;
238   return ((value & mask) > 0);
239 }
240
241 static Bit8 bitOff(Bit8 value, Flags bit){
242   return (! bitOn(value,bit));
243 }
244
245 static Bit8 setBit(Bit8 value, Flags bit, int on){
246   Bit8 onMask  = 1;
247   Bit8 offMask = 0xff;
248   onMask = onMask << bit;
249   offMask = offMask ^ onMask;
250   return ((on) ? value | onMask : value & offMask);
251 }
252
253 static Bit8 nibble(Bit8 value, Side side){
254   switch(side){
255   case LEFT:  return value & 0xf0;
256   case RIGHT: return value & 0xf;
257   default:
258     fprintf(stderr,"nibble unknown side\n");
259     return 0;
260   }
261 }
262
263
264 /* used for tracing. XXX: combined with function getvalue */
265 static BOOL peekValue(machine_6502 *machine, m6502_AddrMode adm, Pointer *pointer, Bit16 PC){
266   Bit8 zp;
267   pointer->value = 0;
268   pointer->addr = 0;
269   switch(adm){
270   case SINGLE:
271     return FALSE;
272   case IMMEDIATE_LESS:
273   case IMMEDIATE_GREAT:
274   case IMMEDIATE_VALUE:
275     pointer->value = memReadByte(machine, PC);
276     return TRUE;
277   case INDIRECT_X:
278     zp = memReadByte(machine, PC) + machine->regX;
279     pointer->addr = memReadByte(machine,zp) + 
280       (memReadByte(machine,zp+1)<<8);
281     pointer->value = memReadByte(machine, pointer->addr);
282     return TRUE;
283   case INDIRECT_Y:
284     zp = memReadByte(machine, PC);
285     pointer->addr = memReadByte(machine,zp) + 
286       (memReadByte(machine,zp+1)<<8) + machine->regY;
287     pointer->value = memReadByte(machine, pointer->addr);
288     return TRUE;
289   case ZERO:
290     pointer->addr = memReadByte(machine, PC);
291     pointer->value = memReadByte(machine, pointer->addr);
292     return TRUE;
293   case ZERO_X:
294     pointer->addr = memReadByte(machine, PC) + machine->regX;
295     pointer->value = memReadByte(machine, pointer->addr);
296     return TRUE;
297   case ZERO_Y:
298     pointer->addr = memReadByte(machine, PC) + machine->regY;
299     pointer->value = memReadByte(machine, pointer->addr);
300     return TRUE;
301   case ABS_OR_BRANCH:
302     pointer->addr = memReadByte(machine, PC);
303     return TRUE;
304   case ABS_VALUE:
305     pointer->addr = memReadByte(machine, PC) + (memReadByte(machine, PC+1) << 8);
306     pointer->value = memReadByte(machine, pointer->addr);
307     return TRUE;
308   case ABS_LABEL_X:
309   case ABS_X:
310     pointer->addr = (memReadByte(machine, PC) + 
311                      (memReadByte(machine, PC+1) << 8)) + machine->regX;
312     pointer->value = memReadByte(machine, pointer->addr);
313     return TRUE;
314   case ABS_LABEL_Y:
315   case ABS_Y:
316     pointer->addr = (memReadByte(machine, PC) + 
317                      (memReadByte(machine, PC+1) << 8)) + machine->regY;
318     pointer->value = memReadByte(machine, pointer->addr);
319     return TRUE;
320   case DCB_PARAM:
321     /* Handled elsewhere */
322     break;
323   }
324   return FALSE;
325
326 }
327
328
329 /* Figure out how to get the value from the addrmode and get it.*/
330 static BOOL getValue(machine_6502 *machine, m6502_AddrMode adm, Pointer *pointer){
331   Bit8 zp;
332   pointer->value = 0;
333   pointer->addr = 0;
334   switch(adm){
335   case SINGLE:
336     return FALSE;
337   case IMMEDIATE_LESS:
338   case IMMEDIATE_GREAT:
339   case IMMEDIATE_VALUE:
340     pointer->value = popByte(machine);
341     return TRUE;
342   case INDIRECT_X:
343     zp = popByte(machine) + machine->regX;
344     pointer->addr = memReadByte(machine,zp) + 
345       (memReadByte(machine,zp+1)<<8);
346     pointer->value = memReadByte(machine, pointer->addr);
347     return TRUE;
348   case INDIRECT_Y:
349     zp = popByte(machine);
350     pointer->addr = memReadByte(machine,zp) + 
351       (memReadByte(machine,zp+1)<<8) + machine->regY;
352     pointer->value = memReadByte(machine, pointer->addr);
353     return TRUE;
354   case ZERO:
355     pointer->addr = popByte(machine);
356     pointer->value = memReadByte(machine, pointer->addr);
357     return TRUE;
358   case ZERO_X:
359     pointer->addr = popByte(machine) + machine->regX;
360     pointer->value = memReadByte(machine, pointer->addr);
361     return TRUE;
362   case ZERO_Y:
363     pointer->addr = popByte(machine) + machine->regY;
364     pointer->value = memReadByte(machine, pointer->addr);
365     return TRUE;
366   case ABS_OR_BRANCH:
367     pointer->addr = popByte(machine);
368     return TRUE;
369   case ABS_VALUE:
370     pointer->addr = popWord(machine);
371     pointer->value = memReadByte(machine, pointer->addr);
372     return TRUE;
373   case ABS_LABEL_X:
374   case ABS_X:
375     pointer->addr = popWord(machine) + machine->regX;
376     pointer->value = memReadByte(machine, pointer->addr);
377     return TRUE;
378   case ABS_LABEL_Y:
379   case ABS_Y:
380     pointer->addr = popWord(machine) + machine->regY;
381     pointer->value = memReadByte(machine, pointer->addr);
382     return TRUE;
383   case DCB_PARAM:
384     /* Handled elsewhere */
385     break;
386   }
387   return FALSE;
388
389 }
390
391 #if 0
392 static void dismem(machine_6502 *machine, m6502_AddrMode adm, char *output){
393   Bit8 zp;
394   Bit16 n;
395   switch(adm){
396   case SINGLE:
397     *output = 0;
398     break;
399   case IMMEDIATE_LESS:
400   case IMMEDIATE_GREAT:
401   case IMMEDIATE_VALUE:
402     n = popByte(machine);
403     sprintf(output,"#$%x",n);
404     break;
405   case INDIRECT_X:
406     zp = popByte(machine);
407     n = memReadByte(machine,zp) + 
408       (memReadByte(machine,zp+1)<<8);
409     sprintf(output,"($%x,x)",n);
410     break;
411   case INDIRECT_Y:
412     zp = popByte(machine);
413     n = memReadByte(machine,zp) + 
414       (memReadByte(machine,zp+1)<<8);
415     sprintf(output,"($%x),y",n);
416     break;
417   case ABS_OR_BRANCH:
418   case ZERO:    
419     n = popByte(machine);
420     sprintf(output,"$%x",n);
421     break;
422   case ZERO_X:
423     n = popByte(machine);
424     sprintf(output,"$%x,x",n);
425     break;
426   case ZERO_Y:
427     n = popByte(machine);
428     sprintf(output,"$%x,y",n);
429     break;
430   case ABS_VALUE:
431     n = popWord(machine);
432     sprintf(output,"$%x",n);
433     break;
434   case ABS_LABEL_X:
435   case ABS_X:
436     n = popWord(machine);
437     sprintf(output,"$%x,x",n);
438     break;
439   case ABS_LABEL_Y:
440   case ABS_Y:
441     n = popWord(machine);
442     sprintf(output,"$%x,x",n);
443     break;
444   case DCB_PARAM:
445     *output = 0;
446     break;
447   }
448 }
449 #endif
450
451 /* manZeroNeg - Manage the negative and zero flags */
452 static void manZeroNeg(machine_6502 *machine, Bit8 value){
453   machine->regP = setBit(machine->regP, ZERO_FL, (value == 0));
454   machine->regP = setBit(machine->regP, NEGATIVE_FL, bitOn(value,NEGATIVE_FL));
455 }
456
457 static void warnValue(BOOL isValue){
458   if (! isValue){
459     fprintf(stderr,"Invalid Value from getValue.\n");
460   }
461 }
462
463 static void jmpADC(machine_6502 *machine, m6502_AddrMode adm){
464   Pointer ptr;
465   Bit16 tmp;
466   Bit8 c = bitOn(machine->regP, CARRY_FL);
467   BOOL isValue = getValue(machine, adm, &ptr);
468
469   warnValue(isValue);
470   
471   if (bitOn(machine->regA, NEGATIVE_FL) &&
472       bitOn(ptr.value, NEGATIVE_FL))
473     machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
474   else
475     machine->regP = setBit(machine->regP, OVERFLOW_FL, 1);
476
477   if (bitOn(machine->regP, DECIMAL_FL)) {    
478     tmp = nibble(machine->regA,RIGHT) + nibble(ptr.value,RIGHT ) + c;
479     /* The decimal part is limited to 0 through 9 */
480     if (tmp >= 10){
481       tmp = 0x10 | ((tmp + 6) & 0xf);
482     }
483     tmp += nibble(machine->regA,LEFT) + nibble(ptr.value,LEFT);
484     if (tmp >= 160){
485       machine->regP = setBit(machine->regP,CARRY_FL,1);
486       if (bitOn(machine->regP, OVERFLOW_FL) && tmp >= 0x180)
487         machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
488       tmp += 0x60;
489     }
490     else {
491       machine->regP = setBit(machine->regP,CARRY_FL,0);
492       if (bitOn(machine->regP, OVERFLOW_FL) && tmp < 0x80)
493         machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
494     }
495   } /* end decimal */      
496   else {
497     tmp = machine->regA + ptr.value + c;
498     if ( tmp >= 0x100 ){
499       machine->regP = setBit(machine->regP,CARRY_FL,1);
500       if (bitOn(machine->regP, OVERFLOW_FL) && tmp >= 0x180)
501         machine->regP =setBit(machine->regP, OVERFLOW_FL, 0);
502     }
503     else {
504       machine->regP = setBit(machine->regP,CARRY_FL,0);
505       if (bitOn(machine->regP, OVERFLOW_FL) && tmp < 0x80)
506         machine->regP =setBit(machine->regP, OVERFLOW_FL, 0);
507     }
508   }
509
510   machine->regA = tmp;
511   manZeroNeg(machine,machine->regA);
512 }
513
514 static void jmpAND(machine_6502 *machine, m6502_AddrMode adm){
515   Pointer ptr;
516   BOOL isValue = getValue(machine, adm, &ptr);
517   warnValue(isValue);
518   machine->regA &= ptr.value;
519   manZeroNeg(machine,machine->regA);
520 }
521
522 static void jmpASL(machine_6502 *machine, m6502_AddrMode adm){
523   Pointer ptr;
524   BOOL isValue = getValue(machine, adm, &ptr);
525   if (isValue){
526       machine->regP = setBit(machine->regP, CARRY_FL, bitOn(ptr.value, NEGATIVE_FL));
527       ptr.value = ptr.value << 1;
528       ptr.value = setBit(ptr.value, CARRY_FL, 0);
529       memStoreByte(machine, ptr.addr, ptr.value);
530       manZeroNeg(machine,ptr.value);
531   }
532   else { /* Accumulator */
533       machine->regP = setBit(machine->regP, CARRY_FL, bitOn(machine->regA, NEGATIVE_FL));
534       machine->regA = machine->regA << 1;
535       machine->regA = setBit(machine->regA, CARRY_FL, 0);
536       manZeroNeg(machine,machine->regA);
537   }  
538   
539 }
540
541 static void jmpBIT(machine_6502 *machine, m6502_AddrMode adm){
542   Pointer ptr;
543   BOOL isValue = getValue(machine, adm, &ptr);
544   warnValue(isValue);
545   machine->regP = setBit(machine->regP, ZERO_FL, (ptr.value & machine->regA));
546   machine->regP = setBit(machine->regP, OVERFLOW_FL, bitOn(ptr.value, OVERFLOW_FL));
547   machine->regP = setBit(machine->regP, NEGATIVE_FL, bitOn(ptr.value, NEGATIVE_FL));
548   
549 }
550
551 static void jumpBranch(machine_6502 *machine, Bit16 offset){
552   if ( offset > 0x7f )
553     machine->regPC = machine->regPC - (0x100 - offset);
554   else
555     machine->regPC = machine->regPC + offset;
556 }
557
558 static void jmpBPL(machine_6502 *machine, m6502_AddrMode adm){
559   Pointer ptr;
560   BOOL isValue = getValue(machine, adm, &ptr);
561   warnValue(isValue);
562   if (bitOff(machine->regP,NEGATIVE_FL))
563     jumpBranch(machine, ptr.addr);
564     
565 }
566
567 static void jmpBMI(machine_6502 *machine, m6502_AddrMode adm){
568   Pointer ptr;
569   BOOL isValue = getValue(machine, adm, &ptr);
570   warnValue(isValue);
571   if (bitOn(machine->regP,NEGATIVE_FL))
572     jumpBranch(machine, ptr.addr);
573
574 }
575
576 static void jmpBVC(machine_6502 *machine, m6502_AddrMode adm){
577   Pointer ptr;
578   BOOL isValue = getValue(machine, adm, &ptr);
579   warnValue(isValue);
580   if (bitOff(machine->regP,OVERFLOW_FL))
581     jumpBranch(machine, ptr.addr);
582 }
583
584 static void jmpBVS(machine_6502 *machine, m6502_AddrMode adm){
585   Pointer ptr;
586   BOOL isValue = getValue(machine, adm, &ptr);
587   warnValue(isValue);
588   if (bitOn(machine->regP,OVERFLOW_FL))
589     jumpBranch(machine, ptr.addr);
590 }
591
592 static void jmpBCC(machine_6502 *machine, m6502_AddrMode adm){
593   Pointer ptr;
594   BOOL isValue = getValue(machine, adm, &ptr);
595   warnValue(isValue);
596   if (bitOff(machine->regP,CARRY_FL))
597     jumpBranch(machine, ptr.addr);
598 }
599
600 static void jmpBCS(machine_6502 *machine, m6502_AddrMode adm){
601   Pointer ptr;
602   BOOL isValue = getValue(machine, adm, &ptr);
603   warnValue(isValue);
604   if (bitOn(machine->regP,CARRY_FL))
605     jumpBranch(machine, ptr.addr);
606 }
607
608 static void jmpBNE(machine_6502 *machine, m6502_AddrMode adm){
609   Pointer ptr;
610   BOOL isValue = getValue(machine, adm, &ptr);
611   warnValue(isValue);
612   if (bitOff(machine->regP, ZERO_FL))
613     jumpBranch(machine, ptr.addr);
614 }
615
616 static void jmpBEQ(machine_6502 *machine, m6502_AddrMode adm){
617   Pointer ptr;
618   BOOL isValue = getValue(machine, adm, &ptr);
619   warnValue(isValue);
620   if (bitOn(machine->regP, ZERO_FL))
621     jumpBranch(machine, ptr.addr);
622 }
623
624 static void doCompare(machine_6502 *machine, Bit16 reg, Pointer *ptr){
625   machine->regP = setBit(machine->regP,CARRY_FL, ((reg + ptr->value) > 0xff));
626   manZeroNeg(machine,(reg - ptr->value));
627 }
628
629 static void jmpCMP(machine_6502 *machine, m6502_AddrMode adm){
630   Pointer ptr;
631   BOOL isValue = getValue(machine, adm, &ptr);
632   warnValue(isValue);
633   doCompare(machine,machine->regA,&ptr);
634 }
635
636 static void jmpCPX(machine_6502 *machine, m6502_AddrMode adm){
637   Pointer ptr;
638   BOOL isValue = getValue(machine, adm, &ptr);
639   warnValue(isValue);
640   doCompare(machine,machine->regX,&ptr);
641 }
642
643 static void jmpCPY(machine_6502 *machine, m6502_AddrMode adm){
644   Pointer ptr;
645   BOOL isValue = getValue(machine, adm, &ptr);
646   warnValue(isValue);
647   doCompare(machine,machine->regY,&ptr);
648 }
649
650 static void jmpDEC(machine_6502 *machine, m6502_AddrMode adm){
651   Pointer ptr;
652   BOOL isValue = getValue(machine, adm, &ptr);
653   warnValue(isValue);
654   if (ptr.value > 0)
655     ptr.value--;
656   else
657     ptr.value = 0xFF;
658   memStoreByte(machine, ptr.addr, ptr.value);
659   manZeroNeg(machine,ptr.value);
660 }
661
662 static void jmpEOR(machine_6502 *machine, m6502_AddrMode adm){
663   Pointer ptr;
664   BOOL isValue = getValue(machine, adm, &ptr);
665   warnValue(isValue);
666   machine->regA ^= ptr.value;
667   manZeroNeg(machine, machine->regA);
668 }
669
670 static void jmpCLC(machine_6502 *machine, m6502_AddrMode adm){
671   machine->regP = setBit(machine->regP, CARRY_FL, 0);
672 }
673
674 static void jmpSEC(machine_6502 *machine, m6502_AddrMode adm){
675   machine->regP = setBit(machine->regP, CARRY_FL, 1);
676 }
677
678 static void jmpCLI(machine_6502 *machine, m6502_AddrMode adm){
679   machine->regP = setBit(machine->regP, INTERRUPT_FL, 0);
680 }
681
682 static void jmpSEI(machine_6502 *machine, m6502_AddrMode adm){
683   machine->regP = setBit(machine->regP, INTERRUPT_FL, 1);
684 }
685
686 static void jmpCLV(machine_6502 *machine, m6502_AddrMode adm){
687   machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
688 }
689
690 static void jmpCLD(machine_6502 *machine, m6502_AddrMode adm){
691   machine->regP = setBit(machine->regP, DECIMAL_FL, 0);
692 }
693
694 static void jmpSED(machine_6502 *machine, m6502_AddrMode adm){
695   machine->regP = setBit(machine->regP, DECIMAL_FL, 1);
696 }
697
698 static void jmpINC(machine_6502 *machine, m6502_AddrMode adm){
699   Pointer ptr;
700   BOOL isValue = getValue(machine, adm, &ptr);
701   warnValue(isValue);
702   ptr.value = (ptr.value + 1) & 0xFF;
703   memStoreByte(machine, ptr.addr, ptr.value);
704   manZeroNeg(machine,ptr.value);
705 }
706
707 static void jmpJMP(machine_6502 *machine, m6502_AddrMode adm){
708   Pointer ptr;
709   BOOL isValue = getValue(machine, adm, &ptr);
710   warnValue(isValue);
711   machine->regPC = ptr.addr;
712 }
713
714 static void jmpJSR(machine_6502 *machine, m6502_AddrMode adm){
715   Pointer ptr;
716   /* Move past the 2 byte parameter. JSR is always followed by
717      absolute address. */
718   Bit16 currAddr = machine->regPC + 2;
719   BOOL isValue = getValue(machine, adm, &ptr);
720   warnValue(isValue);
721   stackPush(machine, (currAddr >> 8) & 0xff);
722   stackPush(machine, currAddr & 0xff);
723   machine->regPC = ptr.addr;  
724 }
725
726 static void jmpLDA(machine_6502 *machine, m6502_AddrMode adm){
727   Pointer ptr;
728   BOOL isValue = getValue(machine, adm, &ptr);
729   warnValue(isValue);
730   machine->regA = ptr.value;
731   manZeroNeg(machine, machine->regA);
732 }
733
734 static void jmpLDX(machine_6502 *machine, m6502_AddrMode adm){
735   Pointer ptr;
736   BOOL isValue = getValue(machine, adm, &ptr);
737   warnValue(isValue);
738   machine->regX = ptr.value;
739   manZeroNeg(machine, machine->regX);
740 }
741
742 static void jmpLDY(machine_6502 *machine, m6502_AddrMode adm){
743   Pointer ptr;
744   BOOL isValue = getValue(machine, adm, &ptr);
745   warnValue(isValue);
746   machine->regY = ptr.value;
747   manZeroNeg(machine, machine->regY);
748 }
749
750 static void jmpLSR(machine_6502 *machine, m6502_AddrMode adm){
751   Pointer ptr;
752   BOOL isValue = getValue(machine, adm, &ptr);
753   if (isValue){
754     machine->regP = 
755       setBit(machine->regP, CARRY_FL, 
756              bitOn(ptr.value, CARRY_FL));
757     ptr.value = ptr.value >> 1;
758     ptr.value = setBit(ptr.value,NEGATIVE_FL,0);
759     memStoreByte(machine,ptr.addr,ptr.value);
760     manZeroNeg(machine,ptr.value);
761   }
762   else { /* Accumulator */
763     machine->regP = 
764       setBit(machine->regP, CARRY_FL, 
765              bitOn(machine->regA, CARRY_FL));
766     machine->regA = machine->regA >> 1;
767     machine->regA = setBit(machine->regA,NEGATIVE_FL,0);
768     manZeroNeg(machine,ptr.value);
769   }
770 }
771
772 static void jmpNOP(machine_6502 *machine, m6502_AddrMode adm){
773   /* no operation */
774 }
775
776 static void jmpORA(machine_6502 *machine, m6502_AddrMode adm){
777   Pointer ptr;
778   BOOL isValue = getValue(machine, adm, &ptr);
779   warnValue(isValue);
780   machine->regA |= ptr.value;
781   manZeroNeg(machine,machine->regA);
782 }
783
784 static void jmpTAX(machine_6502 *machine, m6502_AddrMode adm){
785   machine->regX = machine->regA;
786   manZeroNeg(machine,machine->regX);
787 }
788
789 static void jmpTXA(machine_6502 *machine, m6502_AddrMode adm){
790   machine->regA = machine->regX;
791   manZeroNeg(machine,machine->regA);
792 }
793
794 static void jmpDEX(machine_6502 *machine, m6502_AddrMode adm){
795   if (machine->regX > 0)
796     machine->regX--;
797   else
798     machine->regX = 0xFF;
799   manZeroNeg(machine, machine->regX);
800 }
801
802 static void jmpINX(machine_6502 *machine, m6502_AddrMode adm){
803   Bit16 value = machine->regX + 1;
804   machine->regX = value & 0xFF;
805   manZeroNeg(machine, machine->regX);
806 }
807
808 static void jmpTAY(machine_6502 *machine, m6502_AddrMode adm){
809   machine->regY = machine->regA;
810   manZeroNeg(machine, machine->regY);
811 }
812
813 static void jmpTYA(machine_6502 *machine, m6502_AddrMode adm){
814   machine->regA = machine->regY;
815   manZeroNeg(machine, machine->regA);
816 }
817
818 static void jmpDEY(machine_6502 *machine, m6502_AddrMode adm){
819   if (machine->regY > 0)
820     machine->regY--;
821   else
822     machine->regY = 0xFF;
823   manZeroNeg(machine, machine->regY);
824 }
825
826 static void jmpINY(machine_6502 *machine, m6502_AddrMode adm){
827   Bit16 value = machine->regY + 1;
828   machine->regY = value & 0xff;
829   manZeroNeg(machine, machine->regY);
830 }
831
832 static void jmpROR(machine_6502 *machine, m6502_AddrMode adm){
833   Pointer ptr;
834   Bit8 cf;
835   BOOL isValue = getValue(machine, adm, &ptr);
836   if (isValue) { 
837     cf = bitOn(machine->regP, CARRY_FL);
838     machine->regP = 
839       setBit(machine->regP, CARRY_FL,
840              bitOn(ptr.value, CARRY_FL));
841     ptr.value = ptr.value >> 1;
842     ptr.value = setBit(ptr.value, NEGATIVE_FL, cf);
843     memStoreByte(machine, ptr.addr, ptr.value);
844     manZeroNeg(machine, ptr.value);
845   }
846   else { /* Implied */
847     cf = bitOn(machine->regP, CARRY_FL);
848     machine->regP = 
849       setBit(machine->regP, CARRY_FL,
850              bitOn(machine->regA, CARRY_FL));
851     machine->regA = machine->regA >> 1;
852     machine->regA = setBit(machine->regA, NEGATIVE_FL, cf);
853     manZeroNeg(machine, machine->regA);
854   }
855 }
856
857 static void jmpROL(machine_6502 *machine, m6502_AddrMode adm){
858   Pointer ptr;
859   Bit8 cf;
860   BOOL isValue = getValue(machine, adm, &ptr);
861   if (isValue) { 
862     cf = bitOn(machine->regP, CARRY_FL);
863     machine->regP = 
864       setBit(machine->regP, CARRY_FL,
865              bitOn(ptr.value, NEGATIVE_FL));
866     ptr.value = ptr.value << 1;
867     ptr.value = setBit(ptr.value, CARRY_FL, cf);
868     memStoreByte(machine, ptr.addr, ptr.value);
869     manZeroNeg(machine, ptr.value);
870   }
871   else { /* Implied */
872     cf = bitOn(machine->regP, CARRY_FL);
873     machine->regP = 
874       setBit(machine->regP, CARRY_FL,
875              bitOn(machine->regA,NEGATIVE_FL));
876     machine->regA = machine->regA << 1;
877     machine->regA = setBit(machine->regA, CARRY_FL, cf);
878     manZeroNeg(machine, machine->regA);
879   }
880 }
881
882 static void jmpRTI(machine_6502 *machine, m6502_AddrMode adm){
883   machine->regP = stackPop(machine);
884   machine->regPC = stackPop(machine);
885 }
886
887 static void jmpRTS(machine_6502 *machine, m6502_AddrMode adm){
888   Pointer ptr;
889   BOOL isValue = getValue(machine, adm, &ptr);
890   Bit16 nr = stackPop(machine);
891   Bit16 nl = stackPop(machine);
892   warnValue(! isValue);
893   machine->regPC = (nl << 8) | nr;
894 }
895
896 static void jmpSBC(machine_6502 *machine, m6502_AddrMode adm){
897   Pointer ptr;
898   /*Bit8 vflag;*/
899   Bit8 c = bitOn(machine->regP, CARRY_FL);
900   Bit16 tmp, w;
901   BOOL isValue = getValue(machine, adm, &ptr);
902   warnValue(isValue);
903   /*vflag = (bitOn(machine->regA,NEGATIVE_FL) &&
904            bitOn(ptr.value, NEGATIVE_FL));*/
905
906   if (bitOn(machine->regP, DECIMAL_FL)) {
907     Bit8 ar = nibble(machine->regA, RIGHT);
908     Bit8 br = nibble(ptr.value, RIGHT);
909     Bit8 al = nibble(machine->regA, LEFT);
910     Bit8 bl = nibble(ptr.value, LEFT);
911
912     tmp = 0xf + ar - br + c;
913     if ( tmp < 0x10){
914       w = 0;
915       tmp -= 6;
916     }
917     else {
918       w = 0x10;
919       tmp -= 0x10;
920     }
921     w += 0xf0 + al - bl;
922     if ( w < 0x100) {
923       machine->regP = setBit(machine->regP, CARRY_FL, 0);
924       if (bitOn(machine->regP, OVERFLOW_FL) && w < 0x80)
925         machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
926       w -= 0x60;
927     }
928     else {
929       machine->regP = setBit(machine->regP, CARRY_FL, 1);
930       if (bitOn(machine->regP, OVERFLOW_FL) && w >= 0x180)
931         machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
932     }
933     w += tmp;
934   } /* end decimal mode */
935   else {
936     w = 0xff + machine->regA - ptr.value + c;
937     if ( w < 0x100 ){
938       machine->regP = setBit(machine->regP, CARRY_FL, 0);
939       if (bitOn(machine->regP, OVERFLOW_FL) && w < 0x80)
940         machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
941     }
942     else {
943       machine->regP = setBit(machine->regP, CARRY_FL, 1);
944       if (bitOn(machine->regP, OVERFLOW_FL) && w >= 0x180)
945         machine->regP = setBit(machine->regP, OVERFLOW_FL, 0);
946     }
947   }
948   machine->regA = w;
949   manZeroNeg(machine,machine->regA);
950 }
951
952 static void jmpSTA(machine_6502 *machine, m6502_AddrMode adm){
953   Pointer ptr;
954   BOOL isValue = getValue(machine, adm, &ptr);
955   warnValue(isValue);
956   memStoreByte(machine,ptr.addr,machine->regA);
957 }
958
959 static void jmpTXS(machine_6502 *machine, m6502_AddrMode adm){
960   stackPush(machine,machine->regX);
961 }
962
963 static void jmpTSX(machine_6502 *machine, m6502_AddrMode adm){
964   machine->regX = stackPop(machine);
965   manZeroNeg(machine, machine->regX);
966 }
967
968 static void jmpPHA(machine_6502 *machine, m6502_AddrMode adm){
969   stackPush(machine, machine->regA);
970 }
971
972 static void jmpPLA(machine_6502 *machine, m6502_AddrMode adm){
973   machine->regA = stackPop(machine);
974   manZeroNeg(machine, machine->regA);
975 }
976
977 static void jmpPHP(machine_6502 *machine, m6502_AddrMode adm){
978   stackPush(machine,machine->regP);
979 }
980
981 static void jmpPLP(machine_6502 *machine, m6502_AddrMode adm){
982   machine->regP = stackPop(machine);
983   machine->regP = setBit(machine->regP, FUTURE_FL, 1);
984 }
985
986 static void jmpSTX(machine_6502 *machine, m6502_AddrMode adm){
987   Pointer ptr;
988   BOOL isValue = getValue(machine, adm, &ptr);
989   warnValue(isValue);
990   memStoreByte(machine,ptr.addr,machine->regX);
991 }
992
993 static void jmpSTY(machine_6502 *machine, m6502_AddrMode adm){
994   Pointer ptr;
995   BOOL isValue = getValue(machine, adm, &ptr);
996   warnValue(isValue);
997   memStoreByte(machine,ptr.addr,machine->regY);
998 }
999
1000 \f
1001
1002 /* OPCODES */
1003 static void assignOpCodes(m6502_Opcodes *opcodes){
1004
1005  #define SETOP(num, _name, _Imm, _ZP, _ZPX, _ZPY, _ABS, _ABSX, _ABSY, _INDX, _INDY, _SNGL, _BRA, _func) \
1006 {opcodes[num].name[3] = '\0'; \
1007  strncpy(opcodes[num].name, _name, 3); opcodes[num].Imm = _Imm; opcodes[num].ZP = _ZP; \
1008  opcodes[num].ZPX = _ZPX; opcodes[num].ZPY = _ZPY; opcodes[num].ABS = _ABS; \
1009  opcodes[num].ABSX = _ABSX; opcodes[num].ABSY = _ABSY; opcodes[num].INDX = _INDX; \
1010  opcodes[num].INDY = _INDY; opcodes[num].SNGL = _SNGL; opcodes[num].BRA = _BRA; \
1011  opcodes[num].func = _func;}
1012
1013   /*        OPCODE Imm   ZP    ZPX   ZPY   ABS   ABSX  ABSY  INDX  INDY  SGNL  BRA   Jump Function*/ 
1014   SETOP( 0, "ADC", 0x69, 0x65, 0x75, 0x00, 0x6d, 0x7d, 0x79, 0x61, 0x71, 0x00, 0x00, jmpADC);
1015   SETOP( 1, "AND", 0x29, 0x25, 0x35, 0x31, 0x2d, 0x3d, 0x39, 0x00, 0x00, 0x00, 0x00, jmpAND);
1016   SETOP( 2, "ASL", 0x00, 0x06, 0x16, 0x00, 0x0e, 0x1e, 0x00, 0x00, 0x00, 0x0a, 0x00, jmpASL);
1017   SETOP( 3, "BIT", 0x00, 0x24, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpBIT);
1018   SETOP( 4, "BPL", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, jmpBPL);
1019   SETOP( 5, "BMI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, jmpBMI);
1020   SETOP( 6, "BVC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, jmpBVC);
1021   SETOP( 7, "BVS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, jmpBVS);
1022   SETOP( 8, "BCC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, jmpBCC);
1023   SETOP( 9, "BCS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, jmpBCS);
1024   SETOP(10, "BNE", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, jmpBNE);
1025   SETOP(11, "BEQ", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, jmpBEQ);
1026   SETOP(12, "CMP", 0xc9, 0xc5, 0xd5, 0x00, 0xcd, 0xdd, 0xd9, 0xc1, 0xd1, 0x00, 0x00, jmpCMP);
1027   SETOP(13, "CPX", 0xe0, 0xe4, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpCPX);
1028   SETOP(14, "CPY", 0xc0, 0xc4, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpCPY);
1029   SETOP(15, "DEC", 0x00, 0xc6, 0xd6, 0x00, 0xce, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, jmpDEC);
1030   SETOP(16, "EOR", 0x49, 0x45, 0x55, 0x00, 0x4d, 0x5d, 0x59, 0x41, 0x51, 0x00, 0x00, jmpEOR);
1031   SETOP(17, "CLC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, jmpCLC);
1032   SETOP(18, "SEC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, jmpSEC);
1033   SETOP(19, "CLI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, jmpCLI);
1034   SETOP(20, "SEI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, jmpSEI);
1035   SETOP(21, "CLV", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, jmpCLV);
1036   SETOP(22, "CLD", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, jmpCLD);
1037   SETOP(23, "SED", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, jmpSED);
1038   SETOP(24, "INC", 0x00, 0xe6, 0xf6, 0x00, 0xee, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, jmpINC);
1039   SETOP(25, "JMP", 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpJMP);
1040   SETOP(26, "JSR", 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpJSR);
1041   SETOP(27, "LDA", 0xa9, 0xa5, 0xb5, 0x00, 0xad, 0xbd, 0xb9, 0xa1, 0xb1, 0x00, 0x00, jmpLDA);
1042   SETOP(28, "LDX", 0xa2, 0xa6, 0x00, 0xb6, 0xae, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, jmpLDX);
1043   SETOP(29, "LDY", 0xa0, 0xa4, 0xb4, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, jmpLDY);
1044   SETOP(30, "LSR", 0x00, 0x46, 0x56, 0x00, 0x4e, 0x5e, 0x00, 0x00, 0x00, 0x4a, 0x00, jmpLSR);
1045   SETOP(31, "NOP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, jmpNOP);
1046   SETOP(32, "ORA", 0x09, 0x05, 0x15, 0x00, 0x0d, 0x1d, 0x19, 0x01, 0x11, 0x00, 0x00, jmpORA);
1047   SETOP(33, "TAX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, jmpTAX);
1048   SETOP(34, "TXA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, jmpTXA);
1049   SETOP(35, "DEX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x00, jmpDEX);
1050   SETOP(36, "INX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, jmpINX);
1051   SETOP(37, "TAY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, jmpTAY);
1052   SETOP(38, "TYA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, jmpTYA);
1053   SETOP(39, "DEY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, jmpDEY);
1054   SETOP(40, "INY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, jmpINY);
1055   SETOP(41, "ROR", 0x00, 0x66, 0x76, 0x00, 0x6e, 0x7e, 0x00, 0x00, 0x00, 0x6a, 0x00, jmpROR);
1056   SETOP(42, "ROL", 0x00, 0x26, 0x36, 0x00, 0x2e, 0x3e, 0x00, 0x00, 0x00, 0x2a, 0x00, jmpROL);
1057   SETOP(43, "RTI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, jmpRTI);
1058   SETOP(44, "RTS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, jmpRTS);
1059   SETOP(45, "SBC", 0xe9, 0xe5, 0xf5, 0x00, 0xed, 0xfd, 0xf9, 0xe1, 0xf1, 0x00, 0x00, jmpSBC);
1060   SETOP(46, "STA", 0x00, 0x85, 0x95, 0x00, 0x8d, 0x9d, 0x99, 0x81, 0x91, 0x00, 0x00, jmpSTA);
1061   SETOP(47, "TXS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, jmpTXS);
1062   SETOP(48, "TSX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, jmpTSX);
1063   SETOP(49, "PHA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, jmpPHA);
1064   SETOP(50, "PLA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, jmpPLA);
1065   SETOP(51, "PHP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, jmpPHP);
1066   SETOP(52, "PLP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, jmpPLP);
1067   SETOP(53, "STX", 0x00, 0x86, 0x00, 0x96, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpSTX);
1068   SETOP(54, "STY", 0x00, 0x84, 0x94, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, jmpSTY);
1069   SETOP(55, "---", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, NULL);
1070 }
1071
1072 static void buildIndexCache(machine_6502 *machine){
1073   unsigned int i;
1074   for (i = 0; i < NUM_OPCODES; i++) {
1075     if (machine->opcodes[i].Imm != 0x00){
1076       machine->opcache[machine->opcodes[i].Imm].adm = IMMEDIATE_VALUE;
1077       machine->opcache[machine->opcodes[i].Imm].index = i;
1078     }
1079      if (machine->opcodes[i].ZP != 0x00){
1080       machine->opcache[machine->opcodes[i].ZP].adm = ZERO;
1081       machine->opcache[machine->opcodes[i].ZP].index = i;
1082     }
1083      if (machine->opcodes[i].ZPX != 0x00){
1084       machine->opcache[machine->opcodes[i].ZPX].adm = ZERO_X;
1085       machine->opcache[machine->opcodes[i].ZPX].index = i;;
1086     }
1087      if (machine->opcodes[i].ZPY != 0x00){
1088       machine->opcache[machine->opcodes[i].ZPY].adm = ZERO_Y;
1089       machine->opcache[machine->opcodes[i].ZPY].index = i;;
1090     }
1091      if (machine->opcodes[i].ABS != 0x00){
1092       machine->opcache[machine->opcodes[i].ABS].adm = ABS_VALUE;
1093       machine->opcache[machine->opcodes[i].ABS].index = i;;
1094     }
1095      if (machine->opcodes[i].ABSX != 0x00){
1096       machine->opcache[machine->opcodes[i].ABSX].adm = ABS_X;
1097       machine->opcache[machine->opcodes[i].ABSX].index = i;;
1098     }
1099      if (machine->opcodes[i].ABSY != 0x00){
1100       machine->opcache[machine->opcodes[i].ABSY].adm = ABS_Y;
1101       machine->opcache[machine->opcodes[i].ABSY].index = i;;
1102     }
1103      if (machine->opcodes[i].INDX != 0x00){
1104       machine->opcache[machine->opcodes[i].INDX].adm = INDIRECT_X;
1105       machine->opcache[machine->opcodes[i].INDX].index = i;;
1106     }
1107      if (machine->opcodes[i].INDY != 0x00){
1108       machine->opcache[machine->opcodes[i].INDY].adm = INDIRECT_Y;
1109       machine->opcache[machine->opcodes[i].INDY].index = i;;
1110     }
1111      if (machine->opcodes[i].SNGL != 0x00){
1112       machine->opcache[machine->opcodes[i].SNGL].adm = SINGLE;
1113       machine->opcache[machine->opcodes[i].SNGL].index = i;
1114     }
1115      if (machine->opcodes[i].BRA != 0x00){
1116       machine->opcache[machine->opcodes[i].BRA].adm = ABS_OR_BRANCH;
1117       machine->opcache[machine->opcodes[i].BRA].index = i;
1118     }
1119   }   
1120 }
1121
1122 /* opIndex() - Search the opcode table for a match. If found return
1123    the index into the optable and the address mode of the opcode. If
1124    the opcode is not found then return -1. */
1125 static int opIndex(machine_6502 *machine, Bit8 opcode, m6502_AddrMode *adm){ 
1126   /* XXX could catch errors by setting a addressmode of error or something */
1127   *adm = machine->opcache[opcode].adm;
1128   return machine->opcache[opcode].index;
1129 }
1130
1131 \f
1132 /* Assembly parser */
1133
1134 static Param *newParam(void){
1135   Param *newp;
1136   int i = 0;
1137
1138   newp = (Param *) ecalloc(1, sizeof(Param));
1139   newp->type = SINGLE;
1140   for (i = 0; i < MAX_PARAM_VALUE; i++)
1141     newp->value[i] = 0;
1142   newp->vp = 0;
1143   newp->label = ecalloc(MAX_LABEL_LEN,sizeof(char));
1144   newp->lbladdr = 0;
1145   return newp;
1146 }
1147
1148 /* Copy the fields from p2 to p1 */
1149 static void copyParam(Param *p1, Param *p2){
1150   int i = 0;
1151   strncpy(p1->label,p2->label,MAX_LABEL_LEN);
1152   for(i = 0; i < MAX_PARAM_VALUE; i++)
1153     p1->value[i] = p2->value[i];
1154   p1->vp = p2->vp;
1155   p1->type = p2->type;
1156 }
1157
1158 static Label *newLabel(void){
1159   Label *newp; 
1160
1161   newp = (Label *) ecalloc(1, sizeof(Label));
1162   newp->addr = 0;
1163   newp->label = ecalloc(MAX_LABEL_LEN,sizeof(char));
1164   
1165   return newp;
1166 }
1167
1168 static AsmLine *newAsmLine(char *cmd, char *label, BOOL decl, Param *param, int lc)
1169 {
1170     AsmLine *newp;
1171
1172     newp =  (AsmLine *) ecalloc(1, sizeof(AsmLine));
1173     newp->labelDecl = decl;
1174     newp->label = newLabel();
1175     strncpy(newp->label->label,label,MAX_LABEL_LEN);
1176     newp->command = estrdup(cmd);
1177     newp->param = newParam();
1178     copyParam(newp->param, param);
1179     newp->next = NULL;
1180     return newp;
1181 }
1182
1183 static AsmLine *addend(AsmLine *listp, AsmLine *newp)
1184 {
1185     AsmLine *p;
1186     if(listp == NULL)
1187       return newp;
1188     for (p =listp; p->next != NULL; p = p->next)
1189       ;
1190     p->next = newp;
1191     return listp;
1192 }
1193
1194 static BOOL apply(AsmLine *listp, BOOL(*fn)(AsmLine*, void*), void *arg)
1195 {
1196   AsmLine *p;
1197   if(listp == NULL)
1198     return FALSE;
1199   for (p = listp; p != NULL; p = p->next)
1200     if (! fn(p,arg) )
1201       return FALSE;
1202   return TRUE;
1203 }
1204
1205 static void freeParam(Param *param){
1206   free(param->label);
1207   free(param);
1208 }
1209
1210 static void freeLabel(Label *label){
1211   free(label->label);
1212   free(label);
1213 }
1214
1215 static void freeallAsmLine(AsmLine *listp)
1216 {
1217     AsmLine *next;
1218     for(; listp != NULL; listp = next){
1219        next = listp->next;
1220        freeParam(listp->param);
1221        freeLabel(listp->label);
1222        free(listp->command);
1223        free(listp);
1224     }
1225 }
1226
1227 static BOOL addvalue(Param *param,Bit32 value){
1228   /* jwz: suppress "0 <= unsigned" warning */
1229   if (/*0 <= param->vp &&*/ param->vp < MAX_PARAM_VALUE) {
1230     param->value[param->vp++] = value;
1231     return TRUE;
1232   }
1233   else {
1234     fprintf(stderr,"Wrong number of parameters: %d. The limit is %d\n",param->vp+1, MAX_PARAM_VALUE);
1235     return FALSE;
1236   }
1237 }
1238
1239 static void parseError(char *s){
1240   fprintf(stderr,"6502 Syntax Error: %s\n", s);
1241 }
1242
1243 /* stoupper() - Destructivley modifies the string making all letters upper case*/
1244 static void stoupper(char **s){
1245   int i = 0;
1246   while((*s)[i] != '\0'){
1247     (*s)[i] = toupper((*s)[i]);
1248     i++;
1249   }
1250 }
1251  
1252 static BOOL isWhite(char c){
1253   return (c == '\r' || c == '\t' || c == ' ');
1254 }
1255
1256 static void skipSpace(char **s){
1257   for(; isWhite(**s); (*s)++)
1258     ;
1259 }
1260   
1261 /* nullify() - fills a string with upto sourceLength null characters. */
1262 static void nullify(char *token, unsigned int sourceLength){
1263   unsigned int i = 0;
1264   while (i < sourceLength)
1265     token[i++] = '\0';
1266 }
1267
1268 static BOOL isBlank(const char *token){
1269   return (token[0] == '\0');
1270 }
1271
1272 static BOOL isCommand(machine_6502 *machine, const char *token){
1273   int i = 0;
1274
1275   while (i < NUM_OPCODES) {
1276     if (strcmp(machine->opcodes[i].name,token) == 0) 
1277       return TRUE;
1278     i++;
1279   }
1280   
1281   if (strcmp(token, "DCB") == 0) return TRUE;
1282   return FALSE;
1283 }
1284
1285 /* hasChar() - Check to see if the current line has a certain
1286    charater */
1287 static BOOL hasChar(char *s, char c){
1288   for(; *s != '\0' && *s != '\n'; s++) {
1289     if (*s  == c)
1290       return TRUE;
1291   }
1292   return FALSE;
1293 }
1294
1295 static BOOL ishexdigit(char c){
1296   if (isdigit(c))
1297     return TRUE;
1298   else {
1299     char c1 = toupper(c);
1300     return ('A' <= c1 && c1 <= 'F');
1301   }
1302 }
1303
1304 /* isCmdChar() - Is this a valid character for a command. All of the
1305    command are alpha except for the entry point code that is "*=" */
1306 static BOOL isCmdChar(char c){
1307   return (isalpha(c) || c == '*' || c == '=');
1308 }
1309   
1310
1311 /* command() - parse a command from the source code. We pass along a
1312    machine so the opcode can be validated. */
1313 static BOOL command(machine_6502 *machine, char **s, char **cmd){
1314   int i = 0;
1315   skipSpace(s);
1316   for(;isCmdChar(**s) && i < MAX_CMD_LEN; (*s)++)
1317     (*cmd)[i++] = **s;
1318   if (i == 0)
1319     return TRUE; /* Could be a blank line. */
1320   else if (strcmp(*cmd,"*=") == 0)
1321     return TRUE; /* This is an entry point. */
1322   else
1323     return isCommand(machine,*cmd);
1324 }
1325
1326 static BOOL declareLabel(char **s, char **label){
1327   int i = 0;
1328   skipSpace(s);
1329   for(;**s != ':' && **s != '\n' && **s != '\0'; (*s)++){
1330     if (isWhite(**s)) 
1331       continue;
1332     (*label)[i++] = **s;
1333   }
1334   if (i == 0)
1335     return FALSE; /* Current line has to have a label */
1336   else if (**s == ':'){
1337     (*s)++; /* Skip colon */
1338     return TRUE;
1339   }
1340   else
1341     return FALSE;
1342 }
1343
1344 static BOOL parseHex(char **s, Bit32 *value){
1345   enum { MAX_HEX_LEN = 5 };
1346   if (**s == '$') {    
1347     char *hex = ecalloc(MAX_HEX_LEN, sizeof(char));
1348     int i = 0;
1349
1350     (*s)++; /* move pass $ */
1351     for(; ishexdigit(**s) && i < MAX_HEX_LEN; (*s)++)
1352       hex[i++] = **s;
1353     
1354     *value = strtol(hex,NULL,16);
1355     free(hex);  
1356     return TRUE;
1357   }
1358   else
1359     return FALSE;
1360 }
1361   
1362 static BOOL parseDec(char **s, Bit32 *value){
1363   enum { MAX_DEC_LEN = 4 };
1364   char *dec = ecalloc(MAX_DEC_LEN, sizeof(char));
1365   int i;
1366   for(i = 0; isdigit(**s) && i < MAX_DEC_LEN; (*s)++)
1367     dec[i++] = **s;
1368   
1369   if (i > 0){
1370     *value = atoi(dec);
1371     free(dec);  
1372     return TRUE;
1373   }
1374   else{
1375     free(dec);
1376     return FALSE;
1377   }
1378 }
1379
1380 static BOOL parseValue(char **s, Bit32 *value){
1381   skipSpace(s);
1382   if (**s == '$')
1383     return parseHex(s, value);
1384   else
1385     return parseDec(s, value);
1386 }
1387
1388 static BOOL paramLabel(char **s, char **label){
1389   int i;
1390   for(i = 0; (isalnum(**s) || **s == '_') && i < MAX_LABEL_LEN; (*s)++)
1391     (*label)[i++] = **s;
1392
1393   if (i > 0)
1394     return TRUE;
1395   else
1396     return FALSE;
1397 }
1398
1399 static BOOL immediate(char **s, Param *param){
1400   if (**s != '#') 
1401     return FALSE;
1402
1403   (*s)++; /*Move past hash */
1404   if (**s == '<' || **s == '>'){    
1405     char *label = ecalloc(MAX_LABEL_LEN, sizeof(char));
1406     param->type = (**s == '<') ? IMMEDIATE_LESS : IMMEDIATE_GREAT;
1407     (*s)++; /* move past < or > */
1408     if (paramLabel(s, &label)){
1409       int ln = strlen(label) + 1;
1410       strncpy(param->label, label, ln);
1411       free(label);
1412       return TRUE;
1413     }    
1414     free(label);
1415   }
1416   else {
1417     Bit32 value;
1418     if (parseValue(s, &value)){
1419       if (value > 0xFF){
1420         parseError("Immediate value is too large.");
1421         return FALSE;
1422       }
1423       param->type = IMMEDIATE_VALUE;
1424       return addvalue(param, value);
1425     }
1426   }
1427   return FALSE;
1428 }
1429
1430 static BOOL isDirection(char c){
1431   return (c == 'X' || c == 'Y');
1432 }
1433
1434 static BOOL getDirection(char **s, char *direction){
1435   skipSpace(s);
1436   if (**s == ','){
1437     (*s)++;
1438     skipSpace(s);
1439     if (isDirection(**s)){
1440       *direction = **s;
1441       (*s)++;
1442       return TRUE;
1443     }
1444   }
1445   return FALSE;
1446 }
1447   
1448 static BOOL indirect(char **s, Param *param){
1449   Bit32 value;
1450   char c;
1451   if (**s == '(') 
1452     (*s)++;
1453   else
1454     return FALSE;
1455   
1456   if (! parseHex(s,&value)) 
1457     return FALSE;
1458   if (value > 0xFF) {
1459     parseError("Indirect value is too large.");
1460     return FALSE;
1461   }
1462   if (!addvalue(param, value))
1463     return FALSE;
1464   skipSpace(s);
1465   if (**s == ')'){
1466     (*s)++;
1467     if (getDirection(s,&c)) {
1468       if (c == 'Y'){
1469         param->type = INDIRECT_Y;
1470         return TRUE;
1471       }
1472     }
1473   }
1474   else if (getDirection(s, &c)){
1475     if (c == 'X'){
1476       skipSpace(s);
1477       if (**s == ')'){
1478         (*s)++;
1479         param->type = INDIRECT_X;
1480         return TRUE;
1481       }
1482     }
1483   }
1484   return FALSE;
1485 }
1486
1487 static BOOL dcbValue(char **s, Param *param){
1488   Bit32 val;
1489   if (! parseValue(s,&val))
1490     return FALSE;
1491
1492   if (val > 0xFF) 
1493     return FALSE;
1494                     
1495   if (!addvalue(param,val))
1496     return FALSE;
1497
1498   param->type = DCB_PARAM;
1499
1500   skipSpace(s);
1501   if(**s == ','){
1502     (*s)++;
1503     return dcbValue(s, param);
1504   }
1505   else
1506     return TRUE;
1507
1508
1509 static BOOL value(char **s, Param *param){
1510   Bit32 val;
1511   BOOL abs;
1512   BOOL dir;
1513   char c = '\0';
1514   if (! parseValue(s,&val))
1515     return FALSE;
1516
1517   abs = (val > 0xFF);
1518   dir = getDirection(s,&c);
1519   if (!addvalue(param,val))
1520     return FALSE;
1521
1522   if(abs && dir){
1523     if (c == 'X')
1524       param->type = ABS_X;
1525     else if (c == 'Y')
1526       param->type = ABS_Y;
1527     else
1528       return FALSE;
1529   }
1530   else if (abs)
1531     param->type = ABS_VALUE;
1532   else if (dir){
1533     if (c == 'X')
1534       param->type = ZERO_X;
1535     else if (c == 'Y')
1536       param->type = ZERO_Y;
1537     else
1538       return FALSE;
1539   }
1540   else
1541     param->type = ZERO;
1542
1543   return TRUE;
1544 }
1545
1546 static BOOL label(char **s, Param *param){
1547   char *label = ecalloc(MAX_LABEL_LEN, sizeof(char));
1548   char c;
1549   BOOL labelOk = FALSE;
1550   if (paramLabel(s, &label)){
1551     labelOk = TRUE;
1552     param->type = ABS_OR_BRANCH;
1553     if (getDirection(s, &c)){
1554       if (c == 'X')
1555         param->type = ABS_LABEL_X;
1556       else if (c == 'Y')
1557         param->type = ABS_LABEL_Y;
1558       else
1559         labelOk = FALSE;
1560     }
1561     strncpy(param->label,label,MAX_LABEL_LEN);
1562   }
1563   free(label);
1564   return labelOk;
1565 }
1566
1567 static BOOL parameter(const char *cmd, char **s, Param *param){
1568   skipSpace(s);
1569   if (**s == '\0' || **s == '\n')
1570     return TRUE;
1571   else if (**s == '#')
1572     return immediate(s,param);
1573   else if (**s == '(')
1574     return indirect(s,param);
1575   else if (**s == '$' || isdigit(**s)){
1576     if (strcmp(cmd, "DCB") == 0)
1577       return dcbValue(s,param);
1578     else
1579       return value(s,param);
1580   }
1581   else if (isalpha(**s))
1582     return label(s ,param);
1583   else
1584     return FALSE; /* Invalid Parameter */
1585 }
1586
1587 static void comment(char **s){
1588   skipSpace(s);
1589   if (**s == ';')
1590     for(;**s != '\n' && **s != '\0'; (*s)++)
1591       ;
1592 }
1593
1594 static void initParam(Param *param){
1595   int i;
1596   param->type = SINGLE;
1597   for(i = 0; i < MAX_PARAM_VALUE; i++)
1598     param->value[i] = 0;
1599   param->vp = 0;
1600   nullify(param->label,MAX_LABEL_LEN);
1601 }
1602   
1603
1604 static AsmLine *parseAssembly(machine_6502 *machine, BOOL *codeOk, const char *code){
1605   char *s;
1606   char *cmd = ecalloc(MAX_CMD_LEN, sizeof(char));
1607   char *label = ecalloc(MAX_LABEL_LEN, sizeof(char));
1608   char *start; /*pointer to the start of the code.*/
1609   unsigned int lc = 1;
1610   Param *param;
1611   BOOL decl;
1612   AsmLine *listp = NULL;
1613
1614   *codeOk = TRUE;
1615   param = newParam();
1616   s = estrdup(code);
1617   start = s;
1618   stoupper(&s);
1619
1620   while(*s != '\0' && *codeOk){
1621     initParam(param);
1622     nullify(cmd, MAX_CMD_LEN);
1623     nullify(label, MAX_LABEL_LEN);
1624     decl = FALSE;
1625     skipSpace(&s);
1626     comment(&s);
1627     if (*s == '\n'){
1628       lc++;
1629       s++;
1630       continue; /* blank line */
1631     }
1632     else if (*s == '\0')
1633       continue; /* no newline at the end of the code */
1634     else if (hasChar(s,':')){
1635       decl = TRUE;
1636       if(! declareLabel(&s,&label)){
1637         *codeOk = FALSE;
1638         break;
1639       }
1640       skipSpace(&s);
1641     }
1642     if(!command(machine, &s, &cmd)){
1643       *codeOk = FALSE;
1644       break;
1645     }
1646     skipSpace(&s);
1647     comment(&s);
1648     if(!parameter(cmd, &s, param)){
1649       *codeOk = FALSE;
1650       break;
1651     }
1652     skipSpace(&s);
1653     comment(&s);
1654     if (*s == '\n' || *s == '\0'){
1655       AsmLine *asmm;
1656       asmm = newAsmLine(cmd,label,decl,param,lc);
1657       listp = addend(listp,asmm);
1658     }
1659     else {
1660       *codeOk = FALSE;
1661       break;
1662     }
1663   }
1664   if (! *codeOk)
1665     fprintf(stderr,"Syntax error at line %u\n", lc);
1666   free(start);
1667   free(cmd);
1668   free(label);
1669   freeParam(param);
1670   return listp;
1671 }
1672     
1673 #ifdef READ_FILES
1674 /* fileToBuffer() - Allocates a buffer and loads all of the file into memory. */
1675 static char *fileToBuffer(const char *filename){
1676   const int defaultSize = 1024;
1677   FILE *ifp;
1678   int c;
1679   int size = defaultSize;
1680   int i = 0;
1681   char *buffer = ecalloc(defaultSize,sizeof(char));
1682
1683   if (!buffer) abort();
1684
1685   ifp = fopen(filename, "rb");
1686   if (!ifp) abort();
1687
1688   while((c = getc(ifp)) != EOF){
1689     buffer[i++] = c;
1690     if (i == size){
1691       size += defaultSize;
1692       buffer = realloc(buffer, size);
1693       if (buffer == NULL) {
1694         abort();
1695       }
1696     }
1697   }
1698   fclose(ifp);
1699   buffer = realloc(buffer, i+2);
1700   if (!buffer) abort();
1701   /* Make sure we have a line feed at the end */
1702   buffer[i] = '\n';
1703   buffer[i+1] = '\0';
1704   return buffer;
1705 }
1706 #endif
1707
1708 \f
1709 /* Routines */
1710
1711 /* reset() - Reset CPU and memory. */
1712 static void reset(machine_6502 *machine){
1713   int x, y;
1714   for ( y = 0; y < 32; y++ ){
1715     for (x = 0; x < 32; x++){
1716       machine->screen[x][y] = 0;
1717     }
1718   }
1719
1720   for(x=0; x < MEM_64K; x++)
1721     machine->memory[x] = 0;
1722
1723   machine->codeCompiledOK = FALSE;
1724   machine->regA = 0;
1725   machine->regX = 0;
1726   machine->regY = 0;
1727   machine->regP = setBit(machine->regP, FUTURE_FL, 1);
1728   machine->defaultCodePC = machine->regPC = PROG_START; 
1729   machine->regSP = STACK_TOP;
1730   machine->runForever = FALSE;
1731   machine->labelPtr = 0;
1732   machine->codeRunning = FALSE;
1733 }
1734
1735 /* hexDump() - Dump the memory to output */
1736 void m6502_hexDump(machine_6502 *machine, Bit16 start, Bit16 numbytes, FILE *output){
1737   Bit32 address;
1738   Bit32 i;
1739   for( i = 0; i < numbytes; i++){
1740     address = start + i;
1741     if ( (i&15) == 0 ) {
1742       fprintf(output,"\n%.4x: ", address);
1743     }
1744     fprintf(output,"%.2x%s",machine->memory[address], (i & 1) ? " ":"");
1745   }
1746   fprintf(output,"%s\n",(i&1)?"--":"");
1747 }
1748
1749 /* XXX */
1750 /* void save_program(machine_6502 *machine, char *filename){ */
1751 /*   FILE *ofp; */
1752 /*   Bit16 pc = PROG_START; */
1753 /*   Bit16 end = pc + machine->codeLen; */
1754 /*   Bit16 n; */
1755 /*   ofp = fopen(filename, "w"); */
1756 /*   if (!ofp) abort(); */
1757   
1758 /*   fprintf(ofp,"Bit8 prog[%d] =\n{",machine->codeLen); */
1759 /*   n = 1; */
1760 /*   while(pc < end) */
1761 /*     fprintf(ofp,"0x%.2x,%s",machine->memory[pc++],n++%10?" ":"\n"); */
1762 /*   fseek(ofp,-2,SEEK_CUR); */
1763 /*   fprintf(ofp,"};\n"); */
1764   
1765 /*   fclose(ofp); */
1766 /* } */
1767
1768 static BOOL translate(m6502_Opcodes *op,Param *param, machine_6502 *machine){
1769    switch(param->type){
1770     case SINGLE:
1771       if (op->SNGL)
1772         pushByte(machine, op->SNGL);
1773       else {
1774         fprintf(stderr,"%s needs a parameter.\n",op->name);
1775         return FALSE;
1776       }
1777       break;
1778     case IMMEDIATE_VALUE:
1779       if (op->Imm) {
1780         pushByte(machine, op->Imm);
1781         pushByte(machine, param->value[0]);
1782         break;
1783       }
1784       else {
1785         fprintf(stderr,"%s does not take IMMEDIATE_VALUE parameters.\n",op->name);
1786         return FALSE;
1787       }
1788     case IMMEDIATE_GREAT:
1789       if (op->Imm) {
1790         pushByte(machine, op->Imm);
1791         pushByte(machine, param->lbladdr >> 8);
1792         break;
1793       }
1794       else {
1795         fprintf(stderr,"%s does not take IMMEDIATE_GREAT parameters.\n",op->name);
1796         return FALSE;
1797       }
1798     case IMMEDIATE_LESS:
1799       if (op->Imm) {
1800         pushByte(machine, op->Imm);
1801         pushByte(machine, param->lbladdr & 0xFF);
1802         break;
1803       }
1804       else {
1805         fprintf(stderr,"%s does not take IMMEDIATE_LESS parameters.\n",op->name);
1806         return FALSE;
1807       }
1808     case INDIRECT_X:
1809       if (op->INDX) {
1810         pushByte(machine, op->INDX);
1811         pushByte(machine, param->value[0]);
1812         break;
1813       }
1814       else {
1815         fprintf(stderr,"%s does not take INDIRECT_X parameters.\n",op->name);
1816         return FALSE;
1817       }
1818     case INDIRECT_Y:
1819       if (op->INDY) {
1820         pushByte(machine, op->INDY);
1821         pushByte(machine, param->value[0]);
1822         break;
1823       }
1824       else {
1825         fprintf(stderr,"%s does not take INDIRECT_Y parameters.\n",op->name);
1826         return FALSE;
1827       }
1828     case ZERO:
1829       if (op->ZP) {
1830         pushByte(machine, op->ZP);
1831         pushByte(machine, param->value[0]);
1832         break;
1833       }
1834       else {
1835         fprintf(stderr,"%s does not take ZERO parameters.\n",op->name);
1836         return FALSE;
1837       }
1838     case ZERO_X:
1839       if (op->ZPX) {
1840         pushByte(machine, op->ZPX);
1841         pushByte(machine, param->value[0]);
1842         break;
1843       }
1844       else {
1845         fprintf(stderr,"%s does not take ZERO_X parameters.\n",op->name);
1846         return FALSE;
1847       }
1848     case ZERO_Y:
1849       if (op->ZPY) {
1850         pushByte(machine, op->ZPY);
1851         pushByte(machine, param->value[0]);
1852         break;
1853       }
1854       else {
1855         fprintf(stderr,"%s does not take ZERO_Y parameters.\n",op->name);
1856         return FALSE;
1857       }
1858     case ABS_VALUE:
1859       if (op->ABS) {
1860         pushByte(machine, op->ABS);
1861         pushWord(machine, param->value[0]);
1862         break;
1863       }
1864       else {
1865         fprintf(stderr,"%s does not take ABS_VALUE parameters.\n",op->name);
1866         return FALSE;
1867       }
1868     case ABS_OR_BRANCH:
1869       if (op->ABS > 0){
1870         pushByte(machine, op->ABS);
1871         pushWord(machine, param->lbladdr);
1872       }
1873       else {
1874         if (op->BRA) {
1875           pushByte(machine, op->BRA);
1876           {
1877             int diff = (param->lbladdr - machine->defaultCodePC);
1878             int backward = (param->lbladdr < machine->defaultCodePC);
1879             pushByte(machine, (backward) ? 0xff - diff : diff - 1);
1880           }
1881         }
1882         else {
1883           fprintf(stderr,"%s does not take BRANCH parameters.\n",op->name);
1884           return FALSE;
1885         }
1886       }
1887       break;
1888     case ABS_X:
1889       if (op->ABSX) {
1890         pushByte(machine, op->ABSX);
1891         pushWord(machine, param->value[0]);
1892         break;
1893       }
1894       else {
1895         fprintf(stderr,"%s does not take ABS_X parameters.\n",op->name);
1896         return FALSE;
1897       }
1898     case ABS_Y:
1899       if (op->ABSY) {
1900         pushByte(machine, op->ABSY);
1901         pushWord(machine, param->value[0]);
1902         break;
1903       }
1904       else {
1905         fprintf(stderr,"%s does not take ABS_Y parameters.\n",op->name);
1906         return FALSE;
1907       }
1908     case ABS_LABEL_X:
1909       if (op->ABSX) {
1910         pushByte(machine, op->ABSX);
1911         pushWord(machine, param->lbladdr);
1912         break;
1913       }
1914       else {
1915         fprintf(stderr,"%s does not take ABS_LABEL_X parameters.\n",op->name);
1916         return FALSE;
1917       }
1918     case ABS_LABEL_Y:
1919       if (op->ABSY) {
1920         pushByte(machine, op->ABSY);
1921         pushWord(machine, param->lbladdr);
1922         break;
1923       }
1924       else {
1925         fprintf(stderr,"%s does not take ABS_LABEL_Y parameters.\n",op->name);
1926         return FALSE;
1927       }
1928    case DCB_PARAM:
1929      /* Handled elsewhere */
1930      break;
1931    }
1932    return TRUE;
1933 }
1934
1935 /* compileLine() - Compile one line of code. Returns
1936    TRUE if it compile successfully. */
1937 static BOOL compileLine(AsmLine *asmline, void *args){
1938   machine_6502 *machine;
1939   machine = args;
1940   if (isBlank(asmline->command)) return TRUE;
1941   if (strcmp("*=",asmline->command) == 0){
1942     machine->defaultCodePC = asmline->param->value[0];
1943   }
1944   else if (strcmp("DCB",asmline->command) == 0){
1945     int i;
1946     for(i = 0; i < asmline->param->vp; i++)
1947       pushByte(machine, asmline->param->value[i]);
1948   }    
1949   else{
1950     int i;
1951     char *command = asmline->command;
1952     m6502_Opcodes op;
1953     for(i = 0; i < NUM_OPCODES; i++){
1954       if (strcmp(machine->opcodes[i].name, command) == 0){
1955         op = machine->opcodes[i];
1956         break;      
1957       }
1958     }
1959     if (i == NUM_OPCODES)
1960       return FALSE; /* unknow upcode */
1961     else
1962       return translate(&op,asmline->param,machine);
1963   }
1964   return TRUE;
1965 }
1966
1967 /* indexLabels() - Get the address for each label */
1968 static BOOL indexLabels(AsmLine *asmline, void *arg){
1969   machine_6502 *machine; 
1970   int thisPC;
1971   Bit16 oldDefault;
1972   machine = arg;
1973   oldDefault = machine->defaultCodePC;
1974   thisPC = machine->regPC;
1975   /* Figure out how many bytes this instruction takes */
1976   machine->codeLen = 0;
1977
1978   if ( ! compileLine(asmline, machine) ){
1979     return FALSE;
1980   }
1981
1982   /* If the machine's defaultCodePC has changed then we encountered a
1983      *= which changes the load address. We need to initials our code
1984      *counter with the current default. */
1985   if (oldDefault == machine->defaultCodePC){    
1986     machine->regPC += machine->codeLen;
1987   }
1988   else {
1989     machine->regPC = machine->defaultCodePC;
1990     /*oldDefault = machine->defaultCodePC;*/
1991   }
1992
1993   if (asmline->labelDecl) {
1994     asmline->label->addr = thisPC;
1995   }
1996    return TRUE; 
1997 }
1998
1999 static BOOL changeParamLabelAddr(AsmLine *asmline, void *label){
2000   Label *la = label;
2001   if (strcmp(asmline->param->label, la->label) == 0)
2002     asmline->param->lbladdr = la->addr;
2003   return TRUE;
2004 }
2005
2006 static BOOL linkit(AsmLine *asmline, void *asmlist){
2007   apply(asmlist,changeParamLabelAddr,asmline->label);
2008   return TRUE;
2009 }
2010
2011 /* linkLabels - Make sure all of the references to the labels contain
2012    the right address*/
2013 static void linkLabels(AsmLine *asmlist){
2014   apply(asmlist,linkit,asmlist);
2015 }
2016
2017 /* compileCode() - Compile the current assembly code for the machine */
2018 static BOOL compileCode(machine_6502 *machine, const char *code){
2019   BOOL codeOk;
2020   AsmLine *asmlist;
2021
2022   reset(machine);
2023   machine->defaultCodePC = machine->regPC = PROG_START;
2024   asmlist = parseAssembly(machine, &codeOk, code);
2025
2026   if(codeOk){
2027     /* First pass: Find the addresses for the labels */
2028     if (!apply(asmlist, indexLabels, machine))
2029       return FALSE;
2030     /* update label references */
2031     linkLabels(asmlist);
2032
2033 #if 0 /* prints out some debugging information */
2034     {
2035       AsmLine *p;
2036       if(asmlist != NULL){
2037         for (p = asmlist; p != NULL; p = p->next)
2038           fprintf(stderr,"%s lbl: %s addr: %d ParamLbl: %s ParamAddr: %d\n",
2039                   p->command, p->label->label, p->label->addr,
2040                   p->param->label, p->param->lbladdr);
2041             }
2042     }
2043
2044 #endif    
2045
2046     /* Second pass: translate the instructions */
2047     machine->codeLen = 0;
2048     /* Link label call push_byte which increments defaultCodePC.
2049        We need to reset it so the compiled code goes in the 
2050        correct spot. */
2051     machine->defaultCodePC = PROG_START;
2052     if (!apply(asmlist, compileLine, machine))
2053       return FALSE;
2054
2055     if (machine->defaultCodePC > PROG_START ){
2056       machine->memory[machine->defaultCodePC] = 0x00;
2057       codeOk = TRUE;
2058     }
2059     else{
2060       fprintf(stderr,"No Code to run.\n");
2061       codeOk = FALSE;
2062     }
2063   }
2064   else{
2065     fprintf(stderr,"An error occured while parsing the file.\n");  
2066     codeOk = FALSE;
2067   }
2068   freeallAsmLine(asmlist);
2069   return codeOk;
2070 }
2071
2072
2073 /*
2074  *  execute() - Executes one instruction.
2075  *              This is the main part of the CPU emulator.
2076  *
2077  */
2078
2079 static void execute(machine_6502 *machine){
2080   Bit8 opcode;
2081   m6502_AddrMode adm;
2082   int opidx;
2083
2084   if(!machine->codeRunning) return;
2085
2086   opcode = popByte(machine);
2087   if (opcode == 0x00)
2088     machine->codeRunning = FALSE;
2089   else {
2090     opidx = opIndex(machine,opcode,&adm);
2091     if(opidx > -1)
2092       machine->opcodes[opidx].func(machine, adm);
2093     else
2094       fprintf(stderr,"Invalid opcode!\n");
2095   }
2096   if( (machine->regPC == 0) || 
2097       (!machine->codeRunning) ) {
2098     machine->codeRunning = FALSE;
2099   }
2100 }
2101
2102 machine_6502 *m6502_build(void){
2103   machine_6502 *machine;
2104   machine = ecalloc(1, sizeof(machine_6502));
2105   assignOpCodes(machine->opcodes);
2106   buildIndexCache(machine);
2107   reset(machine);
2108   return machine;
2109 }
2110
2111 void m6502_destroy6502(machine_6502 *machine){
2112   free(machine);
2113   machine = NULL;
2114 }
2115
2116 void m6502_trace(machine_6502 *machine, FILE *output){
2117   Bit8 opcode = memReadByte(machine,machine->regPC);
2118   m6502_AddrMode adm;
2119   Pointer ptr;
2120   int opidx = opIndex(machine,opcode,&adm);
2121   int stacksz = STACK_TOP - machine->regSP;
2122
2123   fprintf(output,"\n   NVFBDIZC\nP: %d%d%d%d%d%d%d%d ",
2124          bitOn(machine->regP,NEGATIVE_FL),
2125          bitOn(machine->regP,OVERFLOW_FL),
2126          bitOn(machine->regP,FUTURE_FL),
2127          bitOn(machine->regP,BREAK_FL),
2128          bitOn(machine->regP,DECIMAL_FL),
2129          bitOn(machine->regP,INTERRUPT_FL),
2130          bitOn(machine->regP,ZERO_FL),
2131          bitOn(machine->regP,CARRY_FL));
2132   fprintf(output,"A: %.2x X: %.2x Y: %.2x SP: %.4x PC: %.4x\n",
2133          machine->regA, machine->regX, machine->regY, machine->regSP, machine->regPC);
2134   if (opidx > -1){
2135     Bit16 pc = machine->regPC;
2136     fprintf(output,"\n%.4x:\t%s",machine->regPC, machine->opcodes[opidx].name);
2137     if (peekValue(machine, adm, &ptr, pc+1))
2138       fprintf(output,"\tAddress:%.4x\tValue:%.4x\n",
2139              ptr.addr,ptr.value);
2140     else
2141       fprintf(output,"\n");
2142   }
2143   fprintf(output,"STACK:");
2144   m6502_hexDump(machine,(STACK_TOP - stacksz) + 1, stacksz, output);
2145 }
2146
2147 #if 0
2148 void disassemble(machine_6502 *machine, FILE *output){
2149   /* Read the opcode
2150      increment the program counter
2151      print the opcode
2152      loop until end of program. */
2153   m6502_AddrMode adm;
2154   Bit16 addr;
2155   Bit8 opcode;
2156   int opidx;
2157   char *mem;
2158   int i;
2159   Bit16 opc = machine->regPC;
2160   mem = calloc(20,sizeof(char));
2161   machine->regPC = PROG_START;
2162   do{
2163     addr = machine->regPC;
2164     opcode = popByte(machine);
2165     opidx = opIndex(machine,opcode,&adm);
2166     for (i = 0; i < 20; i++) mem[i] = '\0';
2167     dismem(machine, adm, mem);
2168     fprintf(output,"%x\t%s\t%s\n",
2169             addr,machine->opcodes[opidx].name,mem); 
2170   }while((machine->regPC - PROG_START) < machine->codeLen); /*XXX - may need to change since defaultCodePC */
2171   free(mem);
2172   machine->regPC = opc;
2173 }
2174 #endif
2175
2176 \f
2177 #ifdef READ_FILES
2178 void m6502_eval_file(machine_6502 *machine, const char *filename, m6502_Plotter plot, void *plotterState){
2179   char *code = NULL;
2180
2181   machine->plot = plot;
2182   machine->plotterState = plotterState;
2183
2184   code = fileToBuffer(filename);
2185   
2186   if (! compileCode(machine, code) ) abort();
2187
2188   free(code);
2189
2190   machine->defaultCodePC = machine->regPC = PROG_START;
2191   machine->codeRunning = TRUE;
2192   do{
2193     sleep(0); /* XXX */
2194 #if 0
2195     trace(machine);
2196 #endif
2197     execute(machine);
2198   }while(machine->codeRunning);
2199 }
2200
2201 void m6502_start_eval_file(machine_6502 *machine, const char *filename, m6502_Plotter plot, void *plotterState){
2202   char *code = NULL;
2203   reset(machine);
2204
2205   machine->plot = plot;
2206   machine->plotterState = plotterState;
2207
2208   code = fileToBuffer(filename);
2209   
2210   if (! compileCode(machine, code) ) abort();
2211
2212   free(code);
2213
2214   machine->defaultCodePC = machine->regPC = PROG_START;
2215   machine->codeRunning = TRUE;
2216   execute(machine);
2217 }
2218 #endif /* READ_FILES */
2219
2220 void m6502_start_eval_string(machine_6502 *machine, const char *code,
2221                        m6502_Plotter plot, void *plotterState){
2222   reset(machine);
2223
2224   machine->plot = plot;
2225   machine->plotterState = plotterState;
2226
2227   if (! compileCode(machine, code) ){
2228     fprintf(stderr,"Could not compile code.\n");
2229   }
2230
2231   machine->defaultCodePC = machine->regPC = PROG_START;
2232   machine->codeRunning = TRUE;
2233   execute(machine);
2234 }
2235
2236 /* void start_eval_binary(machine_6502 *machine, Bit8 *program, */
2237 /*                     unsigned int proglen, */
2238 /*                     Plotter plot, void *plotterState){ */
2239 /*   unsigned int pc, n; */
2240 /*   reset(machine); */
2241 /*   machine->plot = plot; */
2242 /*   machine->plotterState = plotterState; */
2243
2244 /*   machine->regPC = PROG_START; */
2245 /*   pc = machine->regPC; */
2246 /*   machine->codeLen = proglen; */
2247 /*   n = 0; */
2248 /*   while (n < proglen){ */
2249 /*     machine->memory[pc++] = program[n++]; */
2250 /*   } */
2251 /*   machine->codeRunning = TRUE; */
2252 /*   execute(machine); */
2253 /* } */
2254
2255 void m6502_next_eval(machine_6502 *machine, int insno){
2256   int i = 0;
2257   for (i = 1; i < insno; i++){
2258     if (machine->codeRunning){
2259 #if 0
2260       trace(machine, stdout);
2261 #endif
2262       execute(machine);
2263     }
2264     else
2265       break;
2266   }
2267 }
2268