MCUME/MCUME_pico2/picogen/emu.cpp

264 wiersze
7.8 KiB
C++

#include <string.h>
#include "emuapi.h"
#include "iopins.h"
#include <pico/stdlib.h>
/* Gwenesis Emulator */
extern "C" {
#include "gwenesis/cpus/M68K/m68k.h"
#include "gwenesis/sound/z80inst.h"
#include "gwenesis/bus/gwenesis_bus.h"
#include "gwenesis/io/gwenesis_io.h"
#include "gwenesis/vdp/gwenesis_vdp.h"
#include "gwenesis/savestate/gwenesis_savestate.h"
#include <gwenesis/sound/gwenesis_sn76489.h>
#include <gwenesis/sound/ym2612.h>
}
#include "flash_t.h"
// SETTINGS
bool show_fps = true;
bool limit_fps = true;
bool interlace = true;
bool frameskip = true;
static int z80_enable_mode = 2;
bool sn76489_enabled = true;
extern unsigned short button_state[3];
/* shared variables with gwenesis_sn76589 */
int16_t gwenesis_sn76489_buffer[GWENESIS_AUDIO_BUFFER_LENGTH_NTSC * 2]; // 888 = NTSC, PAL = 1056 (too big) //GWENESIS_AUDIO_BUFFER_LENGTH_PAL];
int sn76489_index; /* sn78649 audio buffer index */
int sn76489_clock; /* sn78649 clock in video clock resolution */
int8_t gwenesis_ym2612_buffer[GWENESIS_AUDIO_BUFFER_LENGTH_NTSC * 2]; //GWENESIS_AUDIO_BUFFER_LENGTH_PAL];
int ym2612_index; /* ym2612 audio buffer index */
int ym2612_clock;
int audio_enabled = 1;
uint8_t snd_accurate = 0;
static unsigned short screen_line[320];
void gwenesis_io_get_buttons() {
}
void emu_KeyboardOnDown(int keymodifer, int key) {
}
void emu_KeyboardOnUp(int keymodifer, int key) {
}
void gen_Init(void)
{
emu_printf("gen_Init");
emu_printf("gen_Init done");
}
static int hk = 0;
static int k = 0;
void gen_Input(int click) {
hk = emu_ReadI2CKeyboard();
k = emu_ReadKeys();
}
extern void * emu_LineBuffer(int line);
void gen_Start(char * filename)
{
emu_printf("gen_Start");
int size = flash_load_bswap(filename);
load_cartridge((uintptr_t)flash_start);
//gwenesis_system_init();
power_on();
reset_emulation();
gwenesis_vdp_set_buffer(&screen_line[0]);
#ifdef HAS_SND
emu_sndInit();
memset(gwenesis_sn76489_buffer, 0, sizeof(gwenesis_sn76489_buffer));
memset(gwenesis_ym2612_buffer, 0, sizeof(gwenesis_ym2612_buffer));
#endif
emu_printf("gen_Start done");
}
int start_time = 0;
int frame, frame_cnt = 0;
int frame_timer_start = 0;
/* Clocks and synchronization */
/* system clock is video clock */
int system_clock;
unsigned int lines_per_frame = LINES_PER_FRAME_NTSC; //262; /* NTSC: 262, PAL: 313 */
int scan_line;
unsigned int frame_counter = 0;
unsigned int drawFrame = 1;
extern unsigned char gwenesis_vdp_regs[0x20];
extern unsigned int gwenesis_vdp_status;
extern unsigned int screen_width, screen_height;
extern int hint_pending;
void gen_Step(void) {
int hint_counter = gwenesis_vdp_regs[10];
const bool is_pal = REG1_PAL;
screen_width = REG12_MODE_H40 ? 320 : 256;
screen_height = is_pal ? 240 : 224;
lines_per_frame = is_pal ? LINES_PER_FRAME_PAL : LINES_PER_FRAME_NTSC;
gwenesis_vdp_render_config();
zclk = 0;
/* Reset the difference clocks and audio index */
system_clock = 0;
sn76489_clock = 0;
sn76489_index = 0;
ym2612_clock = 0;
ym2612_index = 0;
scan_line = 0;
if (z80_enable_mode == 1)
z80_run(lines_per_frame * VDP_CYCLES_PER_LINE);
//printf("m(%x)\n", frame);
while (scan_line < lines_per_frame) {
/* CPUs */
m68k_run(system_clock + VDP_CYCLES_PER_LINE);
if (z80_enable_mode == 2)
z80_run(system_clock + VDP_CYCLES_PER_LINE);
/* Video */
// Interlace mode
//if (drawFrame && !interlace || (frame % 2 == 0 && scan_line % 2) || scan_line % 2 == 0) {
if (drawFrame) {
gwenesis_vdp_set_buffer(&screen_line[0]);
gwenesis_vdp_render_line(scan_line); /* render scan_line */
if (scan_line < screen_height ) emu_DrawLine16(&screen_line[0], 320, screen_height, scan_line);
}
// On these lines, the line counter interrupt is reloaded
if (scan_line == 0 || scan_line > screen_height) {
hint_counter = REG10_LINE_COUNTER;
}
// interrupt line counter
if (--hint_counter < 0) {
if (REG0_LINE_INTERRUPT != 0 && scan_line <= screen_height) {
hint_pending = 1;
if ((gwenesis_vdp_status & STATUS_VIRQPENDING) == 0)
m68k_update_irq(4);
}
hint_counter = REG10_LINE_COUNTER;
}
scan_line++;
// vblank begin at the end of last rendered line
if (scan_line == screen_height) {
if (REG1_VBLANK_INTERRUPT != 0) {
gwenesis_vdp_status |= STATUS_VIRQPENDING;
m68k_set_irq(6);
}
z80_irq_line(1);
}
if (!is_pal && scan_line == screen_height + 1) {
z80_irq_line(0);
// FRAMESKIP every 3rd frame
//drawFrame = frameskip && frame % 3 != 0;
// if (frameskip && frame % 3 == 0) {
// drawFrame = 0;
// } else {
// drawFrame = 1;
// }
}
system_clock += VDP_CYCLES_PER_LINE;
}
frame++;
/*
if (limit_fps) {
frame_cnt++;
if (frame_cnt == (is_pal ? 5 : 6)) {
while (time_us_64() - frame_timer_start < (is_pal ? 20000 * 5 : 16666 * 6)) {
busy_wait_at_least_cycles(10);
}; // 60 Hz
frame_timer_start = time_us_64();
frame_cnt = 0;
}
}
*/
#ifdef HAS_SND_SYNC
if (audio_enabled) {
ym2612_run(262 * VDP_CYCLES_PER_LINE);
gwenesis_SN76489_run(262 * VDP_CYCLES_PER_LINE);
audio_sample * snd_buf = (audio_sample *)emu_sndGetBuffer();
for (int h = 0; h < GWENESIS_AUDIO_BUFFER_LENGTH_NTSC * 2; h++) {
int16_t s1 = gwenesis_ym2612_buffer[h/ 2 / GWENESIS_AUDIO_SAMPLING_DIVISOR] + gwenesis_sn76489_buffer[h/ 2 / GWENESIS_AUDIO_SAMPLING_DIVISOR]>>8;
int16_t s2 = gwenesis_ym2612_buffer[(h/ 2 / GWENESIS_AUDIO_SAMPLING_DIVISOR+1) ] + gwenesis_sn76489_buffer[(h/ 2 / GWENESIS_AUDIO_SAMPLING_DIVISOR+1)]>>8;
*snd_buf++ = ((s1+s2)/4)+128;
}
}
#endif
// reset m68k cycles to the begin of next frame cycle
m68k.cycles -= system_clock;
button_state[0]=0;
if (( k & MASK_JOY1_RIGHT) || ( k & MASK_JOY2_RIGHT)) {
button_state[0] |= (1 << PAD_LEFT);
}
if (( k & MASK_JOY1_LEFT) || ( k & MASK_JOY2_LEFT)) {
button_state[0] |= (1 << PAD_RIGHT);
}
if (( k & MASK_JOY1_UP) || ( k & MASK_JOY2_UP)) {
button_state[0] |= (1 << PAD_UP);
}
if (( k & MASK_JOY1_DOWN) || ( k & MASK_JOY2_DOWN)) {
button_state[0] |= (1 << PAD_DOWN);
}
if ( k & MASK_JOY2_BTN) {
button_state[0] |= (1 << PAD_B);
}
if ( k & MASK_KEY_USER3) {
button_state[0] |= (1 << PAD_C);
}
if ( k & MASK_KEY_USER4) {
button_state[0] |= (1 << PAD_A);
}
if ( k & MASK_KEY_USER1) {
button_state[0] |= (1 << PAD_S);
}
button_state[0] = ~ button_state[0];
//emu_DrawVsync();
}
void SND_Process(void *stream, int len) {
if (audio_enabled) {
//if ( (z80_enable_mode == 3) && (system_clock == 0) )
// z80_run(262 * VDP_CYCLES_PER_LINE);
ym2612_run(262 * VDP_CYCLES_PER_LINE);
gwenesis_SN76489_run(262 * VDP_CYCLES_PER_LINE);
audio_sample * snd_buf = (audio_sample *)stream;
for (int h = 0; h < len*2; h += 2) {
int16_t s1 = gwenesis_ym2612_buffer[h/ 2 / GWENESIS_AUDIO_SAMPLING_DIVISOR] + gwenesis_sn76489_buffer[h/ 2 / GWENESIS_AUDIO_SAMPLING_DIVISOR]>>8;
int16_t s2 = gwenesis_ym2612_buffer[(h/ 2 / GWENESIS_AUDIO_SAMPLING_DIVISOR+1) ] + gwenesis_sn76489_buffer[(h/ 2 / GWENESIS_AUDIO_SAMPLING_DIVISOR+1)]>>8;
*snd_buf++ = ((s1+s2)/4)+128;
}
}
}