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