summaryrefslogtreecommitdiff
path: root/gen_player.c
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2020-04-29 23:42:16 -0700
committerMichael Pavone <pavone@retrodev.com>2020-04-29 23:42:16 -0700
commite2915e2ac57ac58d745eba210288cfe4061f0082 (patch)
treea1c9ad00704f47a31760146e65eccf0cbfc62829 /gen_player.c
parent2071d8e545b9aca6af08852f721e9a7b7a617398 (diff)
Add missing netplay files and add in support for sending gamepad commands back to host
Diffstat (limited to 'gen_player.c')
-rw-r--r--gen_player.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/gen_player.c b/gen_player.c
new file mode 100644
index 0000000..c282517
--- /dev/null
+++ b/gen_player.c
@@ -0,0 +1,153 @@
+#include "gen_player.h"
+#include "event_log.h"
+#include "render.h"
+
+#ifdef IS_LIB
+#define MAX_SOUND_CYCLES (MCLKS_PER_YM*NUM_OPERATORS*6*4)
+#else
+#define MAX_SOUND_CYCLES 100000
+#endif
+
+static void sync_sound(gen_player *gen, uint32_t target)
+{
+ //printf("YM | Cycle: %d, bpos: %d, PSG | Cycle: %d, bpos: %d\n", gen->ym->current_cycle, gen->ym->buffer_pos, gen->psg->cycles, gen->psg->buffer_pos * 2);
+ while (target > gen->psg->cycles && target - gen->psg->cycles > MAX_SOUND_CYCLES) {
+ uint32_t cur_target = gen->psg->cycles + MAX_SOUND_CYCLES;
+ //printf("Running PSG to cycle %d\n", cur_target);
+ psg_run(gen->psg, cur_target);
+ //printf("Running YM-2612 to cycle %d\n", cur_target);
+ ym_run(gen->ym, cur_target);
+ }
+ psg_run(gen->psg, target);
+ ym_run(gen->ym, target);
+
+ //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2);
+}
+
+void start_context(system_header *sys, char *statefile)
+{
+ gen_player *player = (gen_player *)sys;
+ while(player->reader.socket || player->reader.buffer.cur_pos < player->reader.buffer.size)
+ {
+ uint32_t cycle;
+ uint8_t event = reader_next_event(&player->reader, &cycle);
+ switch (event)
+ {
+ case EVENT_FLUSH:
+ sync_sound(player, cycle);
+ vdp_run_context(player->vdp, cycle);
+ break;
+ case EVENT_ADJUST: {
+ sync_sound(player, cycle);
+ vdp_run_context(player->vdp, cycle);
+ uint32_t deduction = load_int32(&player->reader.buffer);
+ ym_adjust_cycles(player->ym, deduction);
+ vdp_adjust_cycles(player->vdp, deduction);
+ player->psg->cycles -= deduction;
+ break;
+ case EVENT_PSG_REG:
+ sync_sound(player, cycle);
+ psg_write(player->psg, load_int8(&player->reader.buffer));
+ break;
+ case EVENT_YM_REG: {
+ sync_sound(player, cycle);
+ uint8_t part = load_int8(&player->reader.buffer);
+ uint8_t reg = load_int8(&player->reader.buffer);
+ uint8_t value = load_int8(&player->reader.buffer);
+ if (part) {
+ ym_address_write_part2(player->ym, reg);
+ } else {
+ ym_address_write_part1(player->ym, reg);
+ }
+ ym_data_write(player->ym, value);
+ break;
+ case EVENT_STATE: {
+ uint32_t size = load_int8(&player->reader.buffer) << 16;
+ size |= load_int16(&player->reader.buffer);
+ if (player->reader.buffer.size - player->reader.buffer.cur_pos < size) {
+ puts("State has not been fully loaded!");
+ exit(1);
+ }
+ deserialize_buffer buffer;
+ init_deserialize(&buffer, player->reader.buffer.data + player->reader.buffer.cur_pos, size);
+ register_section_handler(&buffer, (section_handler){.fun = vdp_deserialize, .data = player->vdp}, SECTION_VDP);
+ register_section_handler(&buffer, (section_handler){.fun = ym_deserialize, .data = player->ym}, SECTION_YM2612);
+ register_section_handler(&buffer, (section_handler){.fun = psg_deserialize, .data = player->psg}, SECTION_PSG);
+ while (buffer.cur_pos < buffer.size)
+ {
+ load_section(&buffer);
+ }
+ player->reader.buffer.cur_pos += size;
+ free(buffer.handlers);
+ break;
+ }
+ default:
+ vdp_run_context(player->vdp, cycle);
+ vdp_replay_event(player->vdp, event, &player->reader);
+ }
+ }
+
+ }
+ }
+
+}
+
+static void gamepad_down(system_header *system, uint8_t gamepad_num, uint8_t button)
+{
+ gen_player *player = (gen_player *)system;
+ reader_send_gamepad_event(&player->reader, gamepad_num, button, 1);
+}
+
+static void gamepad_up(system_header *system, uint8_t gamepad_num, uint8_t button)
+{
+ gen_player *player = (gen_player *)system;
+ reader_send_gamepad_event(&player->reader, gamepad_num, button, 0);
+}
+
+#define MCLKS_NTSC 53693175
+#define MCLKS_PAL 53203395
+#define MCLKS_PER_YM 7
+#define MCLKS_PER_Z80 15
+#define MCLKS_PER_PSG (MCLKS_PER_Z80*16)
+
+static void config_common(gen_player *player)
+{
+ uint8_t vid_std = load_int8(&player->reader.buffer);
+ uint8_t name_len = load_int8(&player->reader.buffer);
+ player->header.info.name = calloc(1, name_len + 1);
+ load_buffer8(&player->reader.buffer, player->header.info.name, name_len);
+
+ player->vdp = init_vdp_context(vid_std == VID_PAL, 0);
+ render_set_video_standard(vid_std);
+ uint32_t master_clock = vid_std == VID_NTSC ? MCLKS_NTSC : MCLKS_PAL;
+
+ player->ym = malloc(sizeof(ym2612_context));
+ ym_init(player->ym, master_clock, MCLKS_PER_YM, 0);
+
+ player->psg = malloc(sizeof(psg_context));
+ psg_init(player->psg, master_clock, MCLKS_PER_PSG);
+
+ player->header.start_context = start_context;
+ player->header.gamepad_down = gamepad_down;
+ player->header.gamepad_up = gamepad_up;
+ player->header.type = SYSTEM_GENESIS_PLAYER;
+ player->header.info.save_type = SAVE_NONE;
+}
+
+gen_player *alloc_config_gen_player(void *stream, uint32_t rom_size)
+{
+ uint8_t *data = stream;
+ gen_player *player = calloc(1, sizeof(gen_player));
+ init_event_reader(&player->reader, data + 9, rom_size - 9);
+ config_common(player);
+ return player;
+}
+
+gen_player *alloc_config_gen_player_reader(event_reader *reader)
+{
+ gen_player *player = calloc(1, sizeof(gen_player));
+ player->reader = *reader;
+ config_common(player);
+ return player;
+}
+