void timer_update_cpu(void) { int i; float time; extern int scanline1; extern int scanline2; frame_base = 0; timer_left = time_slice; if (scanline1 != RASTER_LINES) timer_set_raster_interrupt(RASTER_INTERRUPT1, scanline1); if (scanline2 != RASTER_LINES) timer_set_raster_interrupt(RASTER_INTERRUPT2, scanline2); timer_set_vblank_interrupt(); (*cps2_build_palette)(); while (timer_left > 0) { timer_ticks = timer_left; time = base_time + frame_base; for (i = 0; i < MAX_TIMER; i++) { if (timer[i].enable) { if (timer[i].expire - time <= 0) { timer[i].enable = 0; timer[i].callback(timer[i].param); } } if (timer[i].enable) { if (timer[i].expire - time < timer_ticks) timer_ticks = timer[i].expire - time; } } m68000_execute((int)((float)timer_ticks * m68k_cycles)); if (!z80_suspended) z80_execute((int)((float)timer_ticks * z80_cycles)); frame_base += timer_ticks; timer_left -= timer_ticks; } base_time += time_slice; if (base_time >= 1000000.0) { base_time -= 1000000.0; for (i = 0; i < MAX_TIMER; i++) { if (timer[i].enable) timer[i].expire -= 1000000.0; } } }
/*------------------------------------------------------------------------- Audio command callback. Input: Timer Pointer to the timer that triggered the callback. Data Data associated with the timer. ---------------------------------------------------------------------------*/ void neogeo_audio_command_timer_callback ( TIMER *Timer, Uint32 Data ) { Uint32 Z80_Elapsed; /* Post the audio command to the Z80 */ neogeo_audio_command = Data; z80_set_irq_line ( INPUT_LINE_NMI, ASSERT_LINE ); z80_set_irq_line ( INPUT_LINE_NMI, CLEAR_LINE ); /* Let the Z80 take the command into account */ Z80_Elapsed = z80_execute ( REF_TO_Z80 ( 2000 ) ); neogeo_z80_time_to_execute -= Z80_TO_REF ( Z80_Elapsed ); neogeo_z80_time_this_vbl += Z80_TO_REF ( Z80_Elapsed ); }
// MAIN EMULATION LOOP (MAME CORE) -------------------------------------------- void CPU_Loop (void) { for (;;) { z80_execute (opt.Cur_IPeriod); switch (LoopZ80 ()) { case INT_IRQ: break; case INT_NMI: z80_set_nmi_line (ASSERT_LINE); z80_set_nmi_line (CLEAR_LINE); break; case INT_QUIT: return; } } /* z80_stop_emulating(); */ }
/** @brief run the CPU(s) for the next time slice */ void tmr_run_cpu(void *context, double clock) { z80_cpu_t *cpu = (z80_cpu_t *)context; tmr_t *slice = tmr_next_event(); int ran; tmr_clock = clock; slice = tmr_next_event(); if (NULL == slice) return; if (slice->expire <= now) cycles = 1; else cycles = (int)(tmr_time_to_double(slice->expire - now) * clock) - adjust; #if 0 z80_dump_state(cpu); #endif ran = z80_execute(cpu); cycles_this_frame += ran; z80_cc = 0; adjust = (ran > cycles) ? ran - cycles : 0; tmr_expire(tmr_double_to_time((double)ran / clock)); }
/* Run the virtual console emulation for one frame */ void sms_frame(int skip_render) { /* Take care of hard resets */ if(input.system & INPUT_HARD_RESET) { system_reset(); } /* Debounce pause key */ if(input.system & INPUT_PAUSE) { if(!sms.paused) { sms.paused = 1; z80_set_nmi_line(ASSERT_LINE); z80_set_nmi_line(CLEAR_LINE); } } else { sms.paused = 0; } if(snd.log) snd.callback(0x00); for(vdp.line = 0; vdp.line < 262; vdp.line += 1) { /* Handle VDP line events */ vdp_run(); /* Draw the current frame */ if(!skip_render) render_line(vdp.line); /* Run the Z80 for a line */ z80_execute(227); } /* Update the emulated sound stream */ if(snd.enabled) { int count; SN76496Update(0, snd.psg_buffer, snd.bufsize, sms.psg_mask); if(sms.use_fm) { int i; for(i = 0; i < snd.bufsize; i++) { snd.fm_buffer[i] = OPLL_calc(opll); } } for(count = 0; count < snd.bufsize; count += 1) { signed short left = 0; signed short right = 0; left = right = snd.fm_buffer[count]; left += snd.psg_buffer[0][count]; right += snd.psg_buffer[1][count]; snd.buffer[0][count] = left; snd.buffer[1][count] = right; } } }
/* Run the virtual console emulation for one frame */ void system_frame(int skip_render) { static int iline_table[] = {0xC0, 0xE0, 0xF0}; int lpf = (sms.display == DISPLAY_NTSC) ? 262 : 313; int iline; /* Debounce pause key */ if(input.system & INPUT_PAUSE) { if(!sms.paused) { sms.paused = 1; z80_set_irq_line(IRQ_LINE_NMI, ASSERT_LINE); z80_set_irq_line(IRQ_LINE_NMI, CLEAR_LINE); } } else { sms.paused = 0; } text_counter = 0; /* End of frame, parse sprites for line 0 on line 261 (VCount=$FF) */ if(vdp.mode <= 7) parse_line(0); for(vdp.line = 0; vdp.line < lpf;) { z80_execute(227); iline = iline_table[vdp.extended]; if(!skip_render) { render_line(vdp.line); } if(vdp.line <= iline) { vdp.left -= 1; if(vdp.left == -1) { vdp.left = vdp.reg[0x0A]; vdp.hint_pending = 1; z80_execute(16); if(vdp.reg[0x00] & 0x10) { z80_set_irq_line(0, ASSERT_LINE); } } } else { vdp.left = vdp.reg[0x0A]; } if(vdp.line == iline) { vdp.status |= 0x80; vdp.vint_pending = 1; z80_execute(16); if(vdp.reg[0x01] & 0x20) { z80_set_irq_line(0, ASSERT_LINE); } } sound_update(vdp.line); ++vdp.line; if(vdp.mode <= 7) parse_line(vdp.line); } }
/*------------------------------------------------------------------------- Run our virtual Neo Geo according to the run mode. ---------------------------------------------------------------------------*/ Uint32 neogeo_run ( void ) { Uint32 TimeSlice; Uint32 Elapsed; Uint32 Z80_Elapsed; Uint32 ReturnCode; ReturnCode = 0; switch ( neogeo_run_mode ) { case NEOGEO_RUN_QUIT: ReturnCode = 1; break; case NEOGEO_RUN_TRACE: Elapsed = m68k_execute ( 0 ); if ( !neogeo_z80_disable ) { neogeo_z80_time_to_execute += M68K_TO_REF ( Elapsed ); if ( neogeo_z80_time_to_execute > 0 ) { Z80_Elapsed = z80_execute ( REF_TO_Z80 ( neogeo_z80_time_to_execute ) ); neogeo_z80_time_to_execute -= Z80_TO_REF ( Z80_Elapsed ); neogeo_z80_time_this_vbl += Z80_TO_REF ( Z80_Elapsed ); } } neogeo_screen_position += M68K_TO_REF ( Elapsed ); timer_advance ( M68K_TO_REF ( Elapsed ) ); timer_call_events(); ReturnCode = 3; break; case NEOGEO_RUN_NORMAL: case NEOGEO_RUN_FULL_THROTTLE: while ( 1 ) { TimeSlice = REF_TO_M68K ( timer_request_timeslice() ); if ( neogeo_show_debugger ) { neogeo_show_debugger = 0; ReturnCode = 3; break; } Elapsed = m68k_execute ( TimeSlice ); if ( !neogeo_z80_disable ) { neogeo_z80_time_to_execute += M68K_TO_REF ( Elapsed ); if ( neogeo_z80_time_to_execute > 0 ) { Z80_Elapsed = z80_execute ( REF_TO_Z80 ( neogeo_z80_time_to_execute ) ); neogeo_z80_time_to_execute -= Z80_TO_REF ( Z80_Elapsed ); neogeo_z80_time_this_vbl += Z80_TO_REF ( Z80_Elapsed ); } } neogeo_screen_position += M68K_TO_REF ( Elapsed ); timer_advance ( M68K_TO_REF ( Elapsed ) ); if ( neogeo_show_debugger ) { neogeo_show_debugger = 0; ReturnCode = 3; } if ( neogeo_run_mode == NEOGEO_RUN_TRACE ) { timer_call_events(); ReturnCode = 2; } if ( neogeo_run_mode == NEOGEO_RUN_QUIT ) ReturnCode = 1; if ( ReturnCode ) break; } break; } return ReturnCode; }
uint32 sms_z80_run(uint32 cycles) { uint32 cyclesdone = 0; uint32 opcode; uint16 pc; int tmp; static char last_str[256]; char str[256]; static uint16 last_pc = 0; uint32 c1, c2; while(cyclesdone < cycles) { debug_crab_ents = debug_mz80_ents = 0; debug_port_reads1 = debug_port_reads2 = 0; debug_mem_reads1 = debug_mem_reads2 = 0; debug_crab_ports = debug_mz80_ports = 0; pc = cpuz80->pc.w; opcode = mread8(cpuz80->pc.w); if(opcode == 0xED || opcode == 0xCB || opcode == 0xDD || opcode == 0xFD) { opcode |= (mread8(cpuz80->pc.w + 1) << 8); } if((opcode & 0xFF00) == 0xCB00) { opcode |= (mread8(cpuz80->pc.w + 2) << 16) | (mread8(cpuz80->pc.w + 3) << 24); } c1 = CrabZ80_execute(cpuz80, 1); c2 = z80_execute(1); cyclesdone += c1; tmp = _compare_registers() + _compare_memory() + _compare_ports(); CrabZ80_disassemble(str, cpuz80, pc); if(tmp) { printf("Cycles done: %d %d\n", (int)c1, (int)c2); printf("%d errors at: PC = 0x%04X, old_pc = 0x%04X Opcode = 0x%02X", tmp, pc, last_pc, opcode & 0xFF); switch(opcode & 0xFF) { case 0xED: case 0xCB: printf("%02X (%s -- %s)\n", (opcode & 0xFF00) >> 8, str, last_str); break; case 0xDD: case 0xFD: if((opcode & 0xFF00) == 0xCB00) printf("%02X%02X%02X (%s -- %s)\n", (opcode & 0xFF00) >> 8, (opcode & 0xFF0000) >> 16, (opcode & 0xFF000000) >> 24, str, last_str); else printf("%02X (%s -- %s)\n", (opcode & 0xFF00) >> 8, str, last_str); break; default: printf("(%s -- %s)\n", str, last_str); } } strcpy(last_str, str); last_pc = pc; }
inline void cpu_z80_run(int nbcycle) { //printf("%x\n",z80_get_reg(Z80_PC)); z80_execute(nbcycle); }
int32 qsf_gen(qsf_synth_t *s, int16 *buffer, uint32 samples) { int16 output[44100/30], output2[44100/30]; int16 *stereo[2]; int16 *outp = buffer; int32 i, opos, tickinc, loops; // our largest possible step is samples_per_tick or samples, whichever is smaller if (s->samples_to_next_tick > samples) { tickinc = samples; } else { tickinc = s->samples_to_next_tick; } loops = samples / tickinc; opos = 0; for (i = 0; i < loops; i++) { z80_execute(s->z80, (8000000/44100)*tickinc); stereo[0] = &output[opos]; stereo[1] = &output2[opos]; qsound_update(s->qs, 0, stereo, tickinc); opos += tickinc; s->samples_to_next_tick -= tickinc; if (s->samples_to_next_tick <= 0) { timer_tick(s); s->samples_to_next_tick = samples_per_tick; } } // are there "leftovers"? if (opos < samples) { z80_execute(s->z80, (8000000/44100)*(samples-opos)); stereo[0] = &output[opos]; stereo[1] = &output2[opos]; qsound_update(s->qs, 0, stereo, (samples-opos)); s->samples_to_next_tick -= (samples-opos); if (s->samples_to_next_tick <= 0) { timer_tick(s); s->samples_to_next_tick = samples_per_tick; } } for (i = 0; i < samples; i++) { *outp++ = output[i]; *outp++ = output2[i]; } return AO_SUCCESS; }
void gameboy_run() { uint8_t op; /* reset counter */ cycles.cnt = 0; /* get interrupt flags and interrupt enables */ uint8_t *int_e; uint8_t *int_f; /* pointers to memory location of interrupt enables/flags */ int_e = mmu_addr(0xFFFF); int_f = mmu_addr(0xFF0F); /* start at normal speed */ global_cpu_double_speed = 0; /* run stuff! */ /* mechanism is simple. */ /* 1) execute instruction 2) update cycles counter 3) check interrupts */ /* and repeat forever */ while (!global_quit) { /*if (global_slow_down) { usleep(100000); global_slow_down = 0; }*/ /* pause? */ while (global_pause) sem_wait(&gameboy_sem); /* get op */ op = mmu_read(state.pc); /* print out CPU state if enabled by debug flag */ if (global_debug) { utils_log("OP: %02x F: %02x PC: %04x:%02x:%02x SP: %04x:%02x:%02x ", op, *state.f & 0xd0, state.pc, mmu_read_no_cyc(state.pc + 1), mmu_read_no_cyc(state.pc + 2), state.sp, mmu_read_no_cyc(state.sp), mmu_read_no_cyc(state.sp + 1)); utils_log("A: %02x BC: %04x DE: %04x HL: %04x FF41: %02x " "FF44: %02x ENAB: %02x INTE: %02x INTF: %02x\n", state.a, *state.bc, *state.de, *state.hl, mmu_read_no_cyc(0xFF41), mmu_read_no_cyc(0xFF44), state.int_enable, *int_e, *int_f); } /* execute instruction by the GB Z80 version */ z80_execute(op); /* if last op was Interrupt Enable (0xFB) */ /* we need to check for INTR on next cycle */ if (op == 0xFB) continue; /* interrupts filtered by enable flags */ uint8_t int_r = (*int_f & *int_e); /* check for interrupts */ if ((state.int_enable || op == 0x76) && (int_r != 0)) { /* discard useless bits */ if ((int_r & 0x1F) == 0x00) continue; /* beware of instruction that doesn't move PC! */ /* like HALT (0x76) */ if (op == 0x76) { state.pc++; if (state.int_enable == 0) continue; } /* reset int-enable flag, it will be restored after a RETI op */ state.int_enable = 0; if ((int_r & 0x01) == 0x01) { /* vblank interrupt triggers RST 5 */ /* reset flag */ *int_f &= 0xFE; /* handle the interrupt */ z80_intr(0x0040); } else if ((int_r & 0x02) == 0x02) { /* LCD Stat interrupt */ /* reset flag */ *int_f &= 0xFD; /* handle the interrupt! */ z80_intr(0x0048); } else if ((int_r & 0x04) == 0x04) { /* timer interrupt */ /* reset flag */ *int_f &= 0xFB; /* handle the interrupt! */ z80_intr(0x0050); } else if ((int_r & 0x08) == 0x08) { /* serial interrupt */ /* reset flag */ *int_f &= 0xF7; /* handle the interrupt! */ z80_intr(0x0058); } } } /* terminate all the stuff */ cartridge_term(); sound_term(); mmu_term(); return; }