main
genesis.c
1/*
2 Copyright 2013-2016 Michael Pavone
3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5*/
6#include "genesis.h"
7#include "blastem.h"
8#include "nor.h"
9#include <stdlib.h>
10#include <ctype.h>
11#include <time.h>
12#include <string.h>
13#include "render.h"
14#include "gst.h"
15#include "util.h"
16#include "debug.h"
17#include "gdb_remote.h"
18#include "saves.h"
19#include "bindings.h"
20#include "jcart.h"
21#define MCLKS_NTSC 53693175
22#define MCLKS_PAL 53203395
23
24uint32_t MCLKS_PER_68K;
25#define MCLKS_PER_YM 7
26#define MCLKS_PER_Z80 15
27#define MCLKS_PER_PSG (MCLKS_PER_Z80*16)
28#define Z80_INT_PULSE_MCLKS 2573 //measured value is ~171.5 Z80 clocks
29#define DEFAULT_SYNC_INTERVAL MCLKS_LINE
30#define DEFAULT_LOWPASS_CUTOFF 3390
31
32//TODO: Figure out the exact value for this
33#define LINES_NTSC 262
34#define LINES_PAL 313
35
36#define MAX_SOUND_CYCLES 100000
37
38#define Z80_CYCLE current_cycle
39#define Z80_OPTS options
40
41void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68k_pc)
42{
43 start_section(buf, SECTION_68000);
44 m68k_serialize(gen->m68k, m68k_pc, buf);
45 end_section(buf);
46
47 start_section(buf, SECTION_Z80);
48 z80_serialize(gen->z80, buf);
49 end_section(buf);
50
51 start_section(buf, SECTION_VDP);
52 vdp_serialize(gen->vdp, buf);
53 end_section(buf);
54
55 start_section(buf, SECTION_YM2612);
56 ym_serialize(gen->ym, buf);
57 end_section(buf);
58
59 start_section(buf, SECTION_PSG);
60 psg_serialize(gen->psg, buf);
61 end_section(buf);
62
63 start_section(buf, SECTION_GEN_BUS_ARBITER);
64 save_int8(buf, gen->z80->reset);
65 save_int8(buf, gen->z80->busreq);
66 save_int16(buf, gen->z80_bank_reg);
67 end_section(buf);
68
69 start_section(buf, SECTION_SEGA_IO_1);
70 io_serialize(gen->io.ports, buf);
71 end_section(buf);
72
73 start_section(buf, SECTION_SEGA_IO_2);
74 io_serialize(gen->io.ports + 1, buf);
75 end_section(buf);
76
77 start_section(buf, SECTION_SEGA_IO_EXT);
78 io_serialize(gen->io.ports + 2, buf);
79 end_section(buf);
80
81 start_section(buf, SECTION_MAIN_RAM);
82 save_int8(buf, RAM_WORDS * 2 / 1024);
83 save_buffer16(buf, gen->work_ram, RAM_WORDS);
84 end_section(buf);
85
86 start_section(buf, SECTION_SOUND_RAM);
87 save_int8(buf, Z80_RAM_BYTES / 1024);
88 save_buffer8(buf, gen->zram, Z80_RAM_BYTES);
89 end_section(buf);
90
91 cart_serialize(&gen->header, buf);
92}
93
94static uint8_t *serialize(system_header *sys, size_t *size_out)
95{
96 genesis_context *gen = (genesis_context *)sys;
97 uint32_t address;
98 if (gen->m68k->resume_pc) {
99 gen->m68k->target_cycle = gen->m68k->current_cycle;
100 gen->header.save_state = SERIALIZE_SLOT+1;
101 resume_68k(gen->m68k);
102 if (size_out) {
103 *size_out = gen->serialize_size;
104 }
105 return gen->serialize_tmp;
106 } else {
107 serialize_buffer state;
108 init_serialize(&state);
109 uint32_t address = read_word(4, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k) << 16;
110 address |= read_word(6, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k);
111 genesis_serialize(gen, &state, address);
112 if (size_out) {
113 *size_out = state.size;
114 }
115 return state.data;
116 }
117}
118
119static void ram_deserialize(deserialize_buffer *buf, void *vgen)
120{
121 genesis_context *gen = vgen;
122 uint32_t ram_size = load_int8(buf) * 1024 / 2;
123 if (ram_size > RAM_WORDS) {
124 fatal_error("State has a RAM size of %d bytes", ram_size * 2);
125 }
126 load_buffer16(buf, gen->work_ram, ram_size);
127 m68k_invalidate_code_range(gen->m68k, 0xE00000, 0x1000000);
128}
129
130static void zram_deserialize(deserialize_buffer *buf, void *vgen)
131{
132 genesis_context *gen = vgen;
133 uint32_t ram_size = load_int8(buf) * 1024;
134 if (ram_size > Z80_RAM_BYTES) {
135 fatal_error("State has a Z80 RAM size of %d bytes", ram_size);
136 }
137 load_buffer8(buf, gen->zram, ram_size);
138 z80_invalidate_code_range(gen->z80, 0, 0x4000);
139}
140
141static void update_z80_bank_pointer(genesis_context *gen)
142{
143 if (gen->z80_bank_reg < 0x140) {
144 gen->z80->mem_pointers[1] = get_native_pointer(gen->z80_bank_reg << 15, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen);
145 } else {
146 gen->z80->mem_pointers[1] = NULL;
147 }
148 z80_invalidate_code_range(gen->z80, 0x8000, 0xFFFF);
149}
150
151static void bus_arbiter_deserialize(deserialize_buffer *buf, void *vgen)
152{
153 genesis_context *gen = vgen;
154 gen->z80->reset = load_int8(buf);
155 gen->z80->busreq = load_int8(buf);
156 gen->z80_bank_reg = load_int16(buf) & 0x1FF;
157}
158
159static void adjust_int_cycle(m68k_context * context, vdp_context * v_context);
160void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen)
161{
162 register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = gen->m68k}, SECTION_68000);
163 register_section_handler(buf, (section_handler){.fun = z80_deserialize, .data = gen->z80}, SECTION_Z80);
164 register_section_handler(buf, (section_handler){.fun = vdp_deserialize, .data = gen->vdp}, SECTION_VDP);
165 register_section_handler(buf, (section_handler){.fun = ym_deserialize, .data = gen->ym}, SECTION_YM2612);
166 register_section_handler(buf, (section_handler){.fun = psg_deserialize, .data = gen->psg}, SECTION_PSG);
167 register_section_handler(buf, (section_handler){.fun = bus_arbiter_deserialize, .data = gen}, SECTION_GEN_BUS_ARBITER);
168 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports}, SECTION_SEGA_IO_1);
169 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 1}, SECTION_SEGA_IO_2);
170 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 2}, SECTION_SEGA_IO_EXT);
171 register_section_handler(buf, (section_handler){.fun = ram_deserialize, .data = gen}, SECTION_MAIN_RAM);
172 register_section_handler(buf, (section_handler){.fun = zram_deserialize, .data = gen}, SECTION_SOUND_RAM);
173 register_section_handler(buf, (section_handler){.fun = cart_deserialize, .data = gen}, SECTION_MAPPER);
174 while (buf->cur_pos < buf->size)
175 {
176 load_section(buf);
177 }
178 update_z80_bank_pointer(gen);
179 adjust_int_cycle(gen->m68k, gen->vdp);
180 free(buf->handlers);
181 buf->handlers = NULL;
182}
183
184#include "m68k_internal.h" //needed for get_native_address_trans, should be eliminated once handling of PC is cleaned up
185static void deserialize(system_header *sys, uint8_t *data, size_t size)
186{
187 genesis_context *gen = (genesis_context *)sys;
188 deserialize_buffer buffer;
189 init_deserialize(&buffer, data, size);
190 genesis_deserialize(&buffer, gen);
191 //HACK: Fix this once PC/IR is represented in a better way in 68K core
192 gen->m68k->resume_pc = get_native_address_trans(gen->m68k, gen->m68k->last_prefetch_address);
193}
194
195uint16_t read_dma_value(uint32_t address)
196{
197 genesis_context *genesis = (genesis_context *)current_system;
198 //TODO: Figure out what happens when you try to DMA from weird adresses like IO or banked Z80 area
199 if ((address >= 0xA00000 && address < 0xB00000) || (address >= 0xC00000 && address <= 0xE00000)) {
200 return 0;
201 }
202
203 //addresses here are word addresses (i.e. bit 0 corresponds to A1), so no need to do multiply by 2
204 return read_word(address * 2, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen, genesis->m68k);
205}
206
207static uint16_t get_open_bus_value(system_header *system)
208{
209 genesis_context *genesis = (genesis_context *)system;
210 return read_dma_value(genesis->m68k->last_prefetch_address/2);
211}
212
213static void adjust_int_cycle(m68k_context * context, vdp_context * v_context)
214{
215 //static int old_int_cycle = CYCLE_NEVER;
216 genesis_context *gen = context->system;
217 if (context->sync_cycle - context->current_cycle > gen->max_cycles) {
218 context->sync_cycle = context->current_cycle + gen->max_cycles;
219 }
220 context->int_cycle = CYCLE_NEVER;
221 if ((context->status & 0x7) < 6) {
222 uint32_t next_vint = vdp_next_vint(v_context);
223 if (next_vint != CYCLE_NEVER) {
224 context->int_cycle = next_vint;
225 context->int_num = 6;
226 }
227 if ((context->status & 0x7) < 4) {
228 uint32_t next_hint = vdp_next_hint(v_context);
229 if (next_hint != CYCLE_NEVER) {
230 next_hint = next_hint < context->current_cycle ? context->current_cycle : next_hint;
231 if (next_hint < context->int_cycle) {
232 context->int_cycle = next_hint;
233 context->int_num = 4;
234
235 }
236 }
237 }
238 }
239 if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) {
240 context->int_pending = INT_PENDING_NONE;
241 }
242 /*if (context->int_cycle != old_int_cycle) {
243 printf("int cycle changed to: %d, level: %d @ %d(%d), frame: %d, vcounter: %d, hslot: %d, mask: %d, hint_counter: %d\n", context->int_cycle, context->int_num, v_context->cycles, context->current_cycle, v_context->frame, v_context->vcounter, v_context->hslot, context->status & 0x7, v_context->hint_counter);
244 old_int_cycle = context->int_cycle;
245 }*/
246
247 if (context->status & M68K_STATUS_TRACE || context->trace_pending) {
248 context->target_cycle = context->current_cycle;
249 return;
250 }
251
252 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle;
253 if (context->should_return) {
254 context->target_cycle = context->current_cycle;
255 } else if (context->target_cycle < context->current_cycle) {
256 //Changes to SR can result in an interrupt cycle that's in the past
257 //This can cause issues with the implementation of STOP though
258 context->target_cycle = context->current_cycle;
259 }
260 if (context->target_cycle == context->int_cycle) {
261 //Currently delays from Z80 access and refresh are applied only when we sync
262 //this can cause extra latency when it comes to interrupts
263 //to prevent this code forces some extra synchronization in the period immediately before an interrupt
264 if ((context->target_cycle - context->current_cycle) > gen->int_latency_prev1) {
265 context->target_cycle = context->sync_cycle = context->int_cycle - gen->int_latency_prev1;
266 } else if ((context->target_cycle - context->current_cycle) > gen->int_latency_prev2) {
267 context->target_cycle = context->sync_cycle = context->int_cycle - gen->int_latency_prev2;
268 } else {
269 context->target_cycle = context->sync_cycle = context->current_cycle;
270 }
271
272 }
273 /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n",
274 context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7),
275 v_context->regs[REG_MODE_2] & 0x20, v_context->regs[REG_MODE_1] & 0x10, v_context->hint_counter, v_context->regs[REG_HINT], v_context->cycles / MCLKS_LINE);*/
276}
277
278//#define DO_DEBUG_PRINT
279#ifdef DO_DEBUG_PRINT
280#define dprintf printf
281#define dputs puts
282#else
283#define dprintf
284#define dputs
285#endif
286
287static void z80_next_int_pulse(z80_context * z_context)
288{
289 genesis_context * gen = z_context->system;
290 z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp);
291 z_context->int_pulse_end = z_context->int_pulse_start + Z80_INT_PULSE_MCLKS;
292 z_context->im2_vector = 0xFF;
293}
294
295static void sync_z80(z80_context * z_context, uint32_t mclks)
296{
297 if (z80_enabled) {
298 z80_run(z_context, mclks);
299 } else
300 {
301 z_context->Z80_CYCLE = mclks;
302 }
303}
304
305static void sync_sound(genesis_context * gen, uint32_t target)
306{
307 //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);
308 while (target > gen->psg->cycles && target - gen->psg->cycles > MAX_SOUND_CYCLES) {
309 uint32_t cur_target = gen->psg->cycles + MAX_SOUND_CYCLES;
310 //printf("Running PSG to cycle %d\n", cur_target);
311 psg_run(gen->psg, cur_target);
312 //printf("Running YM-2612 to cycle %d\n", cur_target);
313 ym_run(gen->ym, cur_target);
314 }
315 psg_run(gen->psg, target);
316 ym_run(gen->ym, target);
317
318 //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2);
319}
320
321//TODO: move this inside the system context
322static uint32_t last_frame_num;
323
324//My refresh emulation isn't currently good enough and causes more problems than it solves
325#define REFRESH_EMULATION
326#ifdef REFRESH_EMULATION
327#define REFRESH_INTERVAL 128
328#define REFRESH_DELAY 2
329uint32_t last_sync_cycle;
330uint32_t refresh_counter;
331#endif
332
333#include <limits.h>
334#define ADJUST_BUFFER (8*MCLKS_LINE*313)
335#define MAX_NO_ADJUST (UINT_MAX-ADJUST_BUFFER)
336
337m68k_context * sync_components(m68k_context * context, uint32_t address)
338{
339 genesis_context * gen = context->system;
340 vdp_context * v_context = gen->vdp;
341 z80_context * z_context = gen->z80;
342#ifdef REFRESH_EMULATION
343 //lame estimation of refresh cycle delay
344 refresh_counter += context->current_cycle - last_sync_cycle;
345 if (!gen->bus_busy) {
346 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL));
347 }
348 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
349#endif
350
351 uint32_t mclks = context->current_cycle;
352 sync_z80(z_context, mclks);
353 sync_sound(gen, mclks);
354 vdp_run_context(v_context, mclks);
355 if (mclks >= gen->reset_cycle) {
356 gen->reset_requested = 1;
357 context->should_return = 1;
358 gen->reset_cycle = CYCLE_NEVER;
359 }
360 if (v_context->frame != last_frame_num) {
361 //printf("reached frame end %d | MCLK Cycles: %d, Target: %d, VDP cycles: %d, vcounter: %d, hslot: %d\n", last_frame_num, mclks, gen->frame_end, v_context->cycles, v_context->vcounter, v_context->hslot);
362 last_frame_num = v_context->frame;
363
364 if(exit_after){
365 --exit_after;
366 if (!exit_after) {
367 exit(0);
368 }
369 }
370 if (context->current_cycle > MAX_NO_ADJUST) {
371 uint32_t deduction = mclks - ADJUST_BUFFER;
372 vdp_adjust_cycles(v_context, deduction);
373 io_adjust_cycles(gen->io.ports, context->current_cycle, deduction);
374 io_adjust_cycles(gen->io.ports+1, context->current_cycle, deduction);
375 io_adjust_cycles(gen->io.ports+2, context->current_cycle, deduction);
376 if (gen->mapper_type == MAPPER_JCART) {
377 jcart_adjust_cycles(gen, deduction);
378 }
379 context->current_cycle -= deduction;
380 z80_adjust_cycles(z_context, deduction);
381 gen->ym->current_cycle -= deduction;
382 gen->psg->cycles -= deduction;
383 if (gen->ym->write_cycle != CYCLE_NEVER) {
384 gen->ym->write_cycle = gen->ym->write_cycle >= deduction ? gen->ym->write_cycle - deduction : 0;
385 }
386 if (gen->reset_cycle != CYCLE_NEVER) {
387 gen->reset_cycle -= deduction;
388 }
389 }
390 }
391 gen->frame_end = vdp_cycles_to_frame_end(v_context);
392 context->sync_cycle = gen->frame_end;
393 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot);
394 if (context->int_ack) {
395 //printf("acknowledging %d @ %d:%d, vcounter: %d, hslot: %d\n", context->int_ack, context->current_cycle, v_context->cycles, v_context->vcounter, v_context->hslot);
396 vdp_int_ack(v_context);
397 context->int_ack = 0;
398 }
399 if (!address && (gen->header.enter_debugger || gen->header.save_state)) {
400 context->sync_cycle = context->current_cycle + 1;
401 }
402 adjust_int_cycle(context, v_context);
403 if (gen->reset_cycle < context->target_cycle) {
404 context->target_cycle = gen->reset_cycle;
405 }
406 if (address) {
407 if (gen->header.enter_debugger) {
408 gen->header.enter_debugger = 0;
409 debugger(context, address);
410 }
411 if (gen->header.save_state && (z_context->pc || !z_context->native_pc || z_context->reset || !z_context->busreq)) {
412 uint8_t slot = gen->header.save_state - 1;
413 gen->header.save_state = 0;
414 if (z_context->native_pc && !z_context->reset) {
415 //advance Z80 core to the start of an instruction
416 while (!z_context->pc)
417 {
418 sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80);
419 }
420 }
421 char *save_path = slot == SERIALIZE_SLOT ? NULL : get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst");
422 if (use_native_states || slot == SERIALIZE_SLOT) {
423 serialize_buffer state;
424 init_serialize(&state);
425 genesis_serialize(gen, &state, address);
426 if (slot == SERIALIZE_SLOT) {
427 gen->serialize_tmp = state.data;
428 gen->serialize_size = state.size;
429 context->sync_cycle = context->current_cycle;
430 context->should_return = 1;
431 } else {
432 save_to_file(&state, save_path);
433 free(state.data);
434 }
435 } else {
436 save_gst(gen, save_path, address);
437 }
438 printf("Saved state to %s\n", save_path);
439 free(save_path);
440 } else if(gen->header.save_state) {
441 context->sync_cycle = context->current_cycle + 1;
442 }
443 }
444#ifdef REFRESH_EMULATION
445 last_sync_cycle = context->current_cycle;
446#endif
447 return context;
448}
449
450static m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value)
451{
452 if (vdp_port & 0x2700E0) {
453 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port);
454 }
455 vdp_port &= 0x1F;
456 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle);
457#ifdef REFRESH_EMULATION
458 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access
459 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle;
460 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL));
461 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
462 last_sync_cycle = context->current_cycle;
463#endif
464 sync_components(context, 0);
465 genesis_context * gen = context->system;
466 vdp_context *v_context = gen->vdp;
467 uint32_t before_cycle = v_context->cycles;
468 if (vdp_port < 0x10) {
469 int blocked;
470 if (vdp_port < 4) {
471 while (vdp_data_port_write(v_context, value) < 0) {
472 while(v_context->flags & FLAG_DMA_RUN) {
473 vdp_run_dma_done(v_context, gen->frame_end);
474 if (v_context->cycles >= gen->frame_end) {
475 uint32_t cycle_diff = v_context->cycles - context->current_cycle;
476 uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
477 if (m68k_cycle_diff < cycle_diff) {
478 m68k_cycle_diff += MCLKS_PER_68K;
479 }
480 context->current_cycle += m68k_cycle_diff;
481 gen->bus_busy = 1;
482 sync_components(context, 0);
483 gen->bus_busy = 0;
484 }
485 }
486 //context->current_cycle = v_context->cycles;
487 }
488 } else if(vdp_port < 8) {
489 vdp_run_context_full(v_context, context->current_cycle);
490 before_cycle = v_context->cycles;
491 blocked = vdp_control_port_write(v_context, value);
492 if (blocked) {
493 while (blocked) {
494 while(v_context->flags & FLAG_DMA_RUN) {
495 vdp_run_dma_done(v_context, gen->frame_end);
496 if (v_context->cycles >= gen->frame_end) {
497 uint32_t cycle_diff = v_context->cycles - context->current_cycle;
498 uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
499 if (m68k_cycle_diff < cycle_diff) {
500 m68k_cycle_diff += MCLKS_PER_68K;
501 }
502 context->current_cycle += m68k_cycle_diff;
503 gen->bus_busy = 1;
504 sync_components(context, 0);
505 gen->bus_busy = 0;
506 }
507 }
508
509 if (blocked < 0) {
510 blocked = vdp_control_port_write(v_context, value);
511 } else {
512 blocked = 0;
513 }
514 }
515 } else {
516 context->sync_cycle = gen->frame_end = vdp_cycles_to_frame_end(v_context);
517 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot);
518 adjust_int_cycle(context, v_context);
519 }
520 } else {
521 fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
522 }
523 if (v_context->cycles != before_cycle) {
524 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for write\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle);
525 uint32_t cycle_diff = v_context->cycles - context->current_cycle;
526 uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
527 if (m68k_cycle_diff < cycle_diff) {
528 m68k_cycle_diff += MCLKS_PER_68K;
529 }
530 context->current_cycle += m68k_cycle_diff;
531 //Lock the Z80 out of the bus until the VDP access is complete
532 gen->bus_busy = 1;
533 sync_z80(gen->z80, v_context->cycles);
534 gen->bus_busy = 0;
535 }
536 } else if (vdp_port < 0x18) {
537 psg_write(gen->psg, value);
538 } else {
539 vdp_test_port_write(gen->vdp, value);
540 }
541#ifdef REFRESH_EMULATION
542 last_sync_cycle -= 4;
543 //refresh may have happened while we were waiting on the VDP,
544 //so advance refresh_counter but don't add any delays
545 if (vdp_port >= 4 && vdp_port < 8 && v_context->cycles != before_cycle) {
546 refresh_counter = 0;
547 } else {
548 refresh_counter += (context->current_cycle - last_sync_cycle);
549 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
550 }
551 last_sync_cycle = context->current_cycle;
552#endif
553 return context;
554}
555
556static m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8_t value)
557{
558 return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : ((vdp_port & 1) ? value : 0));
559}
560
561static void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value)
562{
563 z80_context * context = vcontext;
564 genesis_context * gen = context->system;
565 vdp_port &= 0xFF;
566 if (vdp_port & 0xE0) {
567 fatal_error("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port);
568 }
569 if (vdp_port < 0x10) {
570 //These probably won't currently interact well with the 68K accessing the VDP
571 if (vdp_port < 4) {
572 vdp_run_context(gen->vdp, context->Z80_CYCLE);
573 vdp_data_port_write(gen->vdp, value << 8 | value);
574 } else if (vdp_port < 8) {
575 vdp_run_context_full(gen->vdp, context->Z80_CYCLE);
576 vdp_control_port_write(gen->vdp, value << 8 | value);
577 } else {
578 fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
579 }
580 } else if (vdp_port < 0x18) {
581 sync_sound(gen, context->Z80_CYCLE);
582 psg_write(gen->psg, value);
583 } else {
584 vdp_test_port_write(gen->vdp, value);
585 }
586 return context;
587}
588
589static uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context)
590{
591 if (vdp_port & 0x2700E0) {
592 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port);
593 }
594 vdp_port &= 0x1F;
595 uint16_t value;
596#ifdef REFRESH_EMULATION
597 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access
598 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle;
599 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL));
600 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
601 last_sync_cycle = context->current_cycle;
602#endif
603 sync_components(context, 0);
604 genesis_context *gen = context->system;
605 vdp_context * v_context = gen->vdp;
606 uint32_t before_cycle = v_context->cycles;
607 if (vdp_port < 0x10) {
608 if (vdp_port < 4) {
609 value = vdp_data_port_read(v_context);
610 } else if(vdp_port < 8) {
611 value = vdp_control_port_read(v_context);
612 } else {
613 value = vdp_hv_counter_read(v_context);
614 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles);
615 }
616 } else if (vdp_port < 0x18){
617 fatal_error("Illegal read from PSG port %X\n", vdp_port);
618 } else {
619 value = vdp_test_port_read(v_context);
620 }
621 if (v_context->cycles != before_cycle) {
622 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle);
623 context->current_cycle = v_context->cycles;
624 //Lock the Z80 out of the bus until the VDP access is complete
625 genesis_context *gen = context->system;
626 gen->bus_busy = 1;
627 sync_z80(gen->z80, v_context->cycles);
628 gen->bus_busy = 0;
629 }
630#ifdef REFRESH_EMULATION
631 last_sync_cycle -= 4;
632 //refresh may have happened while we were waiting on the VDP,
633 //so advance refresh_counter but don't add any delays
634 refresh_counter += (context->current_cycle - last_sync_cycle);
635 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
636 last_sync_cycle = context->current_cycle;
637#endif
638 return value;
639}
640
641static uint8_t vdp_port_read_b(uint32_t vdp_port, m68k_context * context)
642{
643 uint16_t value = vdp_port_read(vdp_port, context);
644 if (vdp_port & 1) {
645 return value;
646 } else {
647 return value >> 8;
648 }
649}
650
651static uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext)
652{
653 z80_context * context = vcontext;
654 if (vdp_port & 0xE0) {
655 fatal_error("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port);
656 }
657 genesis_context * gen = context->system;
658 //VDP access goes over the 68K bus like a bank area access
659 //typical delay from bus arbitration
660 context->Z80_CYCLE += 3 * MCLKS_PER_Z80;
661 //TODO: add cycle for an access right after a previous one
662 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
663 // Needs a new logic analyzer capture to get the actual delay on the 68K side
664 gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
665
666
667 vdp_port &= 0x1F;
668 uint16_t ret;
669 if (vdp_port < 0x10) {
670 //These probably won't currently interact well with the 68K accessing the VDP
671 vdp_run_context(gen->vdp, context->Z80_CYCLE);
672 if (vdp_port < 4) {
673 ret = vdp_data_port_read(gen->vdp);
674 } else if (vdp_port < 8) {
675 ret = vdp_control_port_read(gen->vdp);
676 } else {
677 ret = vdp_hv_counter_read(gen->vdp);
678 }
679 } else {
680 //TODO: Figure out the correct value today
681 ret = 0xFFFF;
682 }
683 return vdp_port & 1 ? ret : ret >> 8;
684}
685
686//TODO: Move this inside the system context
687static uint32_t zram_counter = 0;
688
689static m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value)
690{
691 genesis_context * gen = context->system;
692 if (location < 0x10000) {
693 //Access to Z80 memory incurs a one 68K cycle wait state
694 context->current_cycle += MCLKS_PER_68K;
695 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) {
696 location &= 0x7FFF;
697 if (location < 0x4000) {
698 gen->zram[location & 0x1FFF] = value;
699 z80_handle_code_write(location & 0x1FFF, gen->z80);
700 } else if (location < 0x6000) {
701 sync_sound(gen, context->current_cycle);
702 if (location & 1) {
703 ym_data_write(gen->ym, value);
704 } else if(location & 2) {
705 ym_address_write_part2(gen->ym, value);
706 } else {
707 ym_address_write_part1(gen->ym, value);
708 }
709 } else if (location == 0x6000) {
710 gen->z80_bank_reg = (gen->z80_bank_reg >> 1 | value << 8) & 0x1FF;
711 if (gen->z80_bank_reg < 0x80) {
712 gen->z80->mem_pointers[1] = (gen->z80_bank_reg << 15) + ((char *)gen->z80->mem_pointers[2]);
713 } else {
714 gen->z80->mem_pointers[1] = NULL;
715 }
716 } else {
717 fatal_error("68K write to unhandled Z80 address %X\n", location);
718 }
719 }
720 } else {
721 location &= 0x1FFF;
722 if (location < 0x100) {
723 switch(location/2)
724 {
725 case 0x1:
726 io_data_write(gen->io.ports, value, context->current_cycle);
727 break;
728 case 0x2:
729 io_data_write(gen->io.ports+1, value, context->current_cycle);
730 break;
731 case 0x3:
732 io_data_write(gen->io.ports+2, value, context->current_cycle);
733 break;
734 case 0x4:
735 io_control_write(gen->io.ports, value, context->current_cycle);
736 break;
737 case 0x5:
738 io_control_write(gen->io.ports+1, value, context->current_cycle);
739 break;
740 case 0x6:
741 io_control_write(gen->io.ports+2, value, context->current_cycle);
742 break;
743 case 0x7:
744 gen->io.ports[0].serial_out = value;
745 break;
746 case 0x8:
747 case 0xB:
748 case 0xE:
749 //serial input port is not writeable
750 break;
751 case 0x9:
752 gen->io.ports[0].serial_ctrl = value;
753 break;
754 case 0xA:
755 gen->io.ports[1].serial_out = value;
756 break;
757 case 0xC:
758 gen->io.ports[1].serial_ctrl = value;
759 break;
760 case 0xD:
761 gen->io.ports[2].serial_out = value;
762 break;
763 case 0xF:
764 gen->io.ports[2].serial_ctrl = value;
765 break;
766 }
767 } else {
768 if (location == 0x1100) {
769 if (value & 1) {
770 dputs("bus requesting Z80");
771 if (z80_enabled) {
772 z80_assert_busreq(gen->z80, context->current_cycle);
773 } else {
774 gen->z80->busack = 1;
775 }
776 } else {
777 if (gen->z80->busreq) {
778 dputs("releasing z80 bus");
779 #ifdef DO_DEBUG_PRINT
780 char fname[20];
781 sprintf(fname, "zram-%d", zram_counter++);
782 FILE * f = fopen(fname, "wb");
783 fwrite(z80_ram, 1, sizeof(z80_ram), f);
784 fclose(f);
785 #endif
786 }
787 if (z80_enabled) {
788 z80_clear_busreq(gen->z80, context->current_cycle);
789 } else {
790 gen->z80->busack = 0;
791 }
792 }
793 } else if (location == 0x1200) {
794 sync_z80(gen->z80, context->current_cycle);
795 if (value & 1) {
796 if (z80_enabled) {
797 z80_clear_reset(gen->z80, context->current_cycle);
798 } else {
799 gen->z80->reset = 0;
800 }
801 } else {
802 if (z80_enabled) {
803 z80_assert_reset(gen->z80, context->current_cycle);
804 } else {
805 gen->z80->reset = 1;
806 }
807 ym_reset(gen->ym);
808 }
809 }
810 }
811 }
812 return context;
813}
814
815static m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value)
816{
817 if (location < 0x10000 || (location & 0x1FFF) >= 0x100) {
818 return io_write(location, context, value >> 8);
819 } else {
820 return io_write(location, context, value);
821 }
822}
823
824#define FOREIGN 0x80
825#define HZ50 0x40
826#define USA FOREIGN
827#define JAP 0x00
828#define EUR (HZ50|FOREIGN)
829#define NO_DISK 0x20
830
831static uint8_t io_read(uint32_t location, m68k_context * context)
832{
833 uint8_t value;
834 genesis_context *gen = context->system;
835 if (location < 0x10000) {
836 //Access to Z80 memory incurs a one 68K cycle wait state
837 context->current_cycle += MCLKS_PER_68K;
838 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) {
839 location &= 0x7FFF;
840 if (location < 0x4000) {
841 value = gen->zram[location & 0x1FFF];
842 } else if (location < 0x6000) {
843 sync_sound(gen, context->current_cycle);
844 value = ym_read_status(gen->ym);
845 } else {
846 value = 0xFF;
847 }
848 } else {
849 value = 0xFF;
850 }
851 } else {
852 location &= 0x1FFF;
853 if (location < 0x100) {
854 switch(location/2)
855 {
856 case 0x0:
857 //version bits should be 0 for now since we're not emulating TMSS
858 value = gen->version_reg;
859 break;
860 case 0x1:
861 value = io_data_read(gen->io.ports, context->current_cycle);
862 break;
863 case 0x2:
864 value = io_data_read(gen->io.ports+1, context->current_cycle);
865 break;
866 case 0x3:
867 value = io_data_read(gen->io.ports+2, context->current_cycle);
868 break;
869 case 0x4:
870 value = gen->io.ports[0].control;
871 break;
872 case 0x5:
873 value = gen->io.ports[1].control;
874 break;
875 case 0x6:
876 value = gen->io.ports[2].control;
877 break;
878 case 0x7:
879 value = gen->io.ports[0].serial_out;
880 break;
881 case 0x8:
882 value = gen->io.ports[0].serial_in;
883 break;
884 case 0x9:
885 value = gen->io.ports[0].serial_ctrl;
886 break;
887 case 0xA:
888 value = gen->io.ports[1].serial_out;
889 break;
890 case 0xB:
891 value = gen->io.ports[1].serial_in;
892 break;
893 case 0xC:
894 value = gen->io.ports[1].serial_ctrl;
895 break;
896 case 0xD:
897 value = gen->io.ports[2].serial_out;
898 break;
899 case 0xE:
900 value = gen->io.ports[2].serial_in;
901 break;
902 case 0xF:
903 value = gen->io.ports[2].serial_ctrl;
904 break;
905 default:
906 value = 0xFF;
907 }
908 } else {
909 if (location == 0x1100) {
910 value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : !gen->z80->busack;
911 value |= (get_open_bus_value(&gen->header) >> 8) & 0xFE;
912 dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset);
913 } else if (location == 0x1200) {
914 value = !gen->z80->reset;
915 } else {
916 value = 0xFF;
917 printf("Byte read of unknown IO location: %X\n", location);
918 }
919 }
920 }
921 return value;
922}
923
924static uint16_t io_read_w(uint32_t location, m68k_context * context)
925{
926 genesis_context *gen = context->system;
927 uint16_t value = io_read(location, context);
928 if (location < 0x10000 || (location & 0x1FFF) < 0x100) {
929 value = value | (value << 8);
930 } else {
931 value <<= 8;
932 value |= get_open_bus_value(&gen->header) & 0xFF;
933 }
934 return value;
935}
936
937static void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value)
938{
939 z80_context * context = vcontext;
940 genesis_context * gen = context->system;
941 sync_sound(gen, context->Z80_CYCLE);
942 if (location & 1) {
943 ym_data_write(gen->ym, value);
944 } else if (location & 2) {
945 ym_address_write_part2(gen->ym, value);
946 } else {
947 ym_address_write_part1(gen->ym, value);
948 }
949 return context;
950}
951
952static uint8_t z80_read_ym(uint32_t location, void * vcontext)
953{
954 z80_context * context = vcontext;
955 genesis_context * gen = context->system;
956 sync_sound(gen, context->Z80_CYCLE);
957 return ym_read_status(gen->ym);
958}
959
960static uint8_t z80_read_bank(uint32_t location, void * vcontext)
961{
962 z80_context * context = vcontext;
963 genesis_context *gen = context->system;
964 if (gen->bus_busy) {
965 context->Z80_CYCLE = gen->m68k->current_cycle;
966 }
967 //typical delay from bus arbitration
968 context->Z80_CYCLE += 3 * MCLKS_PER_Z80;
969 //TODO: add cycle for an access right after a previous one
970 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
971 // Needs a new logic analyzer capture to get the actual delay on the 68K side
972 gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
973
974 location &= 0x7FFF;
975 if (context->mem_pointers[1]) {
976 return context->mem_pointers[1][location ^ 1];
977 }
978 uint32_t address = gen->z80_bank_reg << 15 | location;
979 if (address >= 0xC00000 && address < 0xE00000) {
980 return z80_vdp_port_read(location & 0xFF, context);
981 } else {
982 fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, gen->z80_bank_reg << 15);
983 }
984 return 0;
985}
986
987static void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value)
988{
989 z80_context * context = vcontext;
990 genesis_context *gen = context->system;
991 if (gen->bus_busy) {
992 context->Z80_CYCLE = gen->m68k->current_cycle;
993 }
994 //typical delay from bus arbitration
995 context->Z80_CYCLE += 3 * MCLKS_PER_Z80;
996 //TODO: add cycle for an access right after a previous one
997 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
998 // Needs a new logic analyzer capture to get the actual delay on the 68K side
999 gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
1000
1001 location &= 0x7FFF;
1002 uint32_t address = gen->z80_bank_reg << 15 | location;
1003 if (address >= 0xE00000) {
1004 address &= 0xFFFF;
1005 ((uint8_t *)gen->work_ram)[address ^ 1] = value;
1006 } else if (address >= 0xC00000) {
1007 z80_vdp_port_write(location & 0xFF, context, value);
1008 } else {
1009 fprintf(stderr, "Unhandled write by Z80 to address %X through banked memory area\n", address);
1010 }
1011 return context;
1012}
1013
1014static void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value)
1015{
1016 z80_context * context = vcontext;
1017 genesis_context *gen = context->system;
1018
1019 gen->z80_bank_reg = (gen->z80_bank_reg >> 1 | value << 8) & 0x1FF;
1020 update_z80_bank_pointer(context->system);
1021
1022 return context;
1023}
1024
1025static void set_speed_percent(system_header * system, uint32_t percent)
1026{
1027 genesis_context *context = (genesis_context *)system;
1028 uint32_t old_clock = context->master_clock;
1029 context->master_clock = ((uint64_t)context->normal_clock * (uint64_t)percent) / 100;
1030 while (context->ym->current_cycle != context->psg->cycles) {
1031 sync_sound(context, context->psg->cycles + MCLKS_PER_PSG);
1032 }
1033 ym_adjust_master_clock(context->ym, context->master_clock);
1034 psg_adjust_master_clock(context->psg, context->master_clock);
1035}
1036
1037void set_region(genesis_context *gen, rom_info *info, uint8_t region)
1038{
1039 if (!region) {
1040 char * def_region = tern_find_path_default(config, "system\0default_region\0", (tern_val){.ptrval = "U"}, TVAL_PTR).ptrval;
1041 if (!info->regions || (info->regions & translate_region_char(toupper(*def_region)))) {
1042 region = translate_region_char(toupper(*def_region));
1043 } else {
1044 region = info->regions;
1045 }
1046 }
1047 if (region & REGION_E) {
1048 gen->version_reg = NO_DISK | EUR;
1049 } else if (region & REGION_J) {
1050 gen->version_reg = NO_DISK | JAP;
1051 } else {
1052 gen->version_reg = NO_DISK | USA;
1053 }
1054
1055 if (region & HZ50) {
1056 gen->normal_clock = MCLKS_PAL;
1057 } else {
1058 gen->normal_clock = MCLKS_NTSC;
1059 }
1060 gen->master_clock = gen->normal_clock;
1061}
1062
1063static uint8_t load_state(system_header *system, uint8_t slot)
1064{
1065 genesis_context *gen = (genesis_context *)system;
1066 char *statepath = get_slot_name(system, slot, "state");
1067 deserialize_buffer state;
1068 uint32_t pc = 0;
1069 uint8_t ret;
1070 if (!gen->m68k->resume_pc) {
1071 system->delayed_load_slot = slot + 1;
1072 gen->m68k->should_return = 1;
1073 ret = get_modification_time(statepath) != 0;
1074 if (!ret) {
1075 strcpy(statepath + strlen(statepath)-strlen("state"), "gst");
1076 ret = get_modification_time(statepath) != 0;
1077 }
1078 goto done;
1079 }
1080 if (load_from_file(&state, statepath)) {
1081 genesis_deserialize(&state, gen);
1082 free(state.data);
1083 //HACK
1084 pc = gen->m68k->last_prefetch_address;
1085 ret = 1;
1086 } else {
1087 strcpy(statepath + strlen(statepath)-strlen("state"), "gst");
1088 pc = load_gst(gen, statepath);
1089 ret = pc != 0;
1090 }
1091 if (ret) {
1092 gen->m68k->resume_pc = get_native_address_trans(gen->m68k, pc);
1093 }
1094done:
1095 free(statepath);
1096 return ret;
1097}
1098
1099static void handle_reset_requests(genesis_context *gen)
1100{
1101 while (gen->reset_requested || gen->header.delayed_load_slot)
1102 {
1103 if (gen->reset_requested) {
1104 gen->reset_requested = 0;
1105 gen->m68k->should_return = 0;
1106 z80_assert_reset(gen->z80, gen->m68k->current_cycle);
1107 z80_clear_busreq(gen->z80, gen->m68k->current_cycle);
1108 ym_reset(gen->ym);
1109 //Is there any sort of VDP reset?
1110 m68k_reset(gen->m68k);
1111 }
1112 if (gen->header.delayed_load_slot) {
1113 load_state(&gen->header, gen->header.delayed_load_slot - 1);
1114 gen->header.delayed_load_slot = 0;
1115 resume_68k(gen->m68k);
1116 }
1117 }
1118 bindings_release_capture();
1119 vdp_release_framebuffer(gen->vdp);
1120 render_pause_source(gen->ym->audio);
1121 render_pause_source(gen->psg->audio);
1122}
1123
1124static void start_genesis(system_header *system, char *statefile)
1125{
1126 genesis_context *gen = (genesis_context *)system;
1127 if (statefile) {
1128 //first try loading as a native format savestate
1129 deserialize_buffer state;
1130 uint32_t pc;
1131 if (load_from_file(&state, statefile)) {
1132 genesis_deserialize(&state, gen);
1133 free(state.data);
1134 //HACK
1135 pc = gen->m68k->last_prefetch_address;
1136 } else {
1137 pc = load_gst(gen, statefile);
1138 if (!pc) {
1139 fatal_error("Failed to load save state %s\n", statefile);
1140 }
1141 }
1142 printf("Loaded %s\n", statefile);
1143 if (gen->header.enter_debugger) {
1144 gen->header.enter_debugger = 0;
1145 insert_breakpoint(gen->m68k, pc, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter);
1146 }
1147 adjust_int_cycle(gen->m68k, gen->vdp);
1148 start_68k_context(gen->m68k, pc);
1149 } else {
1150 if (gen->header.enter_debugger) {
1151 gen->header.enter_debugger = 0;
1152 uint32_t address = gen->cart[2] << 16 | gen->cart[3];
1153 insert_breakpoint(gen->m68k, address, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter);
1154 }
1155 m68k_reset(gen->m68k);
1156 }
1157 handle_reset_requests(gen);
1158 return;
1159}
1160
1161static void resume_genesis(system_header *system)
1162{
1163 genesis_context *gen = (genesis_context *)system;
1164 render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC);
1165 bindings_reacquire_capture();
1166 vdp_reacquire_framebuffer(gen->vdp);
1167 render_resume_source(gen->ym->audio);
1168 render_resume_source(gen->psg->audio);
1169 resume_68k(gen->m68k);
1170 handle_reset_requests(gen);
1171}
1172
1173static void inc_debug_mode(system_header *system)
1174{
1175 genesis_context *gen = (genesis_context *)system;
1176 vdp_inc_debug_mode(gen->vdp);
1177}
1178
1179static void request_exit(system_header *system)
1180{
1181 genesis_context *gen = (genesis_context *)system;
1182 gen->m68k->target_cycle = gen->m68k->current_cycle;
1183 gen->m68k->should_return = 1;
1184}
1185
1186static void persist_save(system_header *system)
1187{
1188 genesis_context *gen = (genesis_context *)system;
1189 if (gen->save_type == SAVE_NONE) {
1190 return;
1191 }
1192 FILE * f = fopen(save_filename, "wb");
1193 if (!f) {
1194 fprintf(stderr, "Failed to open %s file %s for writing\n", save_type_name(gen->save_type), save_filename);
1195 return;
1196 }
1197 fwrite(gen->save_storage, 1, gen->save_size, f);
1198 fclose(f);
1199 printf("Saved %s to %s\n", save_type_name(gen->save_type), save_filename);
1200}
1201
1202static void load_save(system_header *system)
1203{
1204 genesis_context *gen = (genesis_context *)system;
1205 FILE * f = fopen(save_filename, "rb");
1206 if (f) {
1207 uint32_t read = fread(gen->save_storage, 1, gen->save_size, f);
1208 fclose(f);
1209 if (read > 0) {
1210 printf("Loaded %s from %s\n", save_type_name(gen->save_type), save_filename);
1211 }
1212 }
1213}
1214
1215static void soft_reset(system_header *system)
1216{
1217 genesis_context *gen = (genesis_context *)system;
1218 if (gen->reset_cycle == CYCLE_NEVER) {
1219 double random = (double)rand()/(double)RAND_MAX;
1220 gen->reset_cycle = gen->m68k->current_cycle + random * MCLKS_LINE * (gen->version_reg & HZ50 ? LINES_PAL : LINES_NTSC);
1221 if (gen->reset_cycle < gen->m68k->target_cycle) {
1222 gen->m68k->target_cycle = gen->reset_cycle;
1223 }
1224 }
1225}
1226
1227static void free_genesis(system_header *system)
1228{
1229 genesis_context *gen = (genesis_context *)system;
1230 vdp_free(gen->vdp);
1231 memmap_chunk *map = (memmap_chunk *)gen->m68k->options->gen.memmap;
1232 m68k_options_free(gen->m68k->options);
1233 free(gen->cart);
1234 free(gen->m68k);
1235 free(gen->work_ram);
1236 z80_options_free(gen->z80->Z80_OPTS);
1237 free(gen->z80);
1238 free(gen->zram);
1239 ym_free(gen->ym);
1240 psg_free(gen->psg);
1241 free(gen->header.save_dir);
1242 free_rom_info(&gen->header.info);
1243 free(gen->lock_on);
1244 free(gen);
1245}
1246
1247static void gamepad_down(system_header *system, uint8_t gamepad_num, uint8_t button)
1248{
1249 genesis_context *gen = (genesis_context *)system;
1250 io_gamepad_down(&gen->io, gamepad_num, button);
1251 if (gen->mapper_type == MAPPER_JCART) {
1252 jcart_gamepad_down(gen, gamepad_num, button);
1253 }
1254}
1255
1256static void gamepad_up(system_header *system, uint8_t gamepad_num, uint8_t button)
1257{
1258 genesis_context *gen = (genesis_context *)system;
1259 io_gamepad_up(&gen->io, gamepad_num, button);
1260 if (gen->mapper_type == MAPPER_JCART) {
1261 jcart_gamepad_up(gen, gamepad_num, button);
1262 }
1263}
1264
1265static void mouse_down(system_header *system, uint8_t mouse_num, uint8_t button)
1266{
1267 genesis_context *gen = (genesis_context *)system;
1268 io_mouse_down(&gen->io, mouse_num, button);
1269}
1270
1271static void mouse_up(system_header *system, uint8_t mouse_num, uint8_t button)
1272{
1273 genesis_context *gen = (genesis_context *)system;
1274 io_mouse_up(&gen->io, mouse_num, button);
1275}
1276
1277static void mouse_motion_absolute(system_header *system, uint8_t mouse_num, uint16_t x, uint16_t y)
1278{
1279 genesis_context *gen = (genesis_context *)system;
1280 io_mouse_motion_absolute(&gen->io, mouse_num, x, y);
1281}
1282
1283static void mouse_motion_relative(system_header *system, uint8_t mouse_num, int32_t x, int32_t y)
1284{
1285 genesis_context *gen = (genesis_context *)system;
1286 io_mouse_motion_relative(&gen->io, mouse_num, x, y);
1287}
1288
1289static void keyboard_down(system_header *system, uint8_t scancode)
1290{
1291 genesis_context *gen = (genesis_context *)system;
1292 io_keyboard_down(&gen->io, scancode);
1293}
1294
1295static void keyboard_up(system_header *system, uint8_t scancode)
1296{
1297 genesis_context *gen = (genesis_context *)system;
1298 io_keyboard_up(&gen->io, scancode);
1299}
1300
1301static void set_audio_config(genesis_context *gen)
1302{
1303 char *config_gain;
1304 config_gain = tern_find_path(config, "audio\0psg_gain\0", TVAL_PTR).ptrval;
1305 render_audio_source_gaindb(gen->psg->audio, config_gain ? atof(config_gain) : 0.0f);
1306 config_gain = tern_find_path(config, "audio\0fm_gain\0", TVAL_PTR).ptrval;
1307 render_audio_source_gaindb(gen->ym->audio, config_gain ? atof(config_gain) : 0.0f);
1308
1309 char *config_dac = tern_find_path_default(config, "audio\0fm_dac\0", (tern_val){.ptrval="zero_offset"}, TVAL_PTR).ptrval;
1310 ym_enable_zero_offset(gen->ym, !strcmp(config_dac, "zero_offset"));
1311}
1312
1313static void config_updated(system_header *system)
1314{
1315 genesis_context *gen = (genesis_context *)system;
1316 setup_io_devices(config, &system->info, &gen->io);
1317 set_audio_config(gen);
1318}
1319
1320genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region)
1321{
1322 static memmap_chunk z80_map[] = {
1323 { 0x0000, 0x4000, 0x1FFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, NULL, NULL, NULL, NULL },
1324 { 0x8000, 0x10000, 0x7FFF, 0, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank},
1325 { 0x4000, 0x6000, 0x0003, 0, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym},
1326 { 0x6000, 0x6100, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg},
1327 { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write}
1328 };
1329 genesis_context *gen = calloc(1, sizeof(genesis_context));
1330 gen->header.set_speed_percent = set_speed_percent;
1331 gen->header.start_context = start_genesis;
1332 gen->header.resume_context = resume_genesis;
1333 gen->header.load_save = load_save;
1334 gen->header.persist_save = persist_save;
1335 gen->header.load_state = load_state;
1336 gen->header.soft_reset = soft_reset;
1337 gen->header.free_context = free_genesis;
1338 gen->header.get_open_bus_value = get_open_bus_value;
1339 gen->header.request_exit = request_exit;
1340 gen->header.inc_debug_mode = inc_debug_mode;
1341 gen->header.gamepad_down = gamepad_down;
1342 gen->header.gamepad_up = gamepad_up;
1343 gen->header.mouse_down = mouse_down;
1344 gen->header.mouse_up = mouse_up;
1345 gen->header.mouse_motion_absolute = mouse_motion_absolute;
1346 gen->header.mouse_motion_relative = mouse_motion_relative;
1347 gen->header.keyboard_down = keyboard_down;
1348 gen->header.keyboard_up = keyboard_up;
1349 gen->header.config_updated = config_updated;
1350 gen->header.serialize = serialize;
1351 gen->header.deserialize = deserialize;
1352 gen->header.type = SYSTEM_GENESIS;
1353 gen->header.info = *rom;
1354 set_region(gen, rom, force_region);
1355
1356 gen->vdp = init_vdp_context(gen->version_reg & 0x40);
1357 gen->vdp->system = &gen->header;
1358 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp);
1359 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval;
1360 gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL;
1361 gen->int_latency_prev1 = MCLKS_PER_68K * 32;
1362 gen->int_latency_prev2 = MCLKS_PER_68K * 16;
1363
1364 render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC);
1365
1366 gen->ym = malloc(sizeof(ym2612_context));
1367 ym_init(gen->ym, gen->master_clock, MCLKS_PER_YM, system_opts);
1368
1369 gen->psg = malloc(sizeof(psg_context));
1370 psg_init(gen->psg, gen->master_clock, MCLKS_PER_PSG);
1371
1372 set_audio_config(gen);
1373
1374 z80_map[0].buffer = gen->zram = calloc(1, Z80_RAM_BYTES);
1375 z80_options *z_opts = malloc(sizeof(z80_options));
1376 init_z80_opts(z_opts, z80_map, 5, NULL, 0, MCLKS_PER_Z80, 0xFFFF);
1377 gen->z80 = init_z80_context(z_opts);
1378 gen->z80->next_int_pulse = z80_next_int_pulse;
1379 z80_assert_reset(gen->z80, 0);
1380
1381 gen->z80->system = gen;
1382 gen->z80->mem_pointers[0] = gen->zram;
1383 gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)main_rom;
1384
1385 gen->cart = main_rom;
1386 gen->lock_on = lock_on;
1387 gen->work_ram = calloc(2, RAM_WORDS);
1388 if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval))
1389 {
1390 srand(time(NULL));
1391 for (int i = 0; i < RAM_WORDS; i++)
1392 {
1393 gen->work_ram[i] = rand();
1394 }
1395 for (int i = 0; i < Z80_RAM_BYTES; i++)
1396 {
1397 gen->zram[i] = rand();
1398 }
1399 for (int i = 0; i < VRAM_SIZE; i++)
1400 {
1401 gen->vdp->vdpmem[i] = rand();
1402 }
1403 for (int i = 0; i < SAT_CACHE_SIZE; i++)
1404 {
1405 gen->vdp->sat_cache[i] = rand();
1406 }
1407 for (int i = 0; i < CRAM_SIZE; i++)
1408 {
1409 write_cram_internal(gen->vdp, i, rand());
1410 }
1411 for (int i = 0; i < VSRAM_SIZE; i++)
1412 {
1413 gen->vdp->vsram[i] = rand();
1414 }
1415 }
1416 setup_io_devices(config, rom, &gen->io);
1417 gen->header.has_keyboard = io_has_keyboard(&gen->io);
1418
1419 gen->mapper_type = rom->mapper_type;
1420 gen->save_type = rom->save_type;
1421 if (gen->save_type != SAVE_NONE) {
1422 gen->save_ram_mask = rom->save_mask;
1423 gen->save_size = rom->save_size;
1424 gen->save_storage = rom->save_buffer;
1425 gen->eeprom_map = rom->eeprom_map;
1426 gen->num_eeprom = rom->num_eeprom;
1427 if (gen->save_type == SAVE_I2C) {
1428 eeprom_init(&gen->eeprom, gen->save_storage, gen->save_size);
1429 } else if (gen->save_type == SAVE_NOR) {
1430 memcpy(&gen->nor, rom->nor, sizeof(gen->nor));
1431 //nor_flash_init(&gen->nor, gen->save_storage, gen->save_size, rom->save_page_size, rom->save_product_id, rom->save_bus);
1432 }
1433 } else {
1434 gen->save_storage = NULL;
1435 }
1436
1437 //This must happen before we generate memory access functions in init_m68k_opts
1438 for (int i = 0; i < rom->map_chunks; i++)
1439 {
1440 if (rom->map[i].start == 0xE00000) {
1441 rom->map[i].buffer = gen->work_ram;
1442 break;
1443 }
1444 }
1445
1446 m68k_options *opts = malloc(sizeof(m68k_options));
1447 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K);
1448 //TODO: make this configurable
1449 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY;
1450 gen->m68k = init_68k_context(opts, NULL);
1451 gen->m68k->system = gen;
1452 opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL;
1453
1454 //This must happen after the 68K context has been allocated
1455 for (int i = 0; i < rom->map_chunks; i++)
1456 {
1457 if (rom->map[i].flags & MMAP_PTR_IDX) {
1458 gen->m68k->mem_pointers[rom->map[i].ptr_index] = rom->map[i].buffer;
1459 }
1460 }
1461
1462 if (gen->mapper_type == MAPPER_SEGA) {
1463 //initialize bank registers
1464 for (int i = 1; i < sizeof(gen->bank_regs); i++)
1465 {
1466 gen->bank_regs[i] = i;
1467 }
1468 }
1469
1470 return gen;
1471}
1472
1473genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region)
1474{
1475 static memmap_chunk base_map[] = {
1476 {0xE00000, 0x1000000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL,
1477 NULL, NULL, NULL, NULL},
1478 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL,
1479 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write,
1480 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
1481 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL,
1482 (read_16_fun)io_read_w, (write_16_fun)io_write_w,
1483 (read_8_fun)io_read, (write_8_fun)io_write}
1484 };
1485 static tern_node *rom_db;
1486 if (!rom_db) {
1487 rom_db = load_rom_db();
1488 }
1489 rom_info info = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, sizeof(base_map)/sizeof(base_map[0]));
1490 rom = info.rom;
1491 rom_size = info.rom_size;
1492#ifndef BLASTEM_BIG_ENDIAN
1493 byteswap_rom(rom_size, rom);
1494 if (lock_on) {
1495 byteswap_rom(lock_on_size, lock_on);
1496 }
1497#endif
1498 char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0", TVAL_PTR).ptrval;
1499 if (!m68k_divider) {
1500 m68k_divider = "7";
1501 }
1502 MCLKS_PER_68K = atoi(m68k_divider);
1503 if (!MCLKS_PER_68K) {
1504 MCLKS_PER_68K = 7;
1505 }
1506 return alloc_init_genesis(&info, rom, lock_on, ym_opts, force_region);
1507}