/* #define NODOUBLEBUFFER - to disable colormap-based double-buffering (primarily useful to see individual lines as they are poked into the framebuffer registers in a debugger) #define MAMETOO_6502 - run the MAME 6502 emulator core in parallel, checking each against the other. #define MAMETOO_MATH - run the MAME mathbox emulator core in parallel, checking each against the other. Note that the MAME 6502 emulator always uses the assembly mathbox; the MAME mathbox code is not very amenable to running multiple instances of itself. */ /*#define MAMETOO_6502*/ /*#define MAMETOO_MATH*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern const char *__progname; #include "cg6.h" static const char *fbpath = "/dev/cgsix0"; static const char *kbpath = "/dev/kbd0"; static unsigned char cmap[16][3] = { { 0, 0, 0 }, { 0, 0, 255 }, { 0, 255, 0 }, { 0, 255, 255 }, { 255, 0, 0 }, { 255, 0, 255 }, { 255, 255, 0 }, { 255, 255, 255 }, { 160, 160, 160 }, { 0, 0, 255 }, { 0, 255, 0 }, { 0, 255, 255 }, { 255, 0, 0 }, { 255, 0, 255 }, { 255, 255, 0 }, { 255, 255, 255 } }; typedef struct xy XY; typedef struct ptvec PTVEC; typedef struct pshot PSHOT; typedef struct m6502state M6502STATE; typedef struct mathbox_state MATHBOX_STATE; struct mathbox_state { unsigned short int reg[16]; unsigned short int o; } ; struct m6502state { unsigned char a; unsigned char x; unsigned char y; unsigned char s; unsigned short int pc; unsigned char p; #define P_C 0x01 #define P_Z 0x02 #define P_I 0x04 #define P_D 0x08 #define P_B 0x10 #define P_T 0x20 #define P_V 0x40 #define P_N 0x80 unsigned char irqbits; signed int cycles; signed int until_3khz; signed int until_intr; unsigned int scratch[4]; /* for the .S code to use as it pleases */ } ; struct xy { double x; double y; } ; struct ptvec { int n; XY *pts; } ; #define PTVEC_ARRAY(a) { ASZ(a), &a[0] } struct pshot { PSHOT *link; int dead; int loc; double h; } ; static int fbfd; static int kbfd; static int ttfd; static volatile struct cg6fbc *fb; static volatile struct brooktree *bt; static volatile unsigned char *vram; static int dummy = 0; #ifdef MAMETOO_6502 static void jb6502_init(void); static void jb_compare(void); static void jb_step(void); /*static void jb_request_interrupt(void);*/ static MATHBOX_STATE jb_mathbox; static unsigned char jbmem[65536]; static unsigned short int jbwrites[8]; static int njbwrites; static M6502STATE m6502p; static void jb_copystate(void); static void jb_ramwrite(unsigned short int); #endif static M6502STATE m6502; static unsigned char mem[65536]; static unsigned char mtype[65536]; /* That MT_RAM==0 and MT_ROM==1 is wired fairly deeply into the code in t-s.S. Other values are not specially known there; if anything but 0 or 1 is encountered, it punts to C, so other values can be used freely. */ #define MT_RAM 0 #define MT_ROM 1 #define MT_SPECIAL 2 #define MT_BAD 3 static unsigned char pokey_skctl[2]; static unsigned char pokey_random[2]; static unsigned char *sw = &mem[0x0c00]; static unsigned char swm = 0x3f; #define EAROM_SIZE 0x40 static unsigned char earom[EAROM_SIZE]; static unsigned char earom_addr; static unsigned char earom_data; static MATHBOX_STATE mathbox; static unsigned char vsnap[0x2000]; static int videosnap; static unsigned char colour_lookup[16]; static unsigned int turning; #define TURN_L 1 #define TURN_R 2 static unsigned int spinner = 0; static int spinshift = 4; #define MIDX (1152/2) #define MIDY (900/2) #define RPSIZE 64 static unsigned long int randpool[RPSIZE]; static int rp; static int rmp; static int wantrender; static int drawbit; /* The assembly part of the 6502 emulator */ extern int s_emul(M6502STATE *, unsigned char *, unsigned char *); /* The assembly part of the vector generator */ extern int s_vg(const unsigned char *, volatile struct cg6fbc *, unsigned int, const unsigned char *); /* Mathbox assembly code. */ extern unsigned short int s_mb_0b(unsigned short int *, unsigned char); extern unsigned short int s_mb_11(unsigned short int *, unsigned char); extern unsigned short int s_mb_12(unsigned short int *); extern unsigned short int s_mb_13(unsigned short int *); extern unsigned short int s_mb_14(unsigned short int *); extern unsigned short int s_mb_1c(unsigned short int *, unsigned char); extern unsigned short int s_mb_1d(unsigned short int *, unsigned char); extern unsigned short int s_mb_1e(unsigned short int *); static __inline__ int incmod(int, int) __attribute__((__const__)); static __inline__ int incmod(int v, int m) { v ++; return((v>=m)?0:v); } static __inline__ int decmod(int, int) __attribute__((__const__)); static __inline__ int decmod(int v, int m) { v --; return((v<0)?m-1:v); } static void setcmap(int bit) { int i; int v; if (dummy) return; bt->addr = 0; for (i=0;i<=255;i++) { v = (bit ? (i >> 4) : i) & 15; bt->cmap = cmap[v][0] * 0x01000000; bt->cmap = cmap[v][1] * 0x01000000; bt->cmap = cmap[v][2] * 0x01000000; } } static void drain(void) { if (! dummy) while (fb->s & 0x10000000) ; } static void draw(void) { if (! dummy) while ((fb->draw & 0xa0000000) == 0xa0000000) ; } static void fbrect(int fg, int x1, int y1, int x2, int y2) { if (dummy) return; fb->fg = 0x11 * fg; fb->arecty = y1; fb->arectx = x1; fb->arecty = y2; fb->arectx = x2; draw(); } static void setupfb(void) { void *mrv; struct fbgattr a; if (dummy) return; fbfd = open(fbpath,O_RDWR,0); if (fbfd < 0) { fprintf(stderr,"%s: %s: %s\n",__progname,fbpath,strerror(errno)); exit(1); } if ( (ioctl(fbfd,FBIOGATTR,&a) < 0) || (a.fbtype.fb_type != FBTYPE_SUNFAST_COLOR) || (a.fbtype.fb_width != 1152) || (a.fbtype.fb_height != 900) || (a.fbtype.fb_depth != 8) ) { close(fbfd); fprintf(stderr,"%s: %s: not a cg6\n",__progname,fbpath); exit(1); } mrv = mmap(0,0x16000+a.fbtype.fb_size,PROT_READ|PROT_WRITE,MAP_SHARED,fbfd,0x70000000); if (mrv == MAP_FAILED) { fprintf(stderr,"%s: can't mmap %s: %s\n",__progname,fbpath,strerror(errno)); exit(1); } fb = mrv; bt = (void *)(0x2000+(unsigned char *)mrv); vram = 0x16000 + (unsigned char *)mrv; drawbit = 0; fb->bg = 0; fb->pixelm = ~0; fb->s = 0; fb->mode = MODE_NORMAL | MODE_COLOR8; fb->alu = ALU_NORMAL | ALU_FG; fb->clip = 0; fb->offx = 0; fb->offy = 0; fb->clipminx = 0; fb->clipminy = 0; fb->clipmaxx = 1151; fb->clipmaxy = 899; fb->pm = ~0; drain(); fb->clipminx = 0; fb->clipminy = 0; fb->clipmaxx = 1151; fb->clipmaxy = 899; #ifdef NODOUBLEBUFFER fb->pm = ~0; #else fb->pm = 15; #endif } static void setupkb(void) { int type; int mode; kbfd = open(kbpath,O_RDWR,0); if (kbfd < 0) { fprintf(stderr,"%s: can't open %s: %s\n",__progname,kbpath,strerror(errno)); exit(1); } if ( (ioctl(kbfd,KIOCTYPE,&type) < 0) || (type != KB_SUN3) ) { close(kbfd); fprintf(stderr,"%s: %s isn't a type-3\n",__progname,kbpath); exit(1); } mode = 1; ioctl(kbfd,KIOCSDIRECT,&mode); mode = TR_UNTRANS_EVENT; ioctl(kbfd,KIOCTRANS,&mode); mode = 1; ioctl(kbfd,FIONBIO,&mode); } static void setuptimer(void) { struct itimerval itv; ttfd = socket(AF_TIMER,SOCK_STREAM,0); if (ttfd < 0) { fprintf(stderr,"%s: timer socket: %s\n",__progname,strerror(errno)); exit(1); } itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 10000; itv.it_interval = itv.it_value; write(ttfd,&itv,sizeof(itv)); } static unsigned long int rnd(void) { int prp; prp = rp++; if (rp >= RPSIZE) rp = 0; randpool[prp] += randpool[rp]; return(randpool[prp]); } static void initrandom(void) { int i; struct timeval tv; randpool[0] = 1; randpool[1] = getpid(); gettimeofday(&tv,0); randpool[2] = tv.tv_sec; randpool[3] = tv.tv_usec; for (i=4;i> 1) ^ ((v & 1) ? 0xedb88320 : 0); randpool[rmp] = v; rmp ++; if (rmp >= RPSIZE) rmp = 0; } } static void reset_6502(void) { m6502.pc = (mem[0xfffd] << 8) | mem[0xfffc]; m6502.p = P_T | P_I | P_Z; m6502.irqbits = 0; #ifdef MAMETOO_6502 jb6502_init(); #endif m6502.cycles = 0; m6502.until_3khz = 0; m6502.until_intr = 0; write(1,"*",1); } static int checkkb(void) { struct firm_event ev; int r; r = read(kbfd,&ev,sizeof(ev)); if (r == sizeof(ev)) { rnd_tweak(&ev,sizeof(ev)); switch ((ev.id & 0x7f) | ((ev.value == VKEY_UP) ? 0x80 : 0)) { default: printf("kbd: %d ",ev.id&0x7f); printf((ev.value==VKEY_UP)?"up\n":"dn\n"); break; /* R3 */ case 23 : exit(0); break; /* Backspace */ case 43 : reset_6502(); break; case 43|0x80: break; /* L1 */ case 1 : sw = &mem[0x0c00]; swm = 0x3f; break; case 1|0x80: break; /* L3 */ case 25 : sw = &mem[0x0d00]; swm = 0xff; break; case 25|0x80: break; /* L5 */ case 49 : sw = &mem[0x0e00]; swm = 0xff; break; case 49|0x80: break; /* L7 */ case 72 : sw = &mem[0x60c8]; swm = 0xf0; break; case 72|0x80: break; /* L9 */ case 95 : sw = &mem[0x60d8]; swm = 0xff; break; case 95|0x80: break; /* 1 */ case 30 : if (swm & 0x80) *sw ^= 0x80; break; case 30|0x80: break; /* 2 */ case 31 : if (swm & 0x40) *sw ^= 0x40; break; case 31|0x80: break; /* 3 */ case 32 : if (swm & 0x20) *sw ^= 0x20; break; case 32|0x80: break; /* 4 */ case 33 : if (swm & 0x10) *sw ^= 0x10; break; case 33|0x80: break; /* 5 */ case 34 : if (swm & 0x08) *sw ^= 0x08; break; case 34|0x80: break; /* 6 */ case 35 : if (swm & 0x04) *sw ^= 0x04; break; case 35|0x80: break; /* 7 */ case 36 : if (swm & 0x02) *sw ^= 0x02; break; case 36|0x80: break; /* 8 */ case 37 : if (swm & 0x01) *sw ^= 0x01; break; case 37|0x80: break; /* Caps */ case 119 : turning |= TURN_L; break; case 119|0x80: turning &= ~TURN_L; break; /* Left */ case 120 : turning |= TURN_R; break; case 120|0x80: turning &= ~TURN_R; break; /* L8 */ case 73 : if (spinshift > 0) spinshift --; break; case 73|0x80: break; /* L10 */ case 97 : if (spinshift < 30) spinshift ++; break; case 97|0x80: break; /* Right */ case 122 : mem[0xc0d8] |= 0x10; break; /* fire */ case 122|0x80: mem[0xc0d8] &= ~0x10; break; /* Alternate */ case 19 : mem[0xc0d8] |= 0x08; break; /* zap */ case 19|0x80: mem[0xc0d8] &= ~0x08; break; /* R1 */ case 21 : videosnap = 1; break; case 21|0x80: break; /* F1 */ case 5 : mem[0xc0d8] |= 0x20; break; /* p1 start */ case 5|0x80: mem[0xc0d8] &= ~0x20; break; /* F2 */ case 6 : mem[0xc0d8] |= 0x40; break; /* p2 start */ case 6|0x80: mem[0xc0d8] &= ~0x40; break; /* R13 */ case 112 : mem[0x0c00] &= ~0x04; break; case 112|0x80: mem[0x0c00] |= 0x04; break; /* R14 */ case 113 : mem[0x0c00] &= ~0x02; break; case 113|0x80: mem[0x0c00] |= 0x02; break; /* R15 */ case 114 : mem[0x0c00] &= ~0x01; break; case 114|0x80: mem[0x0c00] |= 0x01; break; } return(1); } return(0); } static void checktt(void) { struct timersock_event tse; int r; int inc; static int n = 0; r = read(ttfd,&tse,sizeof(tse)); if (r < 0) { fprintf(stderr,"%s: timer socket read: %s\n",__progname,strerror(errno)); exit(1); } if (r == 0) { fprintf(stderr,"%s: timer socket EOF\n",__progname); exit(1); } if (n < 1) { write(1,".",1); n += 100; } n --; inc = 0; switch (turning) { case TURN_L: inc = 1; break; case TURN_R: inc = -1; break; } if (inc) { spinner += inc; mem[0x60c8] = (mem[0x60c8] & 0xf0) | ((spinner >> spinshift) & 0x0f); } } static void mayberender(void) { if (! wantrender) return; write(1,"r",1); wantrender = 0; if (! dummy) { drain(); setcmap(drawbit); drawbit = ! drawbit; #ifndef NODOUBLEBUFFER fb->pm = drawbit ? 0xf0 : 0x0f; #endif fbrect(0,0,0,1151,899); } if (videosnap) { FILE *f; f = fopen("vgsnap","w"); fwrite(&vsnap[0],sizeof(vsnap),1,f); fclose(f); videosnap = 0; } s_vg(&vsnap[0],fb,rnd(),&colour_lookup[0]); } static void loadmem(unsigned short int addr, unsigned short int len, const char *fn) { int fd; int n; fd = open(fn,O_RDONLY,0); if (fd < 0) { fprintf(stderr,"%s: can't read %s: %s\n",__progname,fn,strerror(errno)); exit(1); } n = read(fd,&mem[addr],len); if (n < 0) { fprintf(stderr,"%s: read error on %s: %s\n",__progname,fn,strerror(errno)); exit(1); } if (n != len) { fprintf(stderr,"%s: reading %s wanted %d, got %d\n",__progname,fn,(int)len,n); exit(1); } close(fd); } static void die(int save) { if (save) { FILE *f; f = fopen(".state","w"); if (f) { int i; putc(m6502.a,f); putc(m6502.x,f); putc(m6502.y,f); putc(m6502.s,f); putc(m6502.pc&0xff,f); putc(m6502.pc>>8,f); putc(m6502.p,f); putc(m6502.irqbits,f); for (i=0;i<65536;i++) if (mtype[i] == MT_RAM) putc(mem[i],f); fwrite(&pokey_skctl[0],1,2,f); fwrite(&pokey_random[0],1,2,f); fwrite(&earom[0],1,EAROM_SIZE,f); putc(earom_addr,f); putc(earom_data,f); for (i=0;i<16;i++) { putc(mathbox.reg[i]&0xff&0xff,f); putc(mathbox.reg[i]>>8&0xff,f); } putc(mathbox.o&0xff&0xff,f); putc(mathbox.o>>8&0xff,f); fwrite(&colour_lookup[0],1,16,f); putc(spinner&0xff,f); putc((spinner>>8)&0xff,f); putc((spinner>>16)&0xff,f); putc((spinner>>24)&0xff,f); putc(spinshift,f); fclose(f); } } exit(1); } #ifndef MAMETOO_MATH /* Dummy to keep external references from the MAME mathbox code happy */ FILE *mb_errorlog; #else #include "mathbox.h" FILE *mb_errorlog; static MATHBOX_STATE mathbox_pre; static void mb_set(void) { mb_set_state(&mathbox.reg[0],mathbox.o); mb_errorlog = stderr; } static void mb_compare(int a, unsigned char v) { MATHBOX_STATE s; int i; mb_get_state(&s.reg[0],&s.o); do <"chk"> { for (i=0;i<16;i++) if (s.reg[i] != mathbox.reg[i]) break <"chk">; if (s.o != mathbox.o) break <"chk">; return; } while (0); printf("op %02x, data %02x\n",a,v); printf(" pre MAME Mouse\n"); for (i=0;i<16;i++) printf("%x %04x %04x %04x%s\n",i,mathbox_pre.reg[i],s.reg[i],mathbox.reg[i],(s.reg[i]==mathbox.reg[i])?"":" *"); printf(" = %04x %04x %04x%s\n",mathbox_pre.o,s.o,mathbox.o,(s.o==mathbox.o)?"":" *"); for (i=0;i<16;i++) printf("%x ",mathbox_pre.reg[i]); printf("%x %x %x\n",mathbox_pre.o,a,v); exit(1); } #endif static void setupemul(void) { memset(&mtype[0],MT_BAD,65536); memset(&mtype[0x0000],MT_RAM,0x0800); memset(&mtype[0x0800],MT_SPECIAL,0x0010); mtype[0x0c00] = MT_ROM; mem[0x0c00] = 0x00; /* sw1 */ mtype[0x0d00] = MT_ROM; mem[0x0d00] = 0x00; /* sw2 */ mtype[0x0e00] = MT_ROM; mem[0x0e00] = 0x00; /* sw3 */ memset(&mtype[0x2000],MT_RAM,0x1000); memset(&mtype[0x3000],MT_ROM,0x1000); mtype[0x4000] = MT_SPECIAL; mtype[0x4800] = MT_SPECIAL; mtype[0x5000] = MT_SPECIAL; mtype[0x5800] = MT_SPECIAL; memset(&mtype[0x6000],MT_SPECIAL,0x0040); mtype[0x6040] = MT_ROM; mem[0x6040] = 0; /* mathbox status: never busy */ mtype[0x6050] = MT_SPECIAL; mtype[0x6060] = MT_SPECIAL; mtype[0x6070] = MT_SPECIAL; memset(&mtype[0x6080],MT_SPECIAL,0x0020); memset(&mtype[0x60c0],MT_SPECIAL,0x0010); mtype[0x60c8] = MT_ROM; mem[0x60c8] = 0x00; /* pokey #1 input reg */ memset(&mtype[0x60d0],MT_SPECIAL,0x0010); mtype[0x60d8] = MT_ROM; mem[0x60d8] = 0x00; /* pokey #2 input reg */ mtype[0x60e0] = MT_SPECIAL; memset(&mtype[0x9000],MT_ROM,0x5000); memset(&mtype[0xfff0],MT_ROM,0x0010); loadmem(0x9000,0x0800,"136002.113"); loadmem(0x9800,0x0800,"136002.114"); loadmem(0xa000,0x0800,"136002.115"); loadmem(0xa800,0x0800,"136002.316"); loadmem(0xb000,0x0800,"136002.217"); loadmem(0xb800,0x0800,"136002.118"); loadmem(0xc000,0x0800,"136002.119"); loadmem(0xc800,0x0800,"136002.120"); loadmem(0xd000,0x0800,"136002.121"); loadmem(0xd800,0x0800,"136002.222"); loadmem(0x3000,0x0800,"136002.123"); loadmem(0x3800,0x0800,"136002.124"); bcopy(&mem[0xdff0],&mem[0xfff0],0x0010); pokey_skctl[0] = 0x03; pokey_skctl[1] = 0x03; pokey_random[0] = rnd() >> 22; pokey_random[1] = rnd() >> 22; reset_6502(); #ifdef MAMETOO_MATH mb_set(); #endif } static void loadstate(void) { FILE *f; f = fopen(".state","r"); if (f) { int i; m6502.a = getc(f); m6502.x = getc(f); m6502.y = getc(f); m6502.s = getc(f); m6502.pc = getc(f); m6502.pc |= getc(f) << 8; m6502.p = getc(f); m6502.irqbits = getc(f); for (i=0;i<65536;i++) if (mtype[i] == MT_RAM) mem[i] = getc(f); fread(&pokey_skctl[0],1,2,f); fread(&pokey_random[0],1,2,f); fread(&earom[0],1,EAROM_SIZE,f); earom_addr = getc(f); earom_data = getc(f); for (i=0;i<16;i++) { mathbox.reg[i] = getc(f); mathbox.reg[i] |= getc(f) << 8; } mathbox.o = getc(f); mathbox.o |= getc(f) << 8; fread(&colour_lookup[0],1,16,f); spinner = getc(f); spinner |= getc(f) << 8; spinner |= getc(f) << 16; spinner |= getc(f) << 24; spinshift = getc(f); #ifdef MAMETOO_6502 jb6502_init(); #endif #ifdef MAMETOO_MATH mb_set(); #endif fclose(f); } } static unsigned char rmem1(unsigned short int a) { switch (mtype[a]) { case MT_RAM: case MT_ROM: return(mem[a]); break; case MT_SPECIAL: switch (a) { default: fprintf(stderr,"Read from unsupported special %04x at %04x\n",a,m6502.pc); die(1); break; case 0x6050: return(earom_data); break; case 0x6060: return(mathbox.o&0xff); break; case 0x6070: return(mathbox.o>>8); break; case 0x60c0 ... 0x60c7: case 0x60c9 ... 0x60cf: /* pokey #1 */ { int px; int ca; px = 0; if (0) { case 0x60d0 ... 0x60d7: case 0x60d9 ... 0x60df: /* pokey #2 */ px = 1; } ca = a & 0x000f; switch (ca) { default: fprintf(stderr,"Read from unsupported pokey register [%04x] at %04x\n",a,m6502.pc); die(1); break; case 0xa: /* RANDOM */ if (pokey_skctl[px] & 3) pokey_random[px] = rnd() >> 22; return(pokey_random[px]); break; } } break; } break; case MT_BAD: fprintf(stderr,"Read from bad location %04x at %04x\n",a,m6502.pc); die(0); break; } abort(); } static unsigned short int rmem2(unsigned short int a) { return(rmem1(a)+(rmem1(a+1)<<8)); } static void vg_reset(void) { } static void vg_go(void) { static int first = 1; if (first) { bcopy(&mem[0x3000],&vsnap[0x1000],0x1000); first = 0; } bcopy(&mem[0x2000],&vsnap[0],0x1000); wantrender = 1; write(1,"g",1); } static void mathbox_write(MATHBOX_STATE *b, int a, unsigned char v) { switch (a) { default: abort(); break; #define SETREGL(rno) do { \ b->reg[rno] = b->o = (b->reg[rno] & 0xff00) | v; \ } while (0) #define SETREGH(rno) do { \ b->reg[rno] = b->o = (b->reg[rno] & 0x00ff) | (v << 8); \ } while (0) #define R(n) b->reg[n] case 0x00: SETREGL(0); break; case 0x01: SETREGH(0); break; case 0x02: SETREGL(1); break; case 0x03: SETREGH(1); break; case 0x04: SETREGL(2); break; case 0x05: SETREGH(2); break; case 0x06: SETREGL(3); break; case 0x07: SETREGH(3); break; case 0x08: SETREGL(4); break; case 0x09: SETREGH(4); break; case 0x0a: SETREGL(5); break; case 0x0b: b->o = s_mb_0b(&b->reg[0],v); break; case 0x0c: R(6) = b->o = v; break; case 0x0d: SETREGL(10); break; case 0x0e: SETREGH(10); break; case 0x0f: SETREGL(11); break; case 0x10: SETREGH(11); break; case 0x11: b->o = s_mb_11(&b->reg[0],v); break; case 0x12: b->o = s_mb_12(&b->reg[0]); break; case 0x13: b->o = s_mb_13(&b->reg[0]); break; case 0x14: b->o = s_mb_14(&b->reg[0]); break; case 0x15: SETREGL(7); break; case 0x16: SETREGH(7); break; case 0x17: b->o = R(7); break; case 0x18: b->o = R(9); break; case 0x19: b->o = R(8); break; case 0x1a: SETREGL(8); break; case 0x1b: SETREGH(8); break; case 0x1c: b->o = s_mb_1c(&b->reg[0],v); break; case 0x1d: b->o = s_mb_1d(&b->reg[0],v); break; case 0x1e: b->o = s_mb_1e(&b->reg[0]); break; case 0x1f: /* Does this function actually do anything? Not in MAME, for what that may be worth.... */ break; } #undef SETREGL #undef SETREGH #undef R #undef SLIR } static void set_colorram(int x, int v) { static int map[16] = { 7, 15, 3, 11, 6, 14, 2, 10, 5, 13, 1, 9, 4, 12, 0, 8 }; colour_lookup[x] = map[v&0xf]; } static void wmem1(unsigned short int a, unsigned char v) { switch (mtype[a]) { case MT_RAM: mem[a] = v; break; case MT_ROM: break; case MT_SPECIAL: switch (a) { default: fprintf(stderr,"Write to unsupported special %04x at %04x\n",a,m6502.pc); die(1); break; case 0x0800 ... 0x080f: set_colorram(a&0xf,v); break; case 0x4000: /* coin counters and video invert bits */ break; case 0x4800: vg_go(); break; case 0x5000: /* reset watchdog */ break; case 0x5800: vg_reset(); break; case 0x6000 ... 0x603f: earom_addr = a - 0x6000; earom_data = v; if (earom_addr >= EAROM_SIZE) abort(); break; case 0x6040: if (v & 1) earom_data = earom[earom_addr]; if ((v & 0x0c) == 0x0c) earom[earom_addr] = earom_data; break; case 0x6080 ... 0x609f: /* mathbox */ #ifdef MAMETOO_MATH mathbox_pre = mathbox; #endif mathbox_write(&mathbox,a&0x1f,v); #ifdef MAMETOO_MATH mb_go(a&0x1f,v); mb_compare(a&0x1f,v); #endif break; case 0x60c0 ... 0x60cf: /* pokey #1 */ { int px; int ca; px = 0; if (0) { case 0x60d0 ... 0x60df: /* pokey #2 */ px = 1; } ca = a & 0x000f; switch (ca) { default: fprintf(stderr,"Write to unsupported pokey register [%04x] at %04x\n",a,m6502.pc); die(1); break; case 0x0: /* AUDF1 */ case 0x1: /* AUDC1 */ case 0x2: /* AUDF2 */ case 0x3: /* AUDC2 */ case 0x4: /* AUDF3 */ case 0x5: /* AUDC3 */ case 0x6: /* AUDF4 */ case 0x7: /* AUDC4 */ case 0x8: /* AUDCTL */ case 0xb: /* POTGO */ break; case 0xf: /* SKCTL */ pokey_skctl[px] = v; break; } } break; case 0x60e0: /* set player-start LEDs and FLIP bit */ break; } break; case MT_BAD: fprintf(stderr,"Write to bad location %04x at %04x\n",a,m6502.pc); die(0); break; default: abort(); break; } } static void set_nz(unsigned char v) { if (v == 0) m6502.p |= P_Z; else m6502.p &= ~P_Z; if (v & 0x80) m6502.p |= P_N; else m6502.p &= ~P_N; } static void do_cmp(unsigned char v1, unsigned char v2) { if (v1 >= v2) m6502.p |= P_C; else m6502.p &= ~P_C; set_nz(v1-v2); } static void c_emul(void) { unsigned char opc; opc = rmem1(m6502.pc); switch (opc) { default: fprintf(stderr,"Unsupported opcode %02x at %04x\n",opc,m6502.pc); die(1); break; case 0x2c: /* 2c op mn = bit $mnop */ { unsigned char t; t = rmem1(rmem2(m6502.pc+1)); m6502.p = (m6502.p & ~(P_N|P_V|P_Z)) | (t & (P_N|P_V)) | ((t&m6502.a) ? 0 : P_Z); } m6502.pc += 3; break; case 0x4d: /* 4d op mn = eor $mnop */ m6502.a ^= rmem1(rmem2(m6502.pc+1)); set_nz(m6502.a); m6502.pc += 3; break; case 0x8c: /* 8c op mn = sty $mnop */ wmem1(rmem2(m6502.pc+1),m6502.y); m6502.pc += 3; break; case 0x8d: /* 8d op mn = sta $mnop */ wmem1(rmem2(m6502.pc+1),m6502.a); m6502.pc += 3; break; case 0x8e: /* 8e op mn = stx $mnop */ wmem1(rmem2(m6502.pc+1),m6502.x); m6502.pc += 3; break; case 0x99: /* 99 op mn = sta $mnop,y */ wmem1(rmem2(m6502.pc+1)+m6502.y,m6502.a); m6502.pc += 3; break; case 0x9d: /* 9d op mn = sta $mnop,x */ wmem1(rmem2(m6502.pc+1)+m6502.x,m6502.a); m6502.pc += 3; break; case 0xac: /* ac op mn = ldy $mnop */ m6502.y = rmem1(rmem2(m6502.pc+1)); set_nz(m6502.y); m6502.pc += 3; break; case 0xad: /* ad op mn = lda $mnop */ m6502.a = rmem1(rmem2(m6502.pc+1)); set_nz(m6502.a); m6502.pc += 3; break; case 0xcc: /* cc op mn = cpy $mnop */ do_cmp(m6502.y,rmem1(rmem2(m6502.pc+1))); m6502.pc += 3; break; case 0xcd: /* cd op mn = cmp $mnop */ do_cmp(m6502.a,rmem1(rmem2(m6502.pc+1))); m6502.pc += 3; break; } } #if 0 static void foo(void) { int n; int i; int a; unsigned char v; unsigned int ascan; unsigned int vscan; while (1) { if (scanf("%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%x%x", &mathbox.reg[0], &mathbox.reg[1], &mathbox.reg[2], &mathbox.reg[3], &mathbox.reg[4], &mathbox.reg[5], &mathbox.reg[6], &mathbox.reg[7], &mathbox.reg[8], &mathbox.reg[9], &mathbox.reg[10],&mathbox.reg[11], &mathbox.reg[12],&mathbox.reg[13],&mathbox.reg[14],&mathbox.reg[15], &mathbox.o, &ascan, &vscan) != 19) break; mathbox_pre = mathbox; mb_set_state(&mathbox.reg[0],mathbox.o); mb_go(ascan,vscan); mathbox_write(&mathbox,ascan,vscan); mb_compare(ascan,vscan); } initrandom(); n = 0; while (1) { for (i=0;i<16;i++) mathbox.reg[i] = rnd(); a = rnd() & 0x1f; v = rnd() & 0xff; mathbox.o = rnd(); mathbox_pre = mathbox; mb_set_state(&mathbox.reg[0],mathbox.o); mb_go(a,v); mathbox_write(&mathbox,a,v); mb_compare(a,v); n ++; if ((n & 1023) == 0) write(1,".",1); } } #endif #if 0 #include #include static void foo(void) { int n; int i; int a; unsigned char v; unsigned int ascan; unsigned int vscan; int sock; struct sockaddr_in sin; FILE *fr; FILE *fw; MATHBOX_STATE s; static void doit(int a, unsigned char v) { int i; mathbox_pre = mathbox; mathbox_write(&mathbox,a,v); for (i=0;i<16;i++) fprintf(fw,"%x ",mathbox.reg[i]); fprintf(fw,"%x %x %x\n",mathbox.o,a,v); fflush(fw); if (fscanf(fr,"%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx", &s.reg[0], &s.reg[1], &s.reg[2], &s.reg[3], &s.reg[4], &s.reg[5], &s.reg[6], &s.reg[7], &s.reg[8], &s.reg[9], &s.reg[10],&s.reg[11], &s.reg[12],&s.reg[13],&s.reg[14],&s.reg[15], &s.o) != 17) exit(0); do <"chk"> { for (i=0;i<16;i++) if (s.reg[i] != mathbox.reg[i]) break <"chk">; if (s.o != mathbox.o) break <"chk">; return; } while (0); printf("op %02x, data %02x\n",a,v); printf(" pre i386 sparc\n"); for (i=0;i<16;i++) printf("%x %04x %04x %04x%s\n",i,mathbox_pre.reg[i],s.reg[i],mathbox.reg[i],(s.reg[i]==mathbox.reg[i])?"":" *"); printf(" = %04x %04x %04x%s\n",mathbox_pre.o,s.o,mathbox.o,(s.o==mathbox.o)?"":" *"); for (i=0;i<16;i++) printf("%x ",mathbox_pre.reg[i]); printf("%x %x %x\n",mathbox_pre.o,a,v); exit(1); } sock = socket(AF_INET,SOCK_STREAM,0); bzero(&sin,sizeof(sin)); sin.sin_family = AF_INET; sin.sin_len = sizeof(sin); sin.sin_addr.s_addr = htonl(0x0a010103); sin.sin_port = htons(5555); connect(sock,(void *)&sin,sizeof(sin)); fr = fdopen(sock,"r"); fw = fdopen(sock,"w"); while (1) { if (scanf("%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%hx%x%x", &mathbox.reg[0], &mathbox.reg[1], &mathbox.reg[2], &mathbox.reg[3], &mathbox.reg[4], &mathbox.reg[5], &mathbox.reg[6], &mathbox.reg[7], &mathbox.reg[8], &mathbox.reg[9], &mathbox.reg[10],&mathbox.reg[11], &mathbox.reg[12],&mathbox.reg[13],&mathbox.reg[14],&mathbox.reg[15], &mathbox.o, &ascan, &vscan) != 19) break; doit(ascan,vscan); } initrandom(); n = 0; while (1) { for (i=0;i<16;i++) mathbox.reg[i] = rnd(); a = rnd() & 0x1f; v = rnd() & 0xff; mathbox.o = rnd(); doit(a,v); n ++; if ((n & 1023) == 0) write(1,".",1); } } #endif int main(void); int main(void) { setupfb(); setupkb(); setuptimer(); initrandom(); setupemul(); loadstate(); while (1) { if (m6502.cycles < 1) { checktt(); m6502.cycles += 15000; } #ifdef MAMETOO_6502 { int cyc; cyc = m6502.cycles; m6502.cycles = 1; jb_compare(); m6502p = m6502; if (s_emul(&m6502,&mem[0],&mtype[0])) c_emul(); jb_copystate(); jb_step(); m6502.cycles += cyc - 1; } #else if (s_emul(&m6502,&mem[0],&mtype[0])) c_emul(); #endif checkkb(); mayberender(); } } #ifndef MAMETOO_6502 /* Dummies to keep external references from the MAME 6502 code happy */ #include "m6502.h" void cpu_writemem16(unsigned short int a __attribute__((__unused__)), unsigned char v __attribute__((__unused__))) { abort(); } unsigned char cpu_readmem16(unsigned short int a __attribute__((__unused__))) { abort(); } FILE *errorlog; #else /* ...the rest of the file is ifdef MAMETOO_6502 */ #include "m6502.h" #include "m6502glue.h" #include "mathbox.h" FILE *errorlog; static m6502_Regs jb6502p; extern m6502_Regs jb6502; static int jb6502_callback(int arg __attribute__((__unused__))) { m6502_set_irq_line(0,0); return(0); } static void jb_copystate(void) { jbmem[0x0c00] = mem[0x0c00]; if (m6502.irqbits & 8) { m6502.irqbits &= ~8; jb6502.pending_irq = 1; } } static void jb6502_init(void) { m6502_Regs t; bcopy(&mem[0],&jbmem[0],65536); m6502_reset(); m6502_get_context(&t); t.a = m6502.a; t.x = m6502.x; t.y = m6502.y; t.sp.b.l = m6502.s; t.pc.b.l = m6502.pc & 0xff; t.pc.b.h = m6502.pc >> 8; t.p = m6502.p; t.pending_irq = (m6502.irqbits & 0x02) ? 1 : 0; m6502_set_context(&t); m6502_set_irq_callback(jb6502_callback); m6502_set_irq_line(0,(m6502.irqbits&0x01)?1:0); jb_mathbox = mathbox; errorlog = stderr; njbwrites = 0; } static void dumpstate_m(FILE *f, M6502STATE *sp) { fprintf(f,"a=%02x x=%02x y=%02x s=%02x pc=%04x p=%02x irq=%d",sp->a,sp->x,sp->y,sp->s,sp->pc,sp->p,sp->irqbits); } static void dumpstate_jb(FILE *f, m6502_Regs *sp) { fprintf(f,"a=%02x x=%02x y=%02x s=%02x pc=%04x p=%02x irq pend=%d after=%d state=%d",sp->a,sp->x,sp->y,sp->sp.b.l,sp->pc.w.l,sp->p,sp->pending_irq,sp->after_cli,sp->irq_state); } static void jb_compare(void) { m6502_Regs t; int i; m6502_get_context(&t); if ((m6502.a != t.a) || (m6502.x != t.x) || (m6502.y != t.y) || (m6502.s != t.sp.b.l) || (m6502.pc != t.pc.d) || (m6502.p != t.p)) { fprintf(stderr,"State comparison failed\a\n"); printf("M prev: "); dumpstate_m(stdout,&m6502p); printf("\nJB prev: "); dumpstate_jb(stdout,&jb6502p); printf("\nM cur: "); dumpstate_m(stdout,&m6502); printf("\nJB cur: "); dumpstate_jb(stdout,&jb6502); printf("\n"); fflush(0); die(1); } for (i=0;i 7) abort(); jbwrites[njbwrites++] = a; } #if 0 static void jb_request_interrupt(void) { m6502_set_irq_line(0,1); } #endif static void jb_step(void) { jb6502p = jb6502; m6502_execute(0); } unsigned char cpu_readmem16(unsigned short int a) { switch (mtype[a]) { case MT_RAM: case MT_ROM: return(jbmem[a]); break; case MT_SPECIAL: switch (a) { default: fprintf(stderr,"Read from unsupported special %04x at %04x\n",a,m6502.pc); die(1); break; case 0x6050: return(earom_data); break; case 0x6060: return(jb_mathbox.o&0xff); break; case 0x6070: return(jb_mathbox.o>>8); break; case 0x60c0 ... 0x60c7: case 0x60c9 ... 0x60cf: /* pokey #1 */ { int px; int ca; px = 0; if (0) { case 0x60d0 ... 0x60d7: case 0x60d9 ... 0x60df: /* pokey #2 */ px = 1; } ca = a & 0x000f; switch (ca) { default: fprintf(stderr,"Read from unsupported pokey register [%04x] at %04x\n",a,m6502.pc); die(1); break; case 0xa: /* RANDOM */ return(pokey_random[px]); break; } } break; } break; case MT_BAD: fprintf(stderr,"Read from bad location %04x at %04x\n",a,m6502.pc); die(0); break; } abort(); } void cpu_writemem16(unsigned short int a, unsigned char v) { switch (mtype[a]) { case MT_RAM: jbmem[a] = v; jb_ramwrite(a); break; case MT_ROM: break; case MT_SPECIAL: switch (a) { default: fprintf(stderr,"Write to unsupported special %04x at %04x\n",a,m6502.pc); die(1); break; case 0x0800 ... 0x080f: break; case 0x4000: /* coin counters and video invert bits */ break; case 0x4800: break; case 0x5000: /* reset watchdog */ break; case 0x5800: break; case 0x6000 ... 0x603f: break; case 0x6040: break; case 0x6080 ... 0x609f: /* mathbox */ mathbox_write(&jb_mathbox,a&0x1f,v); break; case 0x60c0 ... 0x60cf: /* pokey #1 */ { int px; int ca; px = 0; if (0) { case 0x60d0 ... 0x60df: /* pokey #2 */ px = 1; } ca = a & 0x000f; switch (ca) { default: fprintf(stderr,"Write to unsupported pokey register [%04x] at %04x\n",a,m6502.pc); die(1); break; case 0x0: /* AUDF1 */ case 0x1: /* AUDC1 */ case 0x2: /* AUDF2 */ case 0x3: /* AUDC2 */ case 0x4: /* AUDF3 */ case 0x5: /* AUDC3 */ case 0x6: /* AUDF4 */ case 0x7: /* AUDC4 */ case 0x8: /* AUDCTL */ case 0xb: /* POTGO */ break; case 0xf: /* SKCTL */ break; } } break; case 0x60e0: /* set player-start LEDs and FLIP bit */ break; } break; case MT_BAD: fprintf(stderr,"Write to bad location %04x at %04x\n",a,m6502.pc); die(0); break; default: abort(); break; } } #endif