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