comparison genesis.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
children 4224980a5f84
comparison
equal deleted inserted replaced
1102:c15896605bf2 1103:22e87b739ad6
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 <stdlib.h>
9 #include "render.h"
10 #include "gst.h"
11 #include "util.h"
12 #define MCLKS_NTSC 53693175
13 #define MCLKS_PAL 53203395
14
15 uint32_t MCLKS_PER_68K;
16 #define MCLKS_PER_YM 7
17 #define MCLKS_PER_Z80 15
18 #define MCLKS_PER_PSG (MCLKS_PER_Z80*16)
19 #define DEFAULT_SYNC_INTERVAL MCLKS_LINE
20 #define DEFAULT_LOWPASS_CUTOFF 3390
21
22 //TODO: Figure out the exact value for this
23 #define LINES_NTSC 262
24 #define LINES_PAL 312
25
26 #define MAX_SOUND_CYCLES 100000
27
28 uint16_t *cart;
29 uint16_t *ram;
30 uint8_t z80_ram[Z80_RAM_BYTES];
31
32 uint16_t read_dma_value(uint32_t address)
33 {
34 //addresses here are word addresses (i.e. bit 0 corresponds to A1), so no need to do multiply by 2
35 uint16_t *ptr = get_native_pointer(address*2, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen);
36 if (ptr) {
37 return *ptr;
38 }
39 //TODO: Figure out what happens when you try to DMA from weird adresses like IO or banked Z80 area
40 return 0;
41 }
42
43 uint16_t get_open_bus_value()
44 {
45 return read_dma_value(genesis->m68k->last_prefetch_address/2);
46 }
47
48 void adjust_int_cycle(m68k_context * context, vdp_context * v_context)
49 {
50 //static int old_int_cycle = CYCLE_NEVER;
51 genesis_context *gen = context->system;
52 if (context->sync_cycle - context->current_cycle > gen->max_cycles) {
53 context->sync_cycle = context->current_cycle + gen->max_cycles;
54 }
55 context->int_cycle = CYCLE_NEVER;
56 if ((context->status & 0x7) < 6) {
57 uint32_t next_vint = vdp_next_vint(v_context);
58 if (next_vint != CYCLE_NEVER) {
59 context->int_cycle = next_vint;
60 context->int_num = 6;
61 }
62 if ((context->status & 0x7) < 4) {
63 uint32_t next_hint = vdp_next_hint(v_context);
64 if (next_hint != CYCLE_NEVER) {
65 next_hint = next_hint < context->current_cycle ? context->current_cycle : next_hint;
66 if (next_hint < context->int_cycle) {
67 context->int_cycle = next_hint;
68 context->int_num = 4;
69
70 }
71 }
72 }
73 }
74 if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) {
75 context->int_pending = INT_PENDING_NONE;
76 }
77 /*if (context->int_cycle != old_int_cycle) {
78 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);
79 old_int_cycle = context->int_cycle;
80 }*/
81
82 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle;
83 if (context->should_return) {
84 context->target_cycle = context->current_cycle;
85 } else if (context->target_cycle < context->current_cycle) {
86 //Changes to SR can result in an interrupt cycle that's in the past
87 //This can cause issues with the implementation of STOP though
88 context->target_cycle = context->current_cycle;
89 }
90 /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n",
91 context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7),
92 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);*/
93 }
94
95 //#define DO_DEBUG_PRINT
96 #ifdef DO_DEBUG_PRINT
97 #define dprintf printf
98 #define dputs puts
99 #else
100 #define dprintf
101 #define dputs
102 #endif
103
104 #define Z80_VINT_DURATION 128
105
106 void z80_next_int_pulse(z80_context * z_context)
107 {
108 genesis_context * gen = z_context->system;
109 z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp);
110 z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION * MCLKS_PER_Z80;
111 }
112
113 void sync_z80(z80_context * z_context, uint32_t mclks)
114 {
115 #ifndef NO_Z80
116 if (z80_enabled) {
117 z80_run(z_context, mclks);
118 } else
119 #endif
120 {
121 z_context->current_cycle = mclks;
122 }
123 }
124
125 void sync_sound(genesis_context * gen, uint32_t target)
126 {
127 //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);
128 while (target > gen->psg->cycles && target - gen->psg->cycles > MAX_SOUND_CYCLES) {
129 uint32_t cur_target = gen->psg->cycles + MAX_SOUND_CYCLES;
130 //printf("Running PSG to cycle %d\n", cur_target);
131 psg_run(gen->psg, cur_target);
132 //printf("Running YM-2612 to cycle %d\n", cur_target);
133 ym_run(gen->ym, cur_target);
134 }
135 psg_run(gen->psg, target);
136 ym_run(gen->ym, target);
137
138 //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2);
139 }
140
141 uint32_t last_frame_num;
142
143 //My refresh emulation isn't currently good enough and causes more problems than it solves
144 #ifdef REFRESH_EMULATION
145 #define REFRESH_INTERVAL 128
146 #define REFRESH_DELAY 2
147 uint32_t last_sync_cycle;
148 uint32_t refresh_counter;
149 #endif
150
151 m68k_context * sync_components(m68k_context * context, uint32_t address)
152 {
153 genesis_context * gen = context->system;
154 vdp_context * v_context = gen->vdp;
155 z80_context * z_context = gen->z80;
156 #ifdef REFRESH_EMULATION
157 //lame estimation of refresh cycle delay
158 if (!gen->bus_busy) {
159 refresh_counter += context->current_cycle - last_sync_cycle;
160 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL));
161 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
162 }
163 #endif
164
165 uint32_t mclks = context->current_cycle;
166 sync_z80(z_context, mclks);
167 sync_sound(gen, mclks);
168 vdp_run_context(v_context, mclks);
169 if (v_context->frame != last_frame_num) {
170 //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);
171 last_frame_num = v_context->frame;
172
173 if(exit_after){
174 --exit_after;
175 if (!exit_after) {
176 exit(0);
177 }
178 }
179
180 vdp_adjust_cycles(v_context, mclks);
181 io_adjust_cycles(gen->ports, context->current_cycle, mclks);
182 io_adjust_cycles(gen->ports+1, context->current_cycle, mclks);
183 io_adjust_cycles(gen->ports+2, context->current_cycle, mclks);
184 context->current_cycle -= mclks;
185 z80_adjust_cycles(z_context, mclks);
186 gen->ym->current_cycle -= mclks;
187 gen->psg->cycles -= mclks;
188 if (gen->ym->write_cycle != CYCLE_NEVER) {
189 gen->ym->write_cycle = gen->ym->write_cycle >= mclks ? gen->ym->write_cycle - mclks : 0;
190 }
191 }
192 gen->frame_end = vdp_cycles_to_frame_end(v_context);
193 context->sync_cycle = gen->frame_end;
194 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot);
195 if (context->int_ack) {
196 //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);
197 vdp_int_ack(v_context);
198 context->int_ack = 0;
199 }
200 if (!address && (break_on_sync || gen->save_state)) {
201 context->sync_cycle = context->current_cycle + 1;
202 }
203 adjust_int_cycle(context, v_context);
204 if (address) {
205 if (break_on_sync) {
206 break_on_sync = 0;
207 debugger(context, address);
208 }
209 if (gen->save_state && (z_context->pc || (!z_context->reset && !z_context->busreq))) {
210 uint8_t slot = gen->save_state - 1;
211 gen->save_state = 0;
212 //advance Z80 core to the start of an instruction
213 while (!z_context->pc)
214 {
215 sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80);
216 }
217 char *save_path;
218 if (slot == QUICK_SAVE_SLOT) {
219 save_path = save_state_path;
220 } else {
221 char slotname[] = "slot_0.gst";
222 slotname[5] = '0' + slot;
223 char const *parts[] = {gen->save_dir, PATH_SEP, slotname};
224 save_path = alloc_concat_m(3, parts);
225 }
226 save_gst(gen, save_path, address);
227 printf("Saved state to %s\n", save_path);
228 if (slot != QUICK_SAVE_SLOT) {
229 free(save_path);
230 }
231 } else if(gen->save_state) {
232 context->sync_cycle = context->current_cycle + 1;
233 }
234 }
235 #ifdef REFRESH_EMULATION
236 last_sync_cycle = context->current_cycle;
237 #endif
238 return context;
239 }
240
241 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value)
242 {
243 if (vdp_port & 0x2700E0) {
244 fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port);
245 }
246 vdp_port &= 0x1F;
247 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle);
248 sync_components(context, 0);
249 genesis_context * gen = context->system;
250 vdp_context *v_context = gen->vdp;
251 if (vdp_port < 0x10) {
252 int blocked;
253 uint32_t before_cycle = v_context->cycles;
254 if (vdp_port < 4) {
255
256 while (vdp_data_port_write(v_context, value) < 0) {
257 while(v_context->flags & FLAG_DMA_RUN) {
258 vdp_run_dma_done(v_context, gen->frame_end);
259 if (v_context->cycles >= gen->frame_end) {
260 uint32_t cycle_diff = v_context->cycles - context->current_cycle;
261 uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
262 if (m68k_cycle_diff < cycle_diff) {
263 m68k_cycle_diff += MCLKS_PER_68K;
264 }
265 context->current_cycle += m68k_cycle_diff;
266 gen->bus_busy = 1;
267 sync_components(context, 0);
268 gen->bus_busy = 0;
269 }
270 }
271 //context->current_cycle = v_context->cycles;
272 }
273 } else if(vdp_port < 8) {
274 blocked = vdp_control_port_write(v_context, value);
275 if (blocked) {
276 while (blocked) {
277 while(v_context->flags & FLAG_DMA_RUN) {
278 vdp_run_dma_done(v_context, gen->frame_end);
279 if (v_context->cycles >= gen->frame_end) {
280 uint32_t cycle_diff = v_context->cycles - context->current_cycle;
281 uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
282 if (m68k_cycle_diff < cycle_diff) {
283 m68k_cycle_diff += MCLKS_PER_68K;
284 }
285 context->current_cycle += m68k_cycle_diff;
286 gen->bus_busy = 1;
287 sync_components(context, 0);
288 gen->bus_busy = 0;
289 }
290 if (!(v_context->flags & FLAG_DMA_RUN)) {
291 //two more slots of delay are needed to kill sufficient sprite capacity in Overdrive
292 //TODO: Measure exact value with logic analyzer
293 vdp_run_context(v_context, v_context->cycles + 1);
294 vdp_run_context(v_context, v_context->cycles + 1);
295 }
296 }
297
298 if (blocked < 0) {
299 blocked = vdp_control_port_write(v_context, value);
300 } else {
301 blocked = 0;
302 }
303 }
304 } else {
305 context->sync_cycle = gen->frame_end = vdp_cycles_to_frame_end(v_context);
306 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot);
307 adjust_int_cycle(context, v_context);
308 }
309 } else {
310 fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
311 }
312 if (v_context->cycles != before_cycle) {
313 //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);
314 uint32_t cycle_diff = v_context->cycles - context->current_cycle;
315 uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
316 if (m68k_cycle_diff < cycle_diff) {
317 m68k_cycle_diff += MCLKS_PER_68K;
318 }
319 context->current_cycle += m68k_cycle_diff;
320 #ifdef REFRESH_EMULATION
321 last_sync_cycle = context->current_cycle;
322 #endif
323 //Lock the Z80 out of the bus until the VDP access is complete
324 gen->bus_busy = 1;
325 sync_z80(gen->z80, v_context->cycles);
326 gen->bus_busy = 0;
327 }
328 } else if (vdp_port < 0x18) {
329 psg_write(gen->psg, value);
330 } else {
331 //TODO: Implement undocumented test register(s)
332 }
333 return context;
334 }
335
336 m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8_t value)
337 {
338 return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : ((vdp_port & 1) ? value : 0));
339 }
340
341 void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value)
342 {
343 z80_context * context = vcontext;
344 genesis_context * gen = context->system;
345 vdp_port &= 0xFF;
346 if (vdp_port & 0xE0) {
347 fatal_error("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port);
348 }
349 if (vdp_port < 0x10) {
350 //These probably won't currently interact well with the 68K accessing the VDP
351 vdp_run_context(gen->vdp, context->current_cycle);
352 if (vdp_port < 4) {
353 vdp_data_port_write(gen->vdp, value << 8 | value);
354 } else if (vdp_port < 8) {
355 vdp_control_port_write(gen->vdp, value << 8 | value);
356 } else {
357 fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
358 }
359 } else if (vdp_port < 0x18) {
360 sync_sound(gen, context->current_cycle);
361 psg_write(gen->psg, value);
362 } else {
363 vdp_test_port_write(gen->vdp, value);
364 }
365 return context;
366 }
367
368 uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context)
369 {
370 if (vdp_port & 0x2700E0) {
371 fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port);
372 }
373 vdp_port &= 0x1F;
374 uint16_t value;
375 sync_components(context, 0);
376 genesis_context *gen = context->system;
377 vdp_context * v_context = gen->vdp;
378 uint32_t before_cycle = v_context->cycles;
379 if (vdp_port < 0x10) {
380 if (vdp_port < 4) {
381 value = vdp_data_port_read(v_context);
382 } else if(vdp_port < 8) {
383 value = vdp_control_port_read(v_context);
384 } else {
385 value = vdp_hv_counter_read(v_context);
386 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles);
387 }
388 } else if (vdp_port < 0x18){
389 fatal_error("Illegal read from PSG port %X\n", vdp_port);
390 } else {
391 value = vdp_test_port_read(v_context);
392 }
393 if (v_context->cycles != before_cycle) {
394 //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);
395 context->current_cycle = v_context->cycles;
396 #ifdef REFRES_EMULATION
397 last_sync_cycle = context->current_cycle;
398 #endif
399 //Lock the Z80 out of the bus until the VDP access is complete
400 genesis_context *gen = context->system;
401 gen->bus_busy = 1;
402 sync_z80(gen->z80, v_context->cycles);
403 gen->bus_busy = 0;
404 }
405 return value;
406 }
407
408 uint8_t vdp_port_read_b(uint32_t vdp_port, m68k_context * context)
409 {
410 uint16_t value = vdp_port_read(vdp_port, context);
411 if (vdp_port & 1) {
412 return value;
413 } else {
414 return value >> 8;
415 }
416 }
417
418 uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext)
419 {
420 z80_context * context = vcontext;
421 if (vdp_port & 0xE0) {
422 fatal_error("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port);
423 }
424 genesis_context * gen = context->system;
425 //VDP access goes over the 68K bus like a bank area access
426 //typical delay from bus arbitration
427 context->current_cycle += 3 * MCLKS_PER_Z80;
428 //TODO: add cycle for an access right after a previous one
429 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
430 // Needs a new logic analyzer capture to get the actual delay on the 68K side
431 gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
432
433
434 vdp_port &= 0x1F;
435 uint16_t ret;
436 if (vdp_port < 0x10) {
437 //These probably won't currently interact well with the 68K accessing the VDP
438 vdp_run_context(gen->vdp, context->current_cycle);
439 if (vdp_port < 4) {
440 ret = vdp_data_port_read(gen->vdp);
441 } else if (vdp_port < 8) {
442 ret = vdp_control_port_read(gen->vdp);
443 } else {
444 fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
445 }
446 } else {
447 //TODO: Figure out the correct value today
448 ret = 0xFFFF;
449 }
450 return vdp_port & 1 ? ret : ret >> 8;
451 }
452
453 uint32_t zram_counter = 0;
454
455 m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value)
456 {
457 genesis_context * gen = context->system;
458 if (location < 0x10000) {
459 //Access to Z80 memory incurs a one 68K cycle wait state
460 context->current_cycle += MCLKS_PER_68K;
461 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) {
462 location &= 0x7FFF;
463 if (location < 0x4000) {
464 z80_ram[location & 0x1FFF] = value;
465 #ifndef NO_Z80
466 z80_handle_code_write(location & 0x1FFF, gen->z80);
467 #endif
468 } else if (location < 0x6000) {
469 sync_sound(gen, context->current_cycle);
470 if (location & 1) {
471 ym_data_write(gen->ym, value);
472 } else if(location & 2) {
473 ym_address_write_part2(gen->ym, value);
474 } else {
475 ym_address_write_part1(gen->ym, value);
476 }
477 } else if (location == 0x6000) {
478 gen->z80->bank_reg = (gen->z80->bank_reg >> 1 | value << 8) & 0x1FF;
479 if (gen->z80->bank_reg < 0x80) {
480 gen->z80->mem_pointers[1] = (gen->z80->bank_reg << 15) + ((char *)gen->z80->mem_pointers[2]);
481 } else {
482 gen->z80->mem_pointers[1] = NULL;
483 }
484 } else {
485 fatal_error("68K write to unhandled Z80 address %X\n", location);
486 }
487 }
488 } else {
489 location &= 0x1FFF;
490 if (location < 0x100) {
491 switch(location/2)
492 {
493 case 0x1:
494 io_data_write(gen->ports, value, context->current_cycle);
495 break;
496 case 0x2:
497 io_data_write(gen->ports+1, value, context->current_cycle);
498 break;
499 case 0x3:
500 io_data_write(gen->ports+2, value, context->current_cycle);
501 break;
502 case 0x4:
503 gen->ports[0].control = value;
504 break;
505 case 0x5:
506 gen->ports[1].control = value;
507 break;
508 case 0x6:
509 gen->ports[2].control = value;
510 break;
511 }
512 } else {
513 if (location == 0x1100) {
514 if (value & 1) {
515 dputs("bus requesting Z80");
516 if (z80_enabled) {
517 z80_assert_busreq(gen->z80, context->current_cycle);
518 } else {
519 gen->z80->busack = 1;
520 }
521 } else {
522 if (gen->z80->busreq) {
523 dputs("releasing z80 bus");
524 #ifdef DO_DEBUG_PRINT
525 char fname[20];
526 sprintf(fname, "zram-%d", zram_counter++);
527 FILE * f = fopen(fname, "wb");
528 fwrite(z80_ram, 1, sizeof(z80_ram), f);
529 fclose(f);
530 #endif
531 }
532 if (z80_enabled) {
533 z80_clear_busreq(gen->z80, context->current_cycle);
534 } else {
535 gen->z80->busack = 0;
536 }
537 }
538 } else if (location == 0x1200) {
539 sync_z80(gen->z80, context->current_cycle);
540 if (value & 1) {
541 if (z80_enabled) {
542 z80_clear_reset(gen->z80, context->current_cycle);
543 } else {
544 gen->z80->reset = 0;
545 }
546 } else {
547 if (z80_enabled) {
548 z80_assert_reset(gen->z80, context->current_cycle);
549 } else {
550 gen->z80->reset = 1;
551 }
552 }
553 }
554 }
555 }
556 return context;
557 }
558
559 m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value)
560 {
561 if (location < 0x10000 || (location & 0x1FFF) >= 0x100) {
562 return io_write(location, context, value >> 8);
563 } else {
564 return io_write(location, context, value);
565 }
566 }
567
568 #define FOREIGN 0x80
569 #define HZ50 0x40
570 #define USA FOREIGN
571 #define JAP 0x00
572 #define EUR (HZ50|FOREIGN)
573 #define NO_DISK 0x20
574
575 uint8_t io_read(uint32_t location, m68k_context * context)
576 {
577 uint8_t value;
578 genesis_context *gen = context->system;
579 if (location < 0x10000) {
580 //Access to Z80 memory incurs a one 68K cycle wait state
581 context->current_cycle += MCLKS_PER_68K;
582 if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) {
583 location &= 0x7FFF;
584 if (location < 0x4000) {
585 value = z80_ram[location & 0x1FFF];
586 } else if (location < 0x6000) {
587 sync_sound(gen, context->current_cycle);
588 value = ym_read_status(gen->ym);
589 } else {
590 value = 0xFF;
591 }
592 } else {
593 value = 0xFF;
594 }
595 } else {
596 location &= 0x1FFF;
597 if (location < 0x100) {
598 switch(location/2)
599 {
600 case 0x0:
601 //version bits should be 0 for now since we're not emulating TMSS
602 value = gen->version_reg;
603 break;
604 case 0x1:
605 value = io_data_read(gen->ports, context->current_cycle);
606 break;
607 case 0x2:
608 value = io_data_read(gen->ports+1, context->current_cycle);
609 break;
610 case 0x3:
611 value = io_data_read(gen->ports+2, context->current_cycle);
612 break;
613 case 0x4:
614 value = gen->ports[0].control;
615 break;
616 case 0x5:
617 value = gen->ports[1].control;
618 break;
619 case 0x6:
620 value = gen->ports[2].control;
621 break;
622 default:
623 value = 0xFF;
624 }
625 } else {
626 if (location == 0x1100) {
627 value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : !gen->z80->busack;
628 value |= (get_open_bus_value() >> 8) & 0xFE;
629 dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset);
630 } else if (location == 0x1200) {
631 value = !gen->z80->reset;
632 } else {
633 value = 0xFF;
634 printf("Byte read of unknown IO location: %X\n", location);
635 }
636 }
637 }
638 return value;
639 }
640
641 uint16_t io_read_w(uint32_t location, m68k_context * context)
642 {
643 uint16_t value = io_read(location, context);
644 if (location < 0x10000 || (location & 0x1FFF) < 0x100) {
645 value = value | (value << 8);
646 } else {
647 value <<= 8;
648 value |= get_open_bus_value() & 0xFF;
649 }
650 return value;
651 }
652
653 void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value)
654 {
655 z80_context * context = vcontext;
656 genesis_context * gen = context->system;
657 sync_sound(gen, context->current_cycle);
658 if (location & 1) {
659 ym_data_write(gen->ym, value);
660 } else if (location & 2) {
661 ym_address_write_part2(gen->ym, value);
662 } else {
663 ym_address_write_part1(gen->ym, value);
664 }
665 return context;
666 }
667
668 uint8_t z80_read_ym(uint32_t location, void * vcontext)
669 {
670 z80_context * context = vcontext;
671 genesis_context * gen = context->system;
672 sync_sound(gen, context->current_cycle);
673 return ym_read_status(gen->ym);
674 }
675
676 uint8_t z80_read_bank(uint32_t location, void * vcontext)
677 {
678 z80_context * context = vcontext;
679 genesis_context *gen = context->system;
680 if (gen->bus_busy) {
681 context->current_cycle = context->sync_cycle;
682 }
683 //typical delay from bus arbitration
684 context->current_cycle += 3 * MCLKS_PER_Z80;
685 //TODO: add cycle for an access right after a previous one
686 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
687 // Needs a new logic analyzer capture to get the actual delay on the 68K side
688 gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
689
690 location &= 0x7FFF;
691 if (context->mem_pointers[1]) {
692 return context->mem_pointers[1][location ^ 1];
693 }
694 uint32_t address = context->bank_reg << 15 | location;
695 if (address >= 0xC00000 && address < 0xE00000) {
696 return z80_vdp_port_read(location & 0xFF, context);
697 } else {
698 fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, context->bank_reg << 15);
699 }
700 return 0;
701 }
702
703 void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value)
704 {
705 z80_context * context = vcontext;
706 genesis_context *gen = context->system;
707 if (gen->bus_busy) {
708 context->current_cycle = context->sync_cycle;
709 }
710 //typical delay from bus arbitration
711 context->current_cycle += 3 * MCLKS_PER_Z80;
712 //TODO: add cycle for an access right after a previous one
713 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
714 // Needs a new logic analyzer capture to get the actual delay on the 68K side
715 gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
716
717 location &= 0x7FFF;
718 uint32_t address = context->bank_reg << 15 | location;
719 if (address >= 0xE00000) {
720 address &= 0xFFFF;
721 ((uint8_t *)ram)[address ^ 1] = value;
722 } else if (address >= 0xC00000) {
723 z80_vdp_port_write(location & 0xFF, context, value);
724 } else {
725 fprintf(stderr, "Unhandled write by Z80 to address %X through banked memory area\n", address);
726 }
727 return context;
728 }
729
730 void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value)
731 {
732 z80_context * context = vcontext;
733
734 context->bank_reg = (context->bank_reg >> 1 | value << 8) & 0x1FF;
735 if (context->bank_reg < 0x100) {
736 genesis_context *gen = context->system;
737 context->mem_pointers[1] = get_native_pointer(context->bank_reg << 15, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen);
738 } else {
739 context->mem_pointers[1] = NULL;
740 }
741
742 return context;
743 }
744
745 void set_speed_percent(genesis_context * context, uint32_t percent)
746 {
747 uint32_t old_clock = context->master_clock;
748 context->master_clock = ((uint64_t)context->normal_clock * (uint64_t)percent) / 100;
749 while (context->ym->current_cycle != context->psg->cycles) {
750 sync_sound(context, context->psg->cycles + MCLKS_PER_PSG);
751 }
752 ym_adjust_master_clock(context->ym, context->master_clock);
753 psg_adjust_master_clock(context->psg, context->master_clock);
754 }
755
756 void set_region(genesis_context *gen, rom_info *info, uint8_t region)
757 {
758 if (!region) {
759 char * def_region = tern_find_ptr(config, "default_region");
760 if (def_region && (!info->regions || (info->regions & translate_region_char(toupper(*def_region))))) {
761 region = translate_region_char(toupper(*def_region));
762 } else {
763 region = info->regions;
764 }
765 }
766 if (region & REGION_E) {
767 gen->version_reg = NO_DISK | EUR;
768 } else if (region & REGION_J) {
769 gen->version_reg = NO_DISK | JAP;
770 } else {
771 gen->version_reg = NO_DISK | USA;
772 }
773
774 if (region & HZ50) {
775 gen->normal_clock = MCLKS_PAL;
776 } else {
777 gen->normal_clock = MCLKS_NTSC;
778 }
779 gen->master_clock = gen->normal_clock;
780 }
781
782 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t ym_opts, uint8_t force_region)
783 {
784 static memmap_chunk z80_map[] = {
785 { 0x0000, 0x4000, 0x1FFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, NULL, NULL, NULL, NULL },
786 { 0x8000, 0x10000, 0x7FFF, 0, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank},
787 { 0x4000, 0x6000, 0x0003, 0, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym},
788 { 0x6000, 0x6100, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg},
789 { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write}
790 };
791 genesis_context *gen = calloc(1, sizeof(genesis_context));
792 set_region(gen, rom, force_region);
793
794 gen->vdp = malloc(sizeof(vdp_context));
795 init_vdp_context(gen->vdp, gen->version_reg & 0x40);
796 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp);
797 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0").ptrval;
798 gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL;
799
800 char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0").ptrval;
801 uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : DEFAULT_LOWPASS_CUTOFF;
802
803 gen->ym = malloc(sizeof(ym2612_context));
804 ym_init(gen->ym, render_sample_rate(), gen->master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_opts, lowpass_cutoff);
805
806 gen->psg = malloc(sizeof(psg_context));
807 psg_init(gen->psg, render_sample_rate(), gen->master_clock, MCLKS_PER_PSG, render_audio_buffer(), lowpass_cutoff);
808
809 gen->z80 = calloc(1, sizeof(z80_context));
810 z80_map[0].buffer = gen->zram = calloc(1, Z80_RAM_BYTES);
811 #ifndef NO_Z80
812 z80_options *z_opts = malloc(sizeof(z80_options));
813 init_z80_opts(z_opts, z80_map, 5, NULL, 0, MCLKS_PER_Z80);
814 init_z80_context(gen->z80, z_opts);
815 z80_assert_reset(gen->z80, 0);
816 #endif
817
818 gen->z80->system = gen;
819 gen->z80->mem_pointers[0] = gen->zram;
820 gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)cart;
821
822 gen->cart = main_rom;
823 gen->lock_on = lock_on;
824 gen->work_ram = calloc(2, RAM_WORDS);
825 gen->zram = z80_ram;
826 setup_io_devices(config, rom, gen);
827
828 gen->save_type = rom->save_type;
829 gen->save_type = rom->save_type;
830 if (gen->save_type != SAVE_NONE) {
831 gen->save_ram_mask = rom->save_mask;
832 gen->save_size = rom->save_size;
833 gen->save_storage = rom->save_buffer;
834 gen->eeprom_map = rom->eeprom_map;
835 gen->num_eeprom = rom->num_eeprom;
836 if (gen->save_type == SAVE_I2C) {
837 eeprom_init(&gen->eeprom, gen->save_storage, gen->save_size);
838 }
839 } else {
840 gen->save_storage = NULL;
841 }
842
843 for (int i = 0; i < rom->map_chunks; i++)
844 {
845 if (rom->map[i].flags & MMAP_PTR_IDX) {
846 gen->m68k->mem_pointers[rom->map[i].ptr_index] = rom->map[i].buffer;
847 }
848 if (rom->map[i].start == 0xE00000) {
849 rom->map[i].buffer = gen->work_ram;
850 }
851 }
852
853 m68k_options *opts = malloc(sizeof(m68k_options));
854 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K);
855 //TODO: make this configurable
856 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY;
857 gen->m68k = init_68k_context(opts, NULL);
858 gen->m68k->system = gen;
859
860 return gen;
861 }
862
863
864
865 void free_genesis(genesis_context *gen)
866 {
867 vdp_free(gen->vdp);
868 m68k_options_free(gen->m68k->options);
869 free(gen->m68k);
870 free(gen->work_ram);
871 z80_options_free(gen->z80->options);
872 free(gen->z80);
873 free(gen->zram);
874 ym_free(gen->ym);
875 psg_free(gen->psg);
876 free(gen->save_storage);
877 free(gen->save_dir);
878 free(gen->lock_on);
879 }
880
881 void start_genesis(genesis_context *gen, char *statefile, uint8_t *debugger)
882 {
883
884 if (statefile) {
885 uint32_t pc = load_gst(gen, statefile);
886 if (!pc) {
887 fatal_error("Failed to load save state %s\n", statefile);
888 }
889 printf("Loaded %s\n", statefile);
890 if (debugger) {
891 insert_breakpoint(gen->m68k, pc, debugger);
892 }
893 adjust_int_cycle(gen->m68k, gen->vdp);
894 start_68k_context(gen->m68k, pc);
895 } else {
896 if (debugger) {
897 uint32_t address = cart[2] << 16 | cart[3];
898 insert_breakpoint(gen->m68k, address, debugger);
899 }
900 m68k_reset(gen->m68k);
901 }
902 }
903
904 genesis_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, rom_info *info_out)
905 {
906 static memmap_chunk base_map[] = {
907 {0xE00000, 0x1000000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL,
908 NULL, NULL, NULL, NULL},
909 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL,
910 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write,
911 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
912 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL,
913 (read_16_fun)io_read_w, (write_16_fun)io_write_w,
914 (read_8_fun)io_read, (write_8_fun)io_write}
915 };
916 static tern_node *rom_db;
917 if (!rom_db) {
918 rom_db = load_rom_db();
919 }
920 *info_out = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, sizeof(base_map)/sizeof(base_map[0]));
921 #ifndef BIG_ENDIAN
922 byteswap_rom(rom, rom_size);
923 if (lock_on) {
924 byteswap_rom(lock_on, lock_on_size);
925 }
926 #endif
927 char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0").ptrval;
928 if (!m68k_divider) {
929 m68k_divider = "7";
930 }
931 MCLKS_PER_68K = atoi(m68k_divider);
932 if (!MCLKS_PER_68K) {
933 MCLKS_PER_68K = 7;
934 }
935 return alloc_init_genesis(info_out, rom, lock_on, ym_opts, force_region);
936 }