/*************************************************************************** machine.c Functions to emulate general aspects of the machine (RAM, ROM, interrupts, I/O ports) ***************************************************************************/ #include #include #include #include "Z80.h" #include "machine.h" #include "vidhrdw.h" #include "sndhrdw.h" #include "roms.h" #include "memmap.h" #include "osdepend.h" #ifdef UNIX #define uclock_t clock_t #define uclock clock #define UCLOCKS_PER_SEC CLOCKS_PER_SEC #endif /* CPU_SPEED is the speed of the CPU in Hz. It is used together with */ /* FRAMES_PER_SECOND to calculate how much CPU cycles must pass between */ /* interrupts. */ #define CPU_SPEED 3072000 /* 3.072 Mhz */ #define FRAMES_PER_SECOND 60 unsigned char RAM[0x10000]; /* 64k of RAM */ /* dip switches */ int dsw[2]; const struct DSW *dswsettings; const byte *evetab,*oddtab; extern const byte ccevetab[],ccoddtab[],ccbootevetab[],ccbootoddtab[]; /*************************************************************************** Initialize the emulated machine (load the roms, initialize the various subsystems...). Returns 0 if successful. ***************************************************************************/ int init_machine(const char *gamename) { int i; FILE *f; char name[100]; i = 0; while (gameinfo[i].name && stricmp(gamename,gameinfo[i].name) != 0) i++; if (readroms(RAM,gameinfo[i].rom,gamename) != 0) return 1; if (vh_init(gamename)) { printf("Cannot initialize video emulation\n"); return 1; } if (sh_init(gamename)) { printf("Cannot initialize sound emulation\n"); return 1; } dswsettings = gameinfo[i].dswsettings; dsw[0] = gameinfo[i].defaultdsw[0]; dsw[1] = gameinfo[i].defaultdsw[1]; /* read dipswitch settings from disk */ sprintf(name,"%s/%s.dsw",gamename,gamename); if ((f = fopen(name,"rb")) != 0) { fread(dsw,1,2,f); fclose(f); } return 0; } /*************************************************************************** Run the emulation. Start the various subsystems and the CPU emulation. Returns non zero in case of error. ***************************************************************************/ int run_machine(const char *gamename) { if (vh_start() == 0) /* start the video hardware */ { if (sh_start() == 0) /* start the audio hardware */ { reg StartRegs; FILE *f; char name[100]; IPeriod = CPU_SPEED / FRAMES_PER_SECOND; /* Number of T-states per interrupt */ ResetZ80(&StartRegs); Z80(&StartRegs); /* start the CPU emulation */ sh_stop(); vh_stop(); /* write dipswitch settings from disk */ sprintf(name,"%s/%s.dsw",gamename,gamename); if ((f = fopen(name,"wb")) != 0) { fwrite(dsw,1,2,f); fclose(f); } return 0; } else printf("Unable to setup audio\n"); vh_stop(); } else printf("Unable to setup display\n"); return 1; } /*************************************************************************** Perform a memory read. This function is called by the CPU emulation. ***************************************************************************/ byte M_RDMEM (dword A) { /* handle input ports (see memmap.h for details) */ switch (A) { case IN0_PORT: { byte res = 0; /* if (osd_key_pressed(OSD_KEY_E)) res |= IN0_LEFT_UP; if (osd_key_pressed(OSD_KEY_D)) res |= IN0_LEFT_DOWN; if (osd_key_pressed(OSD_KEY_S)) res |= IN0_LEFT_LEFT; */ if (osd_key_pressed(OSD_KEY_CONTROL)) res |= IN0_LEFT_RIGHT; if (osd_key_pressed(OSD_KEY_UP)) res |= IN0_RIGHT_UP; if (osd_key_pressed(OSD_KEY_DOWN)) res |= IN0_RIGHT_DOWN; if (osd_key_pressed(OSD_KEY_LEFT)) res |= IN0_RIGHT_LEFT; if (osd_key_pressed(OSD_KEY_RIGHT)) res |= IN0_RIGHT_RIGHT; return res; break; } case IN2_PORT: { byte res = 0xff;//IN2_STANDUP; if (osd_key_pressed(OSD_KEY_2)) res ^= IN2_START2; if (osd_key_pressed(OSD_KEY_1)) res ^= IN2_START1; if (osd_key_pressed(OSD_KEY_3)) res ^= IN2_CREDIT; return res; break; } case DSW1_PORT: { byte res = dsw[0]; if (osd_key_pressed(OSD_KEY_F1)) res |= DSW1_RACK_TEST; return res; break; } default: return RAM[A]; break; } } /*************************************************************************** Perform a memory write. This function is called by the CPU emulation. ***************************************************************************/ void M_WRMEM (dword A,byte V) { if (A <= ROM_END) return; /* Do nothing, it's ROM */ else if (vh_wrmem(A,V)) return; /* the video hardware handled the write */ else if (sh_wrmem(A,V)) return; /* the sound hardware handled the write */ else RAM[A] = V; } /*************************************************************************** Interrupt handler. This function is called at regular intervals (determined by IPeriod) by the CPU emulation. ***************************************************************************/ int Interrupt(void) { static uclock_t prev; uclock_t curr; sh_update(); /* update sound */ if(RAM[INTERRUPT_ENABLE]) vh_screenrefresh(); /*update screen */ /* if the user pressed ESC, stop the emulation */ if (osd_key_pressed(OSD_KEY_ESC)) CPURunning = 0; /* if the user pressed F2, reset the machine */ if (osd_key_pressed(OSD_KEY_F2)) { ResetZ80(&R); return IGNORE_INT; } /* if TAB, go to dipswitch setup menu */ if (osd_key_pressed(OSD_KEY_TAB)) setdipswitches(dsw,dswsettings); if (osd_key_pressed(OSD_KEY_P)) /* pause the game */ { struct DisplayText dt[] = { { "PAUSED", RED_TEXT, 13, 16 }, { 0, 0, 0, 0 } }; int key; displaytext(dt,0); while (osd_key_pressed(OSD_KEY_P)); /* wait for key release */ do { key = osd_read_key(); if (key == OSD_KEY_ESC) CPURunning = 0; else if (key == OSD_KEY_TAB) { setdipswitches(dsw,dswsettings); /* might set CPURunning to 0 */ displaytext(dt,0); } } while (CPURunning && key != OSD_KEY_P); while (osd_key_pressed(key)); /* wait for key release */ vh_screenrefresh(); } /* now wait until it's time to trigger the interrupt */ do { curr = uclock(); } while ((curr - prev) < UCLOCKS_PER_SEC/FRAMES_PER_SECOND); prev = curr; if (RAM[INTERRUPT_ENABLE]) return NMI_INT; else return IGNORE_INT; } /*************************************************************************** This function is called by the CPU emulation when the EI instruction is executed. We don't need to do anything fancy. ***************************************************************************/ int InterruptsEnabled(void) { return IGNORE_INT; } /*************************************************************************** Execute an OUT instruction. This function is called by the CPU emulation. ***************************************************************************/ void DoOut(byte A,byte V) { sh_doout(A,V); } byte DoIn(byte A) { byte B; if(sh_doin(A,&B)) return B; return 0; } void Patch (reg *R) { }