/*************************************************************************** machine.c Functions to emulate general aspects of the machine (RAM, ROM, interrupts, I/O ports) ***************************************************************************/ #include #include #include #include #include "Z80.h" #include "machine.h" #include "vidhrdw.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 720000 /* 0.72 MHz, is this right? */ #define FRAMES_PER_SECOND 60 unsigned char RAM[0x8000]; /* 32k of RAM */ /* default dip switches settings */ int dsw1 = ~( DSW1_VBLANK); /*************************************************************************** Initialize the emulated machine (load the roms, initialize the various subsystems...). Returns 0 if successful. ***************************************************************************/ int init_machine(const char *gamename) { int i; 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; } return 0; } /*************************************************************************** Run the emulation. Start the various subsystems and the CPU emulation. Returns non zero in case of error. ***************************************************************************/ int run_machine(void) { if (vh_start() == 0) /* start the video hardware */ { reg StartRegs; IPeriod = CPU_SPEED / FRAMES_PER_SECOND; /* Number of T-states per interrupt (should be 12000) */ ResetZ80(&StartRegs); Z80(&StartRegs); /* start the CPU emulation */ vh_stop(); return 0; } else printf("Unable to setup display\n"); return 1; } /*************************************************************************** Perform a memory read. This function is called by the CPU emulation. ***************************************************************************/ int vblank; byte M_RDMEM (dword A) { /* handle input ports (see memmap.h for details) */ if (A >= DSW1_PORT_START && A <= DSW1_PORT_END) { byte res = 0x00; if (vblank) { vh_screenrefresh(); vblank = 0; res |= DSW1_VBLANK; } return res; } else if (A >= IN1_PORT_START && A <= IN1_PORT_END) { byte res = 0xff; if (osd_key_pressed(OSD_KEY_1)) res &= ~IN1_START1; if (osd_key_pressed(OSD_KEY_2)) res &= ~IN1_START2; if (osd_key_pressed(OSD_KEY_3)) res &= ~IN1_COIN; if (osd_key_pressed(OSD_KEY_RIGHT)) res &= ~IN1_RIGHT; if (osd_key_pressed(OSD_KEY_LEFT)) res &= ~IN1_LEFT; if (osd_key_pressed(OSD_KEY_CONTROL)) res &= ~IN1_FIRE; if (osd_key_pressed(OSD_KEY_ALT)) res &= ~IN1_BARRIER; return res; } else return RAM[A]; } /*************************************************************************** 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 RAM[A] = V; } /*************************************************************************** Interrupt handler. This function is called at regular intervals (determined by IPeriod) by the CPU emulation. Phoenix doesn't have VBlank interrupts; the software polls port IN1 to know when a vblank is happening. Therefore we set a flag here, to let M_RDMEM() know when it has to report a vblank. ***************************************************************************/ int Interrupt(void) { static uclock_t prev; uclock_t curr; /* first of all, refresh the screen */ /* This is done for now when M_RDMEM() discovers a vblank */ /*vh_screenrefresh();*/ /* if the user pressed ESC, stop the emulation */ if (osd_key_pressed(OSD_KEY_ESC)) CPURunning = 0; if (osd_key_pressed(OSD_KEY_P)) /* pause the game */ { while (osd_key_pressed(OSD_KEY_P)); while (!osd_key_pressed(OSD_KEY_P)); while (osd_key_pressed(OSD_KEY_P)); } /* now wait until it's time to trigger the interrupt */ do { curr = uclock(); } while ((curr - prev) < UCLOCKS_PER_SEC/FRAMES_PER_SECOND); prev = curr; /* let M_RDMEM() know that it is time to report a vblank */ vblank = 1; 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) { } byte DoIn(byte A) { return 0; } void Patch (reg *R) { }