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