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