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