comparison blastem.c @ 1103:22e87b739ad6

WIP split of ROM loading/argument parsing from Genesis emulation code. Compiles and doesn't crash, but nothing works. Still a few too many globals as well.
author Michael Pavone <pavone@retrodev.com>
date Fri, 09 Dec 2016 09:48:48 -0800
parents faa3a4617f62
children 2eb54e24914e
comparison
equal deleted inserted replaced
1102:c15896605bf2 1103:22e87b739ad6
12 #include "m68k_core.h" 12 #include "m68k_core.h"
13 #include "z80_to_x86.h" 13 #include "z80_to_x86.h"
14 #include "mem.h" 14 #include "mem.h"
15 #include "vdp.h" 15 #include "vdp.h"
16 #include "render.h" 16 #include "render.h"
17 #include "blastem.h" 17 #include "genesis.h"
18 #include "gdb_remote.h" 18 #include "gdb_remote.h"
19 #include "gst.h" 19 #include "gst.h"
20 #include "util.h" 20 #include "util.h"
21 #include "romdb.h" 21 #include "romdb.h"
22 #include "terminal.h" 22 #include "terminal.h"
23 #include "arena.h" 23 #include "arena.h"
24 #include "config.h"
24 25
25 #define BLASTEM_VERSION "0.4.1" 26 #define BLASTEM_VERSION "0.4.1"
26
27 #define MCLKS_NTSC 53693175
28 #define MCLKS_PAL 53203395
29
30 uint32_t MCLKS_PER_68K;
31 #define MCLKS_PER_YM 7
32 #define MCLKS_PER_Z80 15
33 #define MCLKS_PER_PSG (MCLKS_PER_Z80*16)
34 #define DEFAULT_SYNC_INTERVAL MCLKS_LINE
35 #define DEFAULT_LOWPASS_CUTOFF 3390
36
37 //TODO: Figure out the exact value for this
38 #define LINES_NTSC 262
39 #define LINES_PAL 312
40
41 #define MAX_SOUND_CYCLES 100000
42 27
43 #ifdef __ANDROID__ 28 #ifdef __ANDROID__
44 #define FULLSCREEN_DEFAULT 1 29 #define FULLSCREEN_DEFAULT 1
45 #else 30 #else
46 #define FULLSCREEN_DEFAULT 0 31 #define FULLSCREEN_DEFAULT 0
47 #endif 32 #endif
48 33
49 uint16_t *cart;
50 uint16_t *ram;
51 uint8_t z80_ram[Z80_RAM_BYTES];
52
53 int headless = 0; 34 int headless = 0;
54 int exit_after = 0; 35 int exit_after = 0;
55 int z80_enabled = 1; 36 int z80_enabled = 1;
56 int frame_limit = 0; 37 int frame_limit = 0;
57 38
65 #define SMD_MAGIC1 0x03 46 #define SMD_MAGIC1 0x03
66 #define SMD_MAGIC2 0xAA 47 #define SMD_MAGIC2 0xAA
67 #define SMD_MAGIC3 0xBB 48 #define SMD_MAGIC3 0xBB
68 #define SMD_BLOCK_SIZE 0x4000 49 #define SMD_BLOCK_SIZE 0x4000
69 50
70 int load_smd_rom(long filesize, FILE * f) 51 int load_smd_rom(long filesize, FILE * f, uint16_t **buffer)
71 { 52 {
72 uint8_t block[SMD_BLOCK_SIZE]; 53 uint8_t block[SMD_BLOCK_SIZE];
73 filesize -= SMD_HEADER_SIZE; 54 filesize -= SMD_HEADER_SIZE;
74 fseek(f, SMD_HEADER_SIZE, SEEK_SET); 55 fseek(f, SMD_HEADER_SIZE, SEEK_SET);
75 56
76 uint16_t * dst = cart = malloc(nearest_pow2(filesize)); 57 uint16_t *dst = *buffer = malloc(nearest_pow2(filesize));
77 int rom_size = filesize; 58 int rom_size = filesize;
78 while (filesize > 0) { 59 while (filesize > 0) {
79 fread(block, 1, SMD_BLOCK_SIZE, f); 60 fread(block, 1, SMD_BLOCK_SIZE, f);
80 for (uint8_t *low = block, *high = (block+SMD_BLOCK_SIZE/2), *end = block+SMD_BLOCK_SIZE; high < end; high++, low++) { 61 for (uint8_t *low = block, *high = (block+SMD_BLOCK_SIZE/2), *end = block+SMD_BLOCK_SIZE; high < end; high++, low++) {
81 *(dst++) = *low << 8 | *high; 62 *(dst++) = *low << 8 | *high;
83 filesize -= SMD_BLOCK_SIZE; 64 filesize -= SMD_BLOCK_SIZE;
84 } 65 }
85 return rom_size; 66 return rom_size;
86 } 67 }
87 68
88 void byteswap_rom(int filesize) 69 int load_rom(char * filename, uint16_t **dst)
89 {
90 for(unsigned short * cur = cart; cur - cart < filesize/2; ++cur)
91 {
92 *cur = (*cur >> 8) | (*cur << 8);
93 }
94 }
95
96 int load_rom(char * filename)
97 { 70 {
98 uint8_t header[10]; 71 uint8_t header[10];
99 FILE * f = fopen(filename, "rb"); 72 FILE * f = fopen(filename, "rb");
100 if (!f) { 73 if (!f) {
101 return 0; 74 return 0;
115 } 88 }
116 if (i == 8) { 89 if (i == 8) {
117 if (header[2]) { 90 if (header[2]) {
118 fatal_error("%s is a split SMD ROM which is not currently supported", filename); 91 fatal_error("%s is a split SMD ROM which is not currently supported", filename);
119 } 92 }
120 return load_smd_rom(filesize, f); 93 return load_smd_rom(filesize, f, dst);
121 } 94 }
122 } 95 }
123 cart = malloc(nearest_pow2(filesize)); 96 *dst = malloc(nearest_pow2(filesize));
124 if (filesize != fread(cart, 1, filesize, f)) { 97 if (filesize != fread(*dst, 1, filesize, f)) {
125 fatal_error("Error reading from %s\n", filename); 98 fatal_error("Error reading from %s\n", filename);
126 } 99 }
127 fclose(f); 100 fclose(f);
128 return filesize; 101 return filesize;
129 } 102 }
130 103
131 uint16_t read_dma_value(uint32_t address) 104
132 {
133 //addresses here are word addresses (i.e. bit 0 corresponds to A1), so no need to do multiply by 2
134 uint16_t *ptr = get_native_pointer(address*2, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen);
135 if (ptr) {
136 return *ptr;
137 }
138 //TODO: Figure out what happens when you try to DMA from weird adresses like IO or banked Z80 area
139 return 0;
140 }
141
142 uint16_t get_open_bus_value()
143 {
144 return read_dma_value(genesis->m68k->last_prefetch_address/2);
145 }
146
147 void adjust_int_cycle(m68k_context * context, vdp_context * v_context)
148 {
149 //static int old_int_cycle = CYCLE_NEVER;
150 genesis_context *gen = context->system;
151 if (context->sync_cycle - context->current_cycle > gen->max_cycles) {
152 context->sync_cycle = context->current_cycle + gen->max_cycles;
153 }
154 context->int_cycle = CYCLE_NEVER;
155 if ((context->status & 0x7) < 6) {
156 uint32_t next_vint = vdp_next_vint(v_context);
157 if (next_vint != CYCLE_NEVER) {
158 context->int_cycle = next_vint;
159 context->int_num = 6;
160 }
161 if ((context->status & 0x7) < 4) {
162 uint32_t next_hint = vdp_next_hint(v_context);
163 if (next_hint != CYCLE_NEVER) {
164 next_hint = next_hint < context->current_cycle ? context->current_cycle : next_hint;
165 if (next_hint < context->int_cycle) {
166 context->int_cycle = next_hint;
167 context->int_num = 4;
168
169 }
170 }
171 }
172 }
173 if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) {
174 context->int_pending = INT_PENDING_NONE;
175 }
176 /*if (context->int_cycle != old_int_cycle) {
177 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);
178 old_int_cycle = context->int_cycle;
179 }*/
180
181 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle;
182 if (context->should_return) {
183 context->target_cycle = context->current_cycle;
184 } else if (context->target_cycle < context->current_cycle) {
185 //Changes to SR can result in an interrupt cycle that's in the past
186 //This can cause issues with the implementation of STOP though
187 context->target_cycle = context->current_cycle;
188 }
189 /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n",
190 context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7),
191 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);*/
192 }
193 105
194 int break_on_sync = 0; 106 int break_on_sync = 0;
195 char *save_state_path; 107 char *save_state_path;
196 108
197 //#define DO_DEBUG_PRINT 109
198 #ifdef DO_DEBUG_PRINT 110
199 #define dprintf printf 111
200 #define dputs puts
201 #else
202 #define dprintf
203 #define dputs
204 #endif
205
206 #define Z80_VINT_DURATION 128
207
208 void z80_next_int_pulse(z80_context * z_context)
209 {
210 genesis_context * gen = z_context->system;
211 z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp);
212 z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION * MCLKS_PER_Z80;
213 }
214
215 void sync_z80(z80_context * z_context, uint32_t mclks)
216 {
217 #ifndef NO_Z80
218 if (z80_enabled) {
219 z80_run(z_context, mclks);
220 } else
221 #endif
222 {
223 z_context->current_cycle = mclks;
224 }
225 }
226
227 void sync_sound(genesis_context * gen, uint32_t target)
228 {
229 //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);
230 while (target > gen->psg->cycles && target - gen->psg->cycles > MAX_SOUND_CYCLES) {
231 uint32_t cur_target = gen->psg->cycles + MAX_SOUND_CYCLES;
232 //printf("Running PSG to cycle %d\n", cur_target);
233 psg_run(gen->psg, cur_target);
234 //printf("Running YM-2612 to cycle %d\n", cur_target);
235 ym_run(gen->ym, cur_target);
236 }
237 psg_run(gen->psg, target);
238 ym_run(gen->ym, target);
239
240 //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2);
241 }
242
243 uint32_t last_frame_num;
244
245 //My refresh emulation isn't currently good enough and causes more problems than it solves
246 #ifdef REFRESH_EMULATION
247 #define REFRESH_INTERVAL 128
248 #define REFRESH_DELAY 2
249 uint32_t last_sync_cycle;
250 uint32_t refresh_counter;
251 #endif
252
253 m68k_context * sync_components(m68k_context * context, uint32_t address)
254 {
255 genesis_context * gen = context->system;
256 vdp_context * v_context = gen->vdp;
257 z80_context * z_context = gen->z80;
258 #ifdef REFRESH_EMULATION
259 //lame estimation of refresh cycle delay
260 if (!gen->bus_busy) {
261 refresh_counter += context->current_cycle - last_sync_cycle;
262 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL));
263 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
264 }
265 #endif
266
267 uint32_t mclks = context->current_cycle;
268 sync_z80(z_context, mclks);
269 sync_sound(gen, mclks);
270 vdp_run_context(v_context, mclks);
271 if (v_context->frame != last_frame_num) {
272 //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);
273 last_frame_num = v_context->frame;
274
275 if(exit_after){
276 --exit_after;
277 if (!exit_after) {
278 exit(0);
279 }
280 }
281
282 vdp_adjust_cycles(v_context, mclks);
283 io_adjust_cycles(gen->ports, context->current_cycle, mclks);
284 io_adjust_cycles(gen->ports+1, context->current_cycle, mclks);
285 io_adjust_cycles(gen->ports+2, context->current_cycle, mclks);
286 context->current_cycle -= mclks;
287 z80_adjust_cycles(z_context, mclks);
288 gen->ym->current_cycle -= mclks;
289 gen->psg->cycles -= mclks;
290 if (gen->ym->write_cycle != CYCLE_NEVER) {
291 gen->ym->write_cycle = gen->ym->write_cycle >= mclks ? gen->ym->write_cycle - mclks : 0;
292 }
293 }
294 gen->frame_end = vdp_cycles_to_frame_end(v_context);
295 context->sync_cycle = gen->frame_end;
296 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot);
297 if (context->int_ack) {
298 //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);
299 vdp_int_ack(v_context);
300 context->int_ack = 0;
301 }
302 if (!address && (break_on_sync || gen->save_state)) {
303 context->sync_cycle = context->current_cycle + 1;
304 }
305 adjust_int_cycle(context, v_context);
306 if (address) {
307 if (break_on_sync) {
308 break_on_sync = 0;
309 debugger(context, address);
310 }
311 if (gen->save_state && (z_context->pc || (!z_context->reset && !z_context->busreq))) {
312 uint8_t slot = gen->save_state - 1;
313 gen->save_state = 0;
314 //advance Z80 core to the start of an instruction
315 while (!z_context->pc)
316 {
317 sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80);
318 }
319 char *save_path;
320 if (slot == QUICK_SAVE_SLOT) {
321 save_path = save_state_path;
322 } else {
323 char slotname[] = "slot_0.gst";
324 slotname[5] = '0' + slot;
325 char const *parts[] = {gen->save_dir, PATH_SEP, slotname};
326 save_path = alloc_concat_m(3, parts);
327 }
328 save_gst(gen, save_path, address);
329 printf("Saved state to %s\n", save_path);
330 if (slot != QUICK_SAVE_SLOT) {
331 free(save_path);
332 }
333 } else if(gen->save_state) {
334 context->sync_cycle = context->current_cycle + 1;
335 }
336 }
337 #ifdef REFRESH_EMULATION
338 last_sync_cycle = context->current_cycle;
339 #endif
340 return context;
341 }
342
343 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value)
344 {
345 if (vdp_port & 0x2700E0) {
346 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port);
347 }
348 vdp_port &= 0x1F;
349 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle);
350 sync_components(context, 0);
351 genesis_context * gen = context->system;
352 vdp_context *v_context = gen->vdp;
353 if (vdp_port < 0x10) {
354 int blocked;
355 uint32_t before_cycle = v_context->cycles;
356 if (vdp_port < 4) {
357
358 while (vdp_data_port_write(v_context, value) < 0) {
359 while(v_context->flags & FLAG_DMA_RUN) {
360 vdp_run_dma_done(v_context, gen->frame_end);
361 if (v_context->cycles >= gen->frame_end) {
362 uint32_t cycle_diff = v_context->cycles - context->current_cycle;
363 uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
364 if (m68k_cycle_diff < cycle_diff) {
365 m68k_cycle_diff += MCLKS_PER_68K;
366 }
367 context->current_cycle += m68k_cycle_diff;
368 gen->bus_busy = 1;
369 sync_components(context, 0);
370 gen->bus_busy = 0;
371 }
372 }
373 //context->current_cycle = v_context->cycles;
374 }
375 } else if(vdp_port < 8) {
376 blocked = vdp_control_port_write(v_context, value);
377 if (blocked) {
378 while (blocked) {
379 while(v_context->flags & FLAG_DMA_RUN) {
380 vdp_run_dma_done(v_context, gen->frame_end);
381 if (v_context->cycles >= gen->frame_end) {
382 uint32_t cycle_diff = v_context->cycles - context->current_cycle;
383 uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
384 if (m68k_cycle_diff < cycle_diff) {
385 m68k_cycle_diff += MCLKS_PER_68K;
386 }
387 context->current_cycle += m68k_cycle_diff;
388 gen->bus_busy = 1;
389 sync_components(context, 0);
390 gen->bus_busy = 0;
391 }
392 if (!(v_context->flags & FLAG_DMA_RUN)) {
393 //two more slots of delay are needed to kill sufficient sprite capacity in Overdrive
394 //TODO: Measure exact value with logic analyzer
395 vdp_run_context(v_context, v_context->cycles + 1);
396 vdp_run_context(v_context, v_context->cycles + 1);
397 }
398 }
399
400 if (blocked < 0) {
401 blocked = vdp_control_port_write(v_context, value);
402 } else {
403 blocked = 0;
404 }
405 }
406 } else {
407 context->sync_cycle = gen->frame_end = vdp_cycles_to_frame_end(v_context);
408 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot);
409 adjust_int_cycle(context, v_context);
410 }
411 } else {
412 fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
413 }
414 if (v_context->cycles != before_cycle) {
415 //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);
416 uint32_t cycle_diff = v_context->cycles - context->current_cycle;
417 uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
418 if (m68k_cycle_diff < cycle_diff) {
419 m68k_cycle_diff += MCLKS_PER_68K;
420 }
421 context->current_cycle += m68k_cycle_diff;
422 #ifdef REFRESH_EMULATION
423 last_sync_cycle = context->current_cycle;
424 #endif
425 //Lock the Z80 out of the bus until the VDP access is complete
426 gen->bus_busy = 1;
427 sync_z80(gen->z80, v_context->cycles);
428 gen->bus_busy = 0;
429 }
430 } else if (vdp_port < 0x18) {
431 psg_write(gen->psg, value);
432 } else {
433 //TODO: Implement undocumented test register(s)
434 }
435 return context;
436 }
437
438 m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8_t value)
439 {
440 return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : ((vdp_port & 1) ? value : 0));
441 }
442
443 void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value)
444 {
445 z80_context * context = vcontext;
446 genesis_context * gen = context->system;
447 vdp_port &= 0xFF;
448 if (vdp_port & 0xE0) {
449 fatal_error("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port);
450 }
451 if (vdp_port < 0x10) {
452 //These probably won't currently interact well with the 68K accessing the VDP
453 vdp_run_context(gen->vdp, context->current_cycle);
454 if (vdp_port < 4) {
455 vdp_data_port_write(gen->vdp, value << 8 | value);
456 } else if (vdp_port < 8) {
457 vdp_control_port_write(gen->vdp, value << 8 | value);
458 } else {
459 fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
460 }
461 } else if (vdp_port < 0x18) {
462 sync_sound(gen, context->current_cycle);
463 psg_write(gen->psg, value);
464 } else {
465 vdp_test_port_write(gen->vdp, value);
466 }
467 return context;
468 }
469
470 uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context)
471 {
472 if (vdp_port & 0x2700E0) {
473 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port);
474 }
475 vdp_port &= 0x1F;
476 uint16_t value;
477 sync_components(context, 0);
478 genesis_context *gen = context->system;
479 vdp_context * v_context = gen->vdp;
480 uint32_t before_cycle = v_context->cycles;
481 if (vdp_port < 0x10) {
482 if (vdp_port < 4) {
483 value = vdp_data_port_read(v_context);
484 } else if(vdp_port < 8) {
485 value = vdp_control_port_read(v_context);
486 } else {
487 value = vdp_hv_counter_read(v_context);
488 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles);
489 }
490 } else if (vdp_port < 0x18){
491 fatal_error("Illegal read from PSG port %X\n", vdp_port);
492 } else {
493 value = vdp_test_port_read(v_context);
494 }
495 if (v_context->cycles != before_cycle) {
496 //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);
497 context->current_cycle = v_context->cycles;
498 #ifdef REFRES_EMULATION
499 last_sync_cycle = context->current_cycle;
500 #endif
501 //Lock the Z80 out of the bus until the VDP access is complete
502 genesis_context *gen = context->system;
503 gen->bus_busy = 1;
504 sync_z80(gen->z80, v_context->cycles);
505 gen->bus_busy = 0;
506 }
507 return value;
508 }
509
510 uint8_t vdp_port_read_b(uint32_t vdp_port, m68k_context * context)
511 {
512 uint16_t value = vdp_port_read(vdp_port, context);
513 if (vdp_port & 1) {
514 return value;
515 } else {
516 return value >> 8;
517 }
518 }
519
520 uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext)
521 {
522 z80_context * context = vcontext;
523 if (vdp_port & 0xE0) {
524 fatal_error("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port);
525 }
526 genesis_context * gen = context->system;
527 //VDP access goes over the 68K bus like a bank area access
528 //typical delay from bus arbitration
529 context->current_cycle += 3 * MCLKS_PER_Z80;
530 //TODO: add cycle for an access right after a previous one
531 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
532 // Needs a new logic analyzer capture to get the actual delay on the 68K side
533 gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
534
535
536 vdp_port &= 0x1F;
537 uint16_t ret;
538 if (vdp_port < 0x10) {
539 //These probably won't currently interact well with the 68K accessing the VDP
540 vdp_run_context(gen->vdp, context->current_cycle);
541 if (vdp_port < 4) {
542 ret = vdp_data_port_read(gen->vdp);
543 } else if (vdp_port < 8) {
544 ret = vdp_control_port_read(gen->vdp);
545 } else {
546 fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
547 }
548 } else {
549 //TODO: Figure out the correct value today
550 ret = 0xFFFF;
551 }
552 return vdp_port & 1 ? ret : ret >> 8;
553 }
554
555 uint32_t zram_counter = 0;
556
557 m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value)
558 {
559 genesis_context * gen = context->system;
560 if (location < 0x10000) {
561 //Access to Z80 memory incurs a one 68K cycle wait state
562 context->current_cycle += MCLKS_PER_68K;
563 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) {
564 location &= 0x7FFF;
565 if (location < 0x4000) {
566 z80_ram[location & 0x1FFF] = value;
567 #ifndef NO_Z80
568 z80_handle_code_write(location & 0x1FFF, gen->z80);
569 #endif
570 } else if (location < 0x6000) {
571 sync_sound(gen, context->current_cycle);
572 if (location & 1) {
573 ym_data_write(gen->ym, value);
574 } else if(location & 2) {
575 ym_address_write_part2(gen->ym, value);
576 } else {
577 ym_address_write_part1(gen->ym, value);
578 }
579 } else if (location == 0x6000) {
580 gen->z80->bank_reg = (gen->z80->bank_reg >> 1 | value << 8) & 0x1FF;
581 if (gen->z80->bank_reg < 0x80) {
582 gen->z80->mem_pointers[1] = (gen->z80->bank_reg << 15) + ((char *)gen->z80->mem_pointers[2]);
583 } else {
584 gen->z80->mem_pointers[1] = NULL;
585 }
586 } else {
587 fatal_error("68K write to unhandled Z80 address %X\n", location);
588 }
589 }
590 } else {
591 location &= 0x1FFF;
592 if (location < 0x100) {
593 switch(location/2)
594 {
595 case 0x1:
596 io_data_write(gen->ports, value, context->current_cycle);
597 break;
598 case 0x2:
599 io_data_write(gen->ports+1, value, context->current_cycle);
600 break;
601 case 0x3:
602 io_data_write(gen->ports+2, value, context->current_cycle);
603 break;
604 case 0x4:
605 gen->ports[0].control = value;
606 break;
607 case 0x5:
608 gen->ports[1].control = value;
609 break;
610 case 0x6:
611 gen->ports[2].control = value;
612 break;
613 }
614 } else {
615 if (location == 0x1100) {
616 if (value & 1) {
617 dputs("bus requesting Z80");
618 if (z80_enabled) {
619 z80_assert_busreq(gen->z80, context->current_cycle);
620 } else {
621 gen->z80->busack = 1;
622 }
623 } else {
624 if (gen->z80->busreq) {
625 dputs("releasing z80 bus");
626 #ifdef DO_DEBUG_PRINT
627 char fname[20];
628 sprintf(fname, "zram-%d", zram_counter++);
629 FILE * f = fopen(fname, "wb");
630 fwrite(z80_ram, 1, sizeof(z80_ram), f);
631 fclose(f);
632 #endif
633 }
634 if (z80_enabled) {
635 z80_clear_busreq(gen->z80, context->current_cycle);
636 } else {
637 gen->z80->busack = 0;
638 }
639 }
640 } else if (location == 0x1200) {
641 sync_z80(gen->z80, context->current_cycle);
642 if (value & 1) {
643 if (z80_enabled) {
644 z80_clear_reset(gen->z80, context->current_cycle);
645 } else {
646 gen->z80->reset = 0;
647 }
648 } else {
649 if (z80_enabled) {
650 z80_assert_reset(gen->z80, context->current_cycle);
651 } else {
652 gen->z80->reset = 1;
653 }
654 }
655 }
656 }
657 }
658 return context;
659 }
660
661 m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value)
662 {
663 if (location < 0x10000 || (location & 0x1FFF) >= 0x100) {
664 return io_write(location, context, value >> 8);
665 } else {
666 return io_write(location, context, value);
667 }
668 }
669
670 #define USA 0x80
671 #define JAP 0x00
672 #define EUR 0xC0
673 #define NO_DISK 0x20
674 uint8_t version_reg = NO_DISK | USA;
675
676 uint8_t io_read(uint32_t location, m68k_context * context)
677 {
678 uint8_t value;
679 genesis_context *gen = context->system;
680 if (location < 0x10000) {
681 //Access to Z80 memory incurs a one 68K cycle wait state
682 context->current_cycle += MCLKS_PER_68K;
683 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) {
684 location &= 0x7FFF;
685 if (location < 0x4000) {
686 value = z80_ram[location & 0x1FFF];
687 } else if (location < 0x6000) {
688 sync_sound(gen, context->current_cycle);
689 value = ym_read_status(gen->ym);
690 } else {
691 value = 0xFF;
692 }
693 } else {
694 value = 0xFF;
695 }
696 } else {
697 location &= 0x1FFF;
698 if (location < 0x100) {
699 switch(location/2)
700 {
701 case 0x0:
702 //version bits should be 0 for now since we're not emulating TMSS
703 value = version_reg;
704 break;
705 case 0x1:
706 value = io_data_read(gen->ports, context->current_cycle);
707 break;
708 case 0x2:
709 value = io_data_read(gen->ports+1, context->current_cycle);
710 break;
711 case 0x3:
712 value = io_data_read(gen->ports+2, context->current_cycle);
713 break;
714 case 0x4:
715 value = gen->ports[0].control;
716 break;
717 case 0x5:
718 value = gen->ports[1].control;
719 break;
720 case 0x6:
721 value = gen->ports[2].control;
722 break;
723 default:
724 value = 0xFF;
725 }
726 } else {
727 if (location == 0x1100) {
728 value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : !gen->z80->busack;
729 value |= (get_open_bus_value() >> 8) & 0xFE;
730 dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset);
731 } else if (location == 0x1200) {
732 value = !gen->z80->reset;
733 } else {
734 value = 0xFF;
735 printf("Byte read of unknown IO location: %X\n", location);
736 }
737 }
738 }
739 return value;
740 }
741
742 uint16_t io_read_w(uint32_t location, m68k_context * context)
743 {
744 uint16_t value = io_read(location, context);
745 if (location < 0x10000 || (location & 0x1FFF) < 0x100) {
746 value = value | (value << 8);
747 } else {
748 value <<= 8;
749 value |= get_open_bus_value() & 0xFF;
750 }
751 return value;
752 }
753
754 void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value)
755 {
756 z80_context * context = vcontext;
757 genesis_context * gen = context->system;
758 sync_sound(gen, context->current_cycle);
759 if (location & 1) {
760 ym_data_write(gen->ym, value);
761 } else if (location & 2) {
762 ym_address_write_part2(gen->ym, value);
763 } else {
764 ym_address_write_part1(gen->ym, value);
765 }
766 return context;
767 }
768
769 uint8_t z80_read_ym(uint32_t location, void * vcontext)
770 {
771 z80_context * context = vcontext;
772 genesis_context * gen = context->system;
773 sync_sound(gen, context->current_cycle);
774 return ym_read_status(gen->ym);
775 }
776
777 uint8_t z80_read_bank(uint32_t location, void * vcontext)
778 {
779 z80_context * context = vcontext;
780 genesis_context *gen = context->system;
781 if (gen->bus_busy) {
782 context->current_cycle = context->sync_cycle;
783 }
784 //typical delay from bus arbitration
785 context->current_cycle += 3 * MCLKS_PER_Z80;
786 //TODO: add cycle for an access right after a previous one
787 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
788 // Needs a new logic analyzer capture to get the actual delay on the 68K side
789 gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
790
791 location &= 0x7FFF;
792 if (context->mem_pointers[1]) {
793 return context->mem_pointers[1][location ^ 1];
794 }
795 uint32_t address = context->bank_reg << 15 | location;
796 if (address >= 0xC00000 && address < 0xE00000) {
797 return z80_vdp_port_read(location & 0xFF, context);
798 } else {
799 fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, context->bank_reg << 15);
800 }
801 return 0;
802 }
803
804 void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value)
805 {
806 z80_context * context = vcontext;
807 genesis_context *gen = context->system;
808 if (gen->bus_busy) {
809 context->current_cycle = context->sync_cycle;
810 }
811 //typical delay from bus arbitration
812 context->current_cycle += 3 * MCLKS_PER_Z80;
813 //TODO: add cycle for an access right after a previous one
814 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
815 // Needs a new logic analyzer capture to get the actual delay on the 68K side
816 gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
817
818 location &= 0x7FFF;
819 uint32_t address = context->bank_reg << 15 | location;
820 if (address >= 0xE00000) {
821 address &= 0xFFFF;
822 ((uint8_t *)ram)[address ^ 1] = value;
823 } else if (address >= 0xC00000) {
824 z80_vdp_port_write(location & 0xFF, context, value);
825 } else {
826 fprintf(stderr, "Unhandled write by Z80 to address %X through banked memory area\n", address);
827 }
828 return context;
829 }
830
831 void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value)
832 {
833 z80_context * context = vcontext;
834
835 context->bank_reg = (context->bank_reg >> 1 | value << 8) & 0x1FF;
836 if (context->bank_reg < 0x100) {
837 genesis_context *gen = context->system;
838 context->mem_pointers[1] = get_native_pointer(context->bank_reg << 15, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen);
839 } else {
840 context->mem_pointers[1] = NULL;
841 }
842
843 return context;
844 }
845
846 void set_speed_percent(genesis_context * context, uint32_t percent)
847 {
848 uint32_t old_clock = context->master_clock;
849 context->master_clock = ((uint64_t)context->normal_clock * (uint64_t)percent) / 100;
850 while (context->ym->current_cycle != context->psg->cycles) {
851 sync_sound(context, context->psg->cycles + MCLKS_PER_PSG);
852 }
853 ym_adjust_master_clock(context->ym, context->master_clock);
854 psg_adjust_master_clock(context->psg, context->master_clock);
855 }
856 112
857 char * save_filename; 113 char * save_filename;
858 genesis_context *genesis; 114 genesis_context *genesis;
859 genesis_context *menu_context; 115 genesis_context *menu_context;
860 genesis_context *game_context; 116 genesis_context *game_context;
871 fwrite(game_context->save_storage, 1, game_context->save_size, f); 127 fwrite(game_context->save_storage, 1, game_context->save_size, f);
872 fclose(f); 128 fclose(f);
873 printf("Saved %s to %s\n", game_context->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); 129 printf("Saved %s to %s\n", game_context->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename);
874 } 130 }
875 131
876 #ifndef NO_Z80 132
877 const memmap_chunk z80_map[] = {
878 { 0x0000, 0x4000, 0x1FFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL },
879 { 0x8000, 0x10000, 0x7FFF, 0, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank},
880 { 0x4000, 0x6000, 0x0003, 0, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym},
881 { 0x6000, 0x6100, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg},
882 { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write}
883 };
884 #endif
885
886 genesis_context *alloc_init_genesis(rom_info *rom, int fps, uint32_t ym_opts)
887 {
888 genesis_context *gen = calloc(1, sizeof(genesis_context));
889 gen->master_clock = gen->normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL;
890
891 gen->vdp = malloc(sizeof(vdp_context));
892 init_vdp_context(gen->vdp, version_reg & 0x40);
893 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp);
894 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0").ptrval;
895 gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL;
896
897 char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0").ptrval;
898 uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : DEFAULT_LOWPASS_CUTOFF;
899
900 gen->ym = malloc(sizeof(ym2612_context));
901 ym_init(gen->ym, render_sample_rate(), gen->master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_opts, lowpass_cutoff);
902
903 gen->psg = malloc(sizeof(psg_context));
904 psg_init(gen->psg, render_sample_rate(), gen->master_clock, MCLKS_PER_PSG, render_audio_buffer(), lowpass_cutoff);
905
906 gen->z80 = calloc(1, sizeof(z80_context));
907 #ifndef NO_Z80
908 z80_options *z_opts = malloc(sizeof(z80_options));
909 init_z80_opts(z_opts, z80_map, 5, NULL, 0, MCLKS_PER_Z80);
910 init_z80_context(gen->z80, z_opts);
911 z80_assert_reset(gen->z80, 0);
912 #endif
913
914 gen->z80->system = gen;
915 gen->z80->mem_pointers[0] = z80_ram;
916 gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)cart;
917
918 gen->cart = cart;
919 gen->work_ram = ram;
920 gen->zram = z80_ram;
921 setup_io_devices(config, rom, gen);
922
923 gen->save_type = rom->save_type;
924 gen->save_type = rom->save_type;
925 if (gen->save_type != SAVE_NONE) {
926 gen->save_ram_mask = rom->save_mask;
927 gen->save_size = rom->save_size;
928 gen->save_storage = rom->save_buffer;
929 gen->eeprom_map = rom->eeprom_map;
930 gen->num_eeprom = rom->num_eeprom;
931 if (gen->save_type == SAVE_I2C) {
932 eeprom_init(&gen->eeprom, gen->save_storage, gen->save_size);
933 }
934 } else {
935 gen->save_storage = NULL;
936 }
937
938 m68k_options *opts = malloc(sizeof(m68k_options));
939 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K);
940 //TODO: make this configurable
941 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY;
942 gen->m68k = init_68k_context(opts, NULL);
943 gen->m68k->system = gen;
944
945 for (int i = 0; i < rom->map_chunks; i++)
946 {
947 if (rom->map[i].flags & MMAP_PTR_IDX) {
948 gen->m68k->mem_pointers[rom->map[i].ptr_index] = rom->map[i].buffer;
949 }
950 }
951
952 return gen;
953 }
954
955 void free_genesis(genesis_context *gen)
956 {
957 vdp_free(gen->vdp);
958 m68k_options_free(gen->m68k->options);
959 free(gen->m68k);
960 z80_options_free(gen->z80->options);
961 free(gen->z80);
962 ym_free(gen->ym);
963 psg_free(gen->psg);
964 free(gen->save_storage);
965 free(gen->save_dir);
966 free(gen->lock_on);
967 }
968
969 void start_genesis(genesis_context *gen, char *statefile, uint8_t *debugger)
970 {
971
972 if (statefile) {
973 uint32_t pc = load_gst(gen, statefile);
974 if (!pc) {
975 fatal_error("Failed to load save state %s\n", statefile);
976 }
977 printf("Loaded %s\n", statefile);
978 if (debugger) {
979 insert_breakpoint(gen->m68k, pc, debugger);
980 }
981 adjust_int_cycle(gen->m68k, gen->vdp);
982 start_68k_context(gen->m68k, pc);
983 } else {
984 if (debugger) {
985 uint32_t address = cart[2] << 16 | cart[3];
986 insert_breakpoint(gen->m68k, address, debugger);
987 }
988 m68k_reset(gen->m68k);
989 }
990 }
991 133
992 char *title; 134 char *title;
993
994 void update_title(char *rom_name) 135 void update_title(char *rom_name)
995 { 136 {
996 if (title) { 137 if (title) {
997 free(title); 138 free(title);
998 title = NULL; 139 title = NULL;
999 } 140 }
1000 title = alloc_concat(rom_name, " - BlastEm"); 141 title = alloc_concat(rom_name, " - BlastEm");
1001 render_update_caption(title); 142 render_update_caption(title);
1002 }
1003
1004 void set_region(rom_info *info, uint8_t region)
1005 {
1006 if (!region) {
1007 char * def_region = tern_find_ptr(config, "default_region");
1008 if (def_region && (!info->regions || (info->regions & translate_region_char(toupper(*def_region))))) {
1009 region = translate_region_char(toupper(*def_region));
1010 } else {
1011 region = info->regions;
1012 }
1013 }
1014 if (region & REGION_E) {
1015 version_reg = NO_DISK | EUR;
1016 } else if (region & REGION_J) {
1017 version_reg = NO_DISK | JAP;
1018 } else {
1019 version_reg = NO_DISK | USA;
1020 }
1021 } 143 }
1022 144
1023 void setup_saves(char *fname, rom_info *info, genesis_context *context) 145 void setup_saves(char *fname, rom_info *info, genesis_context *context)
1024 { 146 {
1025 char * barename = basename_no_extension(fname); 147 char * barename = basename_no_extension(fname);
1057 int width = -1; 179 int width = -1;
1058 int height = -1; 180 int height = -1;
1059 int debug = 0; 181 int debug = 0;
1060 int ym_log = 0; 182 int ym_log = 0;
1061 int loaded = 0; 183 int loaded = 0;
1062 uint8_t force_version = 0; 184 uint8_t force_region = 0;
1063 char * romfname = NULL; 185 char * romfname = NULL;
1064 FILE *address_log = NULL; 186 FILE *address_log = NULL;
1065 char * statefile = NULL; 187 char * statefile = NULL;
1066 int rom_size, lock_on_size; 188 int rom_size, lock_on_size;
1067 uint16_t *lock_on = NULL; 189 uint16_t *cart = NULL, *lock_on = NULL;
1068 uint8_t * debuggerfun = NULL; 190 uint8_t * debuggerfun = NULL;
1069 uint8_t fullscreen = FULLSCREEN_DEFAULT, use_gl = 1; 191 uint8_t fullscreen = FULLSCREEN_DEFAULT, use_gl = 1;
1070 uint8_t debug_target = 0; 192 uint8_t debug_target = 0;
1071 for (int i = 1; i < argc; i++) { 193 for (int i = 1; i < argc; i++) {
1072 if (argv[i][0] == '-') { 194 if (argv[i][0] == '-') {
1109 case 'r': 231 case 'r':
1110 i++; 232 i++;
1111 if (i >= argc) { 233 if (i >= argc) {
1112 fatal_error("-r must be followed by region (J, U or E)\n"); 234 fatal_error("-r must be followed by region (J, U or E)\n");
1113 } 235 }
1114 force_version = translate_region_char(toupper(argv[i][0])); 236 force_region = translate_region_char(toupper(argv[i][0]));
1115 if (!force_version) { 237 if (!force_region) {
1116 fatal_error("'%c' is not a valid region character for the -r option\n", argv[i][0]); 238 fatal_error("'%c' is not a valid region character for the -r option\n", argv[i][0]);
1117 } 239 }
1118 break; 240 break;
1119 case 's': 241 case 's':
1120 i++; 242 i++;
1132 case 'o': { 254 case 'o': {
1133 i++; 255 i++;
1134 if (i >= argc) { 256 if (i >= argc) {
1135 fatal_error("-o must be followed by a lock on cartridge filename\n"); 257 fatal_error("-o must be followed by a lock on cartridge filename\n");
1136 } 258 }
1137 uint16_t *tmp = cart; 259 lock_on_size = load_rom(argv[i], &lock_on);
1138 lock_on_size = load_rom(argv[i]); 260 if (!lock_on_size) {
1139 if (lock_on_size) {
1140 byteswap_rom(lock_on_size);
1141 lock_on = cart;
1142 } else {
1143 fatal_error("Failed to load lock on cartridge %s\n", argv[i]); 261 fatal_error("Failed to load lock on cartridge %s\n", argv[i]);
1144 } 262 }
1145 cart = tmp;
1146 break; 263 break;
1147 } 264 }
1148 case 'h': 265 case 'h':
1149 info_message( 266 info_message(
1150 "Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n" 267 "Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n"
1164 return 0; 281 return 0;
1165 default: 282 default:
1166 fatal_error("Unrecognized switch %s\n", argv[i]); 283 fatal_error("Unrecognized switch %s\n", argv[i]);
1167 } 284 }
1168 } else if (!loaded) { 285 } else if (!loaded) {
1169 if (!(rom_size = load_rom(argv[i]))) { 286 if (!(rom_size = load_rom(argv[i], &cart))) {
1170 fatal_error("Failed to open %s for reading\n", argv[i]); 287 fatal_error("Failed to open %s for reading\n", argv[i]);
1171 } 288 }
1172 romfname = argv[i]; 289 romfname = argv[i];
1173 loaded = 1; 290 loaded = 1;
1174 } else if (width < 0) { 291 } else if (width < 0) {
1183 romfname = tern_find_path(config, "ui\0rom\0").ptrval; 300 romfname = tern_find_path(config, "ui\0rom\0").ptrval;
1184 if (!romfname) { 301 if (!romfname) {
1185 romfname = "menu.bin"; 302 romfname = "menu.bin";
1186 } 303 }
1187 if (is_absolute_path(romfname)) { 304 if (is_absolute_path(romfname)) {
1188 if (!(rom_size = load_rom(romfname))) { 305 if (!(rom_size = load_rom(romfname, &cart))) {
1189 fatal_error("Failed to open UI ROM %s for reading", romfname); 306 fatal_error("Failed to open UI ROM %s for reading", romfname);
1190 } 307 }
1191 } else { 308 } else {
1192 long fsize; 309 long fsize;
1193 cart = (uint16_t *)read_bundled_file(romfname, &fsize); 310 cart = (uint16_t *)read_bundled_file(romfname, &fsize);
1197 rom_size = nearest_pow2(fsize); 314 rom_size = nearest_pow2(fsize);
1198 if (rom_size > fsize) { 315 if (rom_size > fsize) {
1199 cart = realloc(cart, rom_size); 316 cart = realloc(cart, rom_size);
1200 } 317 }
1201 } 318 }
1202 //TODO: load relative to executable or from assets depending on platform
1203 319
1204 loaded = 1; 320 loaded = 1;
1205 } 321 }
1206 char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0").ptrval; 322
1207 if (!m68k_divider) {
1208 m68k_divider = "7";
1209 }
1210 MCLKS_PER_68K = atoi(m68k_divider);
1211 if (!MCLKS_PER_68K) {
1212 MCLKS_PER_68K = 7;
1213 }
1214 ram = malloc(RAM_WORDS * sizeof(uint16_t));
1215 memmap_chunk base_map[] = {
1216 {0xE00000, 0x1000000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram,
1217 NULL, NULL, NULL, NULL},
1218 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL,
1219 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write,
1220 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
1221 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL,
1222 (read_16_fun)io_read_w, (write_16_fun)io_write_w,
1223 (read_8_fun)io_read, (write_8_fun)io_write}
1224 };
1225 tern_node *rom_db = load_rom_db();
1226 rom_info info = configure_rom(rom_db, cart, rom_size, lock_on, lock_on_size, base_map, sizeof(base_map)/sizeof(base_map[0]));
1227 byteswap_rom(rom_size);
1228 set_region(&info, force_version);
1229 update_title(info.name);
1230 int def_width = 0; 323 int def_width = 0;
1231 char *config_width = tern_find_path(config, "video\0width\0").ptrval; 324 char *config_width = tern_find_path(config, "video\0width\0").ptrval;
1232 if (config_width) { 325 if (config_width) {
1233 def_width = atoi(config_width); 326 def_width = atoi(config_width);
1234 } 327 }
1235 if (!def_width) { 328 if (!def_width) {
1236 def_width = 640; 329 def_width = 640;
1237 } 330 }
1238 width = width < 320 ? def_width : width; 331 width = width < 320 ? def_width : width;
1239 height = height < 240 ? (width/320) * 240 : height; 332 height = height < 240 ? (width/320) * 240 : height;
1240 uint32_t fps = 60; 333
1241 if (version_reg & 0x40) {
1242 fps = 50;
1243 }
1244 char *config_fullscreen = tern_find_path(config, "video\0fullscreen\0").ptrval; 334 char *config_fullscreen = tern_find_path(config, "video\0fullscreen\0").ptrval;
1245 if (config_fullscreen && !strcmp("on", config_fullscreen)) { 335 if (config_fullscreen && !strcmp("on", config_fullscreen)) {
1246 fullscreen = !fullscreen; 336 fullscreen = !fullscreen;
1247 } 337 }
1248 if (!headless) { 338 if (!headless) {
1249 render_init(width, height, title, fps, fullscreen); 339 render_init(width, height, "BlastEm", fullscreen);
1250 } 340 }
1251 341
1252 genesis = alloc_init_genesis(&info, fps, (ym_log && !menu) ? YM_OPT_WAVE_LOG : 0); 342 rom_info info;
1253 genesis->lock_on = lock_on; 343 uint32_t ym_opts = (ym_log && !menu) ? YM_OPT_WAVE_LOG : 0;
344 genesis = alloc_config_genesis(cart, rom_size, lock_on, lock_on_size, ym_opts, force_region, &info);
1254 setup_saves(romfname, &info, genesis); 345 setup_saves(romfname, &info, genesis);
346 update_title(info.name);
1255 if (menu) { 347 if (menu) {
1256 menu_context = genesis; 348 menu_context = genesis;
1257 } else { 349 } else {
1258 genesis->m68k->options->address_log = address_log; 350 genesis->m68k->options->address_log = address_log;
1259 game_context = genesis; 351 game_context = genesis;
1271 if (game_context->save_type != SAVE_NONE) { 363 if (game_context->save_type != SAVE_NONE) {
1272 genesis = game_context; 364 genesis = game_context;
1273 persist_save(); 365 persist_save();
1274 genesis = menu_context; 366 genesis = menu_context;
1275 } 367 }
1276 free(game_context->cart); 368 //swap to game context arena and mark all allocated pages in it free
1277 base_map[0].buffer = ram = game_context->work_ram;
1278 } else {
1279 base_map[0].buffer = ram = malloc(RAM_WORDS * sizeof(uint16_t));
1280 }
1281 memset(ram, 0, RAM_WORDS * sizeof(uint16_t));
1282 if (!(rom_size = load_rom(menu_context->next_rom))) {
1283 fatal_error("Failed to open %s for reading\n", menu_context->next_rom);
1284 }
1285 info = configure_rom(rom_db, cart, rom_size, NULL, 0, base_map, sizeof(base_map)/sizeof(base_map[0]));
1286 byteswap_rom(rom_size);
1287 set_region(&info, force_version);
1288 update_title(info.name);
1289 if (!game_context) {
1290 //start a new arena and save old one in suspended genesis context
1291 genesis->arena = start_new_arena();
1292 } else {
1293 genesis->arena = set_current_arena(game_context->arena); 369 genesis->arena = set_current_arena(game_context->arena);
1294 mark_all_free(); 370 mark_all_free();
1295 free_genesis(game_context); 371 free_genesis(game_context);
372 } else {
373 //start a new arena and save old one in suspended genesis context
374 genesis->arena = start_new_arena();
375 }
376 if (!(rom_size = load_rom(menu_context->next_rom, &cart))) {
377 fatal_error("Failed to open %s for reading\n", menu_context->next_rom);
1296 } 378 }
1297 //allocate new genesis context 379 //allocate new genesis context
1298 game_context = alloc_init_genesis(&info, fps, ym_log ? YM_OPT_WAVE_LOG : 0); 380 game_context = alloc_config_genesis(cart, rom_size, lock_on, lock_on_size, ym_opts,force_region, &info);
1299 menu_context->next_context = game_context; 381 menu_context->next_context = game_context;
1300 game_context->next_context = menu_context; 382 game_context->next_context = menu_context;
1301 setup_saves(menu_context->next_rom, &info, game_context); 383 setup_saves(menu_context->next_rom, &info, game_context);
384 update_title(info.name);
1302 free(menu_context->next_rom); 385 free(menu_context->next_rom);
1303 menu_context->next_rom = NULL; 386 menu_context->next_rom = NULL;
1304 menu = 0; 387 menu = 0;
1305 genesis = game_context; 388 genesis = game_context;
1306 genesis->m68k->options->address_log = address_log; 389 genesis->m68k->options->address_log = address_log;
1307 map_all_bindings(genesis->ports); 390 map_all_bindings(genesis->ports);
1308 start_genesis(genesis, statefile, menu == debug_target ? debuggerfun : NULL); 391 start_genesis(genesis, statefile, menu == debug_target ? debuggerfun : NULL);
1309 } else if (menu && game_context) { 392 } else if (menu && game_context) {
1310 genesis->arena = set_current_arena(game_context->arena); 393 genesis->arena = set_current_arena(game_context->arena);
1311 genesis = game_context; 394 genesis = game_context;
1312 cart = genesis->cart;
1313 ram = genesis->work_ram;
1314 menu = 0; 395 menu = 0;
1315 map_all_bindings(genesis->ports); 396 map_all_bindings(genesis->ports);
1316 resume_68k(genesis->m68k); 397 resume_68k(genesis->m68k);
1317 } else if (!menu && menu_context) { 398 } else if (!menu && menu_context) {
1318 genesis->arena = set_current_arena(menu_context->arena); 399 genesis->arena = set_current_arena(menu_context->arena);
1319 genesis = menu_context; 400 genesis = menu_context;
1320 cart = genesis->cart;
1321 ram = genesis->work_ram;
1322 menu = 1; 401 menu = 1;
1323 map_all_bindings(genesis->ports); 402 map_all_bindings(genesis->ports);
1324 resume_68k(genesis->m68k); 403 resume_68k(genesis->m68k);
1325 } else { 404 } else {
1326 break; 405 break;