Mercurial > repos > blastem
comparison blastem.c @ 487:c08a4efeee7f opengl
Update opengl branch from default. Fix build breakage unrelated to merge
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 26 Oct 2013 22:38:47 -0700 |
parents | 7696d824489d 3e1573fa22cf |
children | 32f053ad9b02 |
comparison
equal
deleted
inserted
replaced
449:7696d824489d | 487:c08a4efeee7f |
---|---|
1 /* | |
2 Copyright 2013 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 */ | |
1 #include "68kinst.h" | 6 #include "68kinst.h" |
2 #include "m68k_to_x86.h" | 7 #include "m68k_to_x86.h" |
3 #include "z80_to_x86.h" | 8 #include "z80_to_x86.h" |
4 #include "mem.h" | 9 #include "mem.h" |
5 #include "vdp.h" | 10 #include "vdp.h" |
6 #include "render.h" | 11 #include "render.h" |
7 #include "blastem.h" | 12 #include "blastem.h" |
13 #include "gst.h" | |
8 #include <stdio.h> | 14 #include <stdio.h> |
9 #include <stdlib.h> | 15 #include <stdlib.h> |
10 #include <string.h> | 16 #include <string.h> |
17 | |
18 #define BLASTEM_VERSION "0.1.0" | |
11 | 19 |
12 #define CARTRIDGE_WORDS 0x200000 | 20 #define CARTRIDGE_WORDS 0x200000 |
13 #define RAM_WORDS 32 * 1024 | 21 #define RAM_WORDS 32 * 1024 |
14 #define Z80_RAM_BYTES 8 * 1024 | 22 #define Z80_RAM_BYTES 8 * 1024 |
15 | 23 |
23 | 31 |
24 //TODO: Figure out the exact value for this | 32 //TODO: Figure out the exact value for this |
25 #define LINES_NTSC 262 | 33 #define LINES_NTSC 262 |
26 #define LINES_PAL 312 | 34 #define LINES_PAL 312 |
27 | 35 |
36 #define MAX_SOUND_CYCLES 100000 | |
37 | |
28 uint32_t mclks_per_frame = MCLKS_LINE*LINES_NTSC; | 38 uint32_t mclks_per_frame = MCLKS_LINE*LINES_NTSC; |
29 | 39 |
30 uint16_t cart[CARTRIDGE_WORDS]; | 40 uint16_t cart[CARTRIDGE_WORDS]; |
31 uint16_t ram[RAM_WORDS]; | 41 uint16_t ram[RAM_WORDS]; |
32 uint8_t z80_ram[Z80_RAM_BYTES]; | 42 uint8_t z80_ram[Z80_RAM_BYTES]; |
33 | 43 |
34 int headless = 0; | 44 int headless = 0; |
35 int z80_enabled = 1; | 45 int z80_enabled = 1; |
36 int frame_limit = 0; | 46 int frame_limit = 0; |
47 | |
48 tern_node * config; | |
37 | 49 |
38 #ifndef MIN | 50 #ifndef MIN |
39 #define MIN(a,b) ((a) < (b) ? (a) : (b)) | 51 #define MIN(a,b) ((a) < (b) ? (a) : (b)) |
40 #endif | 52 #endif |
41 | 53 |
48 int load_smd_rom(long filesize, FILE * f) | 60 int load_smd_rom(long filesize, FILE * f) |
49 { | 61 { |
50 uint8_t block[SMD_BLOCK_SIZE]; | 62 uint8_t block[SMD_BLOCK_SIZE]; |
51 filesize -= SMD_HEADER_SIZE; | 63 filesize -= SMD_HEADER_SIZE; |
52 fseek(f, SMD_HEADER_SIZE, SEEK_SET); | 64 fseek(f, SMD_HEADER_SIZE, SEEK_SET); |
53 | 65 |
54 uint16_t * dst = cart; | 66 uint16_t * dst = cart; |
55 while (filesize > 0) { | 67 while (filesize > 0) { |
56 fread(block, 1, SMD_BLOCK_SIZE, f); | 68 fread(block, 1, SMD_BLOCK_SIZE, f); |
57 for (uint8_t *low = block, *high = (block+SMD_BLOCK_SIZE/2), *end = block+SMD_BLOCK_SIZE; high < end; high++, low++) { | 69 for (uint8_t *low = block, *high = (block+SMD_BLOCK_SIZE/2), *end = block+SMD_BLOCK_SIZE; high < end; high++, low++) { |
58 *(dst++) = *high << 8 | *low; | 70 *(dst++) = *high << 8 | *low; |
135 if (next_hint != CYCLE_NEVER) { | 147 if (next_hint != CYCLE_NEVER) { |
136 next_hint /= MCLKS_PER_68K; | 148 next_hint /= MCLKS_PER_68K; |
137 if (next_hint < context->int_cycle) { | 149 if (next_hint < context->int_cycle) { |
138 context->int_cycle = next_hint; | 150 context->int_cycle = next_hint; |
139 context->int_num = 4; | 151 context->int_num = 4; |
140 | 152 |
141 } | 153 } |
142 } | 154 } |
143 } | 155 } |
144 } | 156 } |
145 | 157 |
146 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; | 158 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; |
147 /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", | 159 /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", |
148 context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), | 160 context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7), |
149 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);*/ | 161 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);*/ |
150 } | 162 } |
151 | 163 |
152 int break_on_sync = 0; | 164 int break_on_sync = 0; |
165 int save_state = 0; | |
153 | 166 |
154 uint8_t reset = 1; | 167 uint8_t reset = 1; |
155 uint8_t need_reset = 0; | 168 uint8_t need_reset = 0; |
156 uint8_t busreq = 0; | 169 uint8_t busreq = 0; |
157 uint8_t busack = 0; | 170 uint8_t busack = 0; |
193 } | 206 } |
194 | 207 |
195 void sync_sound(genesis_context * gen, uint32_t target) | 208 void sync_sound(genesis_context * gen, uint32_t target) |
196 { | 209 { |
197 //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); | 210 //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); |
211 while (target > gen->psg->cycles && target - gen->psg->cycles > MAX_SOUND_CYCLES) { | |
212 uint32_t cur_target = gen->psg->cycles + MAX_SOUND_CYCLES; | |
213 //printf("Running PSG to cycle %d\n", cur_target); | |
214 psg_run(gen->psg, cur_target); | |
215 //printf("Running YM-2612 to cycle %d\n", cur_target); | |
216 ym_run(gen->ym, cur_target); | |
217 } | |
198 psg_run(gen->psg, target); | 218 psg_run(gen->psg, target); |
199 ym_run(gen->ym, target); | 219 ym_run(gen->ym, target); |
200 | 220 |
201 //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2); | 221 //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2); |
202 } | 222 } |
203 | 223 |
204 uint32_t frame=0; | 224 uint32_t frame=0; |
205 m68k_context * sync_components(m68k_context * context, uint32_t address) | 225 m68k_context * sync_components(m68k_context * context, uint32_t address) |
217 if (gen->ym->write_cycle != CYCLE_NEVER) { | 237 if (gen->ym->write_cycle != CYCLE_NEVER) { |
218 gen->ym->write_cycle = gen->ym->write_cycle >= mclks_per_frame/MCLKS_PER_68K ? gen->ym->write_cycle - mclks_per_frame/MCLKS_PER_68K : 0; | 238 gen->ym->write_cycle = gen->ym->write_cycle >= mclks_per_frame/MCLKS_PER_68K ? gen->ym->write_cycle - mclks_per_frame/MCLKS_PER_68K : 0; |
219 } | 239 } |
220 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); | 240 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); |
221 vdp_run_context(v_context, mclks_per_frame); | 241 vdp_run_context(v_context, mclks_per_frame); |
222 | 242 |
223 if (!headless) { | 243 if (!headless) { |
224 break_on_sync |= wait_render_frame(v_context, frame_limit); | 244 break_on_sync |= wait_render_frame(v_context, frame_limit); |
225 } | 245 } |
226 frame++; | 246 frame++; |
227 mclks -= mclks_per_frame; | 247 mclks -= mclks_per_frame; |
254 if (context->int_ack) { | 274 if (context->int_ack) { |
255 vdp_int_ack(v_context, context->int_ack); | 275 vdp_int_ack(v_context, context->int_ack); |
256 context->int_ack = 0; | 276 context->int_ack = 0; |
257 } | 277 } |
258 adjust_int_cycle(context, v_context); | 278 adjust_int_cycle(context, v_context); |
259 if (break_on_sync && address) { | 279 if (address) { |
280 if (break_on_sync) { | |
260 break_on_sync = 0; | 281 break_on_sync = 0; |
261 debugger(context, address); | 282 debugger(context, address); |
283 } | |
284 if (save_state) { | |
285 save_state = 0; | |
286 while (!z_context->pc) | |
287 { | |
288 sync_z80(z_context, z_context->current_cycle * MCLKS_PER_Z80 + MCLKS_PER_Z80); | |
289 } | |
290 save_gst(gen, "savestate.gst", address); | |
291 } | |
262 } | 292 } |
263 return context; | 293 return context; |
264 } | 294 } |
265 | 295 |
266 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) | 296 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) |
280 while (vdp_data_port_write(v_context, value) < 0) { | 310 while (vdp_data_port_write(v_context, value) < 0) { |
281 while(v_context->flags & FLAG_DMA_RUN) { | 311 while(v_context->flags & FLAG_DMA_RUN) { |
282 vdp_run_dma_done(v_context, mclks_per_frame); | 312 vdp_run_dma_done(v_context, mclks_per_frame); |
283 if (v_context->cycles >= mclks_per_frame) { | 313 if (v_context->cycles >= mclks_per_frame) { |
284 if (!headless) { | 314 if (!headless) { |
315 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, v_context->cycles); | |
285 wait_render_frame(v_context, frame_limit); | 316 wait_render_frame(v_context, frame_limit); |
286 } | 317 } |
287 vdp_adjust_cycles(v_context, mclks_per_frame); | 318 vdp_adjust_cycles(v_context, mclks_per_frame); |
288 genesis_context * gen = context->system; | 319 genesis_context * gen = context->system; |
289 io_adjust_cycles(gen->ports, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K); | 320 io_adjust_cycles(gen->ports, v_context->cycles/MCLKS_PER_68K, mclks_per_frame/MCLKS_PER_68K); |
297 busack = new_busack; | 328 busack = new_busack; |
298 } | 329 } |
299 } | 330 } |
300 } | 331 } |
301 } | 332 } |
302 context->current_cycle = v_context->cycles / MCLKS_PER_68K; | 333 //context->current_cycle = v_context->cycles / MCLKS_PER_68K; |
303 } | 334 } |
304 } else if(vdp_port < 8) { | 335 } else if(vdp_port < 8) { |
305 blocked = vdp_control_port_write(v_context, value); | 336 blocked = vdp_control_port_write(v_context, value); |
306 if (blocked) { | 337 if (blocked) { |
307 while (blocked) { | 338 while (blocked) { |
330 blocked = vdp_control_port_write(v_context, value); | 361 blocked = vdp_control_port_write(v_context, value); |
331 } else { | 362 } else { |
332 blocked = 0; | 363 blocked = 0; |
333 } | 364 } |
334 } | 365 } |
335 context->current_cycle = v_context->cycles / MCLKS_PER_68K; | |
336 } else { | 366 } else { |
337 adjust_int_cycle(context, v_context); | 367 adjust_int_cycle(context, v_context); |
338 } | 368 } |
339 } else { | 369 } else { |
340 printf("Illegal write to HV Counter port %X\n", vdp_port); | 370 printf("Illegal write to HV Counter port %X\n", vdp_port); |
341 exit(1); | 371 exit(1); |
342 } | 372 } |
343 if (v_context->cycles != before_cycle) { | 373 if (v_context->cycles != before_cycle) { |
374 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for write\n", v_context->cycles / MCLKS_PER_68K - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); | |
344 context->current_cycle = v_context->cycles / MCLKS_PER_68K; | 375 context->current_cycle = v_context->cycles / MCLKS_PER_68K; |
345 } | 376 } |
346 } else if (vdp_port < 0x18) { | 377 } else if (vdp_port < 0x18) { |
347 genesis_context * gen = context->system; | 378 genesis_context * gen = context->system; |
348 sync_sound(gen, context->current_cycle * MCLKS_PER_68K); | 379 sync_sound(gen, context->current_cycle * MCLKS_PER_68K); |
378 } | 409 } |
379 } else if (vdp_port < 0x18) { | 410 } else if (vdp_port < 0x18) { |
380 sync_sound(gen, context->current_cycle * MCLKS_PER_Z80); | 411 sync_sound(gen, context->current_cycle * MCLKS_PER_Z80); |
381 psg_write(gen->psg, value); | 412 psg_write(gen->psg, value); |
382 } else { | 413 } else { |
383 //TODO: Implement undocumented test register(s) | 414 vdp_test_port_write(gen->vdp, value); |
384 } | 415 } |
385 return context; | 416 return context; |
386 } | 417 } |
387 | 418 |
388 uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) | 419 uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) |
393 } | 424 } |
394 vdp_port &= 0x1F; | 425 vdp_port &= 0x1F; |
395 uint16_t value; | 426 uint16_t value; |
396 sync_components(context, 0); | 427 sync_components(context, 0); |
397 vdp_context * v_context = context->video_context; | 428 vdp_context * v_context = context->video_context; |
429 uint32_t before_cycle = v_context->cycles; | |
398 if (vdp_port < 0x10) { | 430 if (vdp_port < 0x10) { |
399 if (vdp_port < 4) { | 431 if (vdp_port < 4) { |
400 value = vdp_data_port_read(v_context); | 432 value = vdp_data_port_read(v_context); |
401 } else if(vdp_port < 8) { | 433 } else if(vdp_port < 8) { |
402 value = vdp_control_port_read(v_context); | 434 value = vdp_control_port_read(v_context); |
403 } else { | 435 } else { |
404 value = vdp_hv_counter_read(v_context); | 436 value = vdp_hv_counter_read(v_context); |
405 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); | 437 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); |
406 } | 438 } |
407 context->current_cycle = v_context->cycles/MCLKS_PER_68K; | 439 } else if (vdp_port < 0x18){ |
440 printf("Illegal read from PSG port %X\n", vdp_port); | |
441 exit(1); | |
408 } else { | 442 } else { |
409 printf("Illegal read from PSG or test register port %X\n", vdp_port); | 443 value = vdp_test_port_read(v_context); |
410 exit(1); | 444 } |
445 if (v_context->cycles != before_cycle) { | |
446 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles / MCLKS_PER_68K - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); | |
447 context->current_cycle = v_context->cycles / MCLKS_PER_68K; | |
411 } | 448 } |
412 return value; | 449 return value; |
413 } | 450 } |
414 | 451 |
415 uint8_t vdp_port_read_b(uint32_t vdp_port, m68k_context * context) | 452 uint8_t vdp_port_read_b(uint32_t vdp_port, m68k_context * context) |
487 gen->ports[2].control = value; | 524 gen->ports[2].control = value; |
488 break; | 525 break; |
489 } | 526 } |
490 } else { | 527 } else { |
491 if (location == 0x1100) { | 528 if (location == 0x1100) { |
492 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); | |
493 if (busack_cycle <= context->current_cycle) { | 529 if (busack_cycle <= context->current_cycle) { |
494 busack = new_busack; | 530 busack = new_busack; |
495 busack_cycle = CYCLE_NEVER; | 531 busack_cycle = CYCLE_NEVER; |
496 } | 532 } |
497 if (value & 1) { | 533 if (value & 1) { |
498 dputs("bus requesting Z80"); | 534 dputs("bus requesting Z80"); |
499 | 535 |
500 if(!reset && !busreq) { | 536 if(!reset && !busreq) { |
501 busack_cycle = ((gen->z80->current_cycle + Z80_ACK_DELAY) * MCLKS_PER_Z80) / MCLKS_PER_68K;//context->current_cycle + Z80_ACK_DELAY; | 537 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K + Z80_ACK_DELAY*MCLKS_PER_Z80); |
538 busack_cycle = (gen->z80->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_68K;//context->current_cycle + Z80_ACK_DELAY; | |
502 new_busack = Z80_REQ_ACK; | 539 new_busack = Z80_REQ_ACK; |
503 } | 540 } |
504 busreq = 1; | 541 busreq = 1; |
505 } else { | 542 } else { |
543 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); | |
506 if (busreq) { | 544 if (busreq) { |
507 dputs("releasing z80 bus"); | 545 dputs("releasing z80 bus"); |
508 #ifdef DO_DEBUG_PRINT | 546 #ifdef DO_DEBUG_PRINT |
509 char fname[20]; | 547 char fname[20]; |
510 sprintf(fname, "zram-%d", zram_counter++); | 548 sprintf(fname, "zram-%d", zram_counter++); |
516 new_busack = Z80_REQ_BUSY; | 554 new_busack = Z80_REQ_BUSY; |
517 busreq = 0; | 555 busreq = 0; |
518 } | 556 } |
519 //busack_cycle = CYCLE_NEVER; | 557 //busack_cycle = CYCLE_NEVER; |
520 //busack = Z80_REQ_BUSY; | 558 //busack = Z80_REQ_BUSY; |
521 | 559 |
522 } | 560 } |
523 } else if (location == 0x1200) { | 561 } else if (location == 0x1200) { |
524 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); | 562 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); |
525 if (value & 1) { | 563 if (value & 1) { |
526 if (reset && busreq) { | 564 if (reset && busreq) { |
1431 case 'z': { | 1469 case 'z': { |
1432 genesis_context * gen = context->system; | 1470 genesis_context * gen = context->system; |
1433 //Z80 debug commands | 1471 //Z80 debug commands |
1434 switch(input_buf[1]) | 1472 switch(input_buf[1]) |
1435 { | 1473 { |
1436 case 'b': | 1474 case 'b': |
1437 param = find_param(input_buf); | 1475 param = find_param(input_buf); |
1438 if (!param) { | 1476 if (!param) { |
1439 fputs("zb command requires a parameter\n", stderr); | 1477 fputs("zb command requires a parameter\n", stderr); |
1440 break; | 1478 break; |
1441 } | 1479 } |
1461 } | 1499 } |
1462 } | 1500 } |
1463 return context; | 1501 return context; |
1464 } | 1502 } |
1465 | 1503 |
1466 #define GST_68K_REGS 0x80 | 1504 void set_speed_percent(genesis_context * context, uint32_t percent) |
1467 #define GST_68K_REG_SIZE (0xDA-GST_68K_REGS) | 1505 { |
1468 #define GST_68K_PC_OFFSET (0xC8-GST_68K_REGS) | 1506 uint32_t old_clock = context->master_clock; |
1469 #define GST_68K_SR_OFFSET (0xD0-GST_68K_REGS) | 1507 context->master_clock = ((uint64_t)context->normal_clock * (uint64_t)percent) / 100; |
1470 #define GST_68K_USP_OFFSET (0xD2-GST_68K_REGS) | 1508 while (context->ym->current_cycle != context->psg->cycles) { |
1471 #define GST_68K_SSP_OFFSET (0xD6-GST_68K_REGS) | 1509 sync_sound(context, context->psg->cycles + MCLKS_PER_PSG); |
1472 #define GST_68K_RAM 0x2478 | 1510 } |
1473 #define GST_Z80_REGS 0x404 | 1511 ym_adjust_master_clock(context->ym, context->master_clock); |
1474 #define GST_Z80_REG_SIZE (0x440-GST_Z80_REGS) | 1512 psg_adjust_master_clock(context->psg, context->master_clock); |
1475 #define GST_Z80_RAM 0x474 | |
1476 | |
1477 uint32_t read_le_32(uint8_t * data) | |
1478 { | |
1479 return data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0]; | |
1480 } | |
1481 | |
1482 uint16_t read_le_16(uint8_t * data) | |
1483 { | |
1484 return data[1] << 8 | data[0]; | |
1485 } | |
1486 | |
1487 uint16_t read_be_16(uint8_t * data) | |
1488 { | |
1489 return data[0] << 8 | data[1]; | |
1490 } | |
1491 | |
1492 uint32_t m68k_load_gst(m68k_context * context, FILE * gstfile) | |
1493 { | |
1494 uint8_t buffer[4096]; | |
1495 fseek(gstfile, GST_68K_REGS, SEEK_SET); | |
1496 if (fread(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) { | |
1497 fputs("Failed to read 68K registers from savestate\n", stderr); | |
1498 return 0; | |
1499 } | |
1500 uint8_t * curpos = buffer; | |
1501 for (int i = 0; i < 8; i++) { | |
1502 context->dregs[i] = read_le_32(curpos); | |
1503 curpos += sizeof(uint32_t); | |
1504 } | |
1505 for (int i = 0; i < 8; i++) { | |
1506 context->aregs[i] = read_le_32(curpos); | |
1507 curpos += sizeof(uint32_t); | |
1508 } | |
1509 uint32_t pc = read_le_32(buffer + GST_68K_PC_OFFSET); | |
1510 uint16_t sr = read_le_16(buffer + GST_68K_SR_OFFSET); | |
1511 context->status = sr >> 8; | |
1512 for (int flag = 4; flag >= 0; flag--) { | |
1513 context->flags[flag] = sr & 1; | |
1514 sr >>= 1; | |
1515 } | |
1516 if (context->status & (1 << 5)) { | |
1517 context->aregs[8] = read_le_32(buffer + GST_68K_USP_OFFSET); | |
1518 } else { | |
1519 context->aregs[8] = read_le_32(buffer + GST_68K_SSP_OFFSET); | |
1520 } | |
1521 fseek(gstfile, GST_68K_RAM, SEEK_SET); | |
1522 for (int i = 0; i < (32*1024);) { | |
1523 if (fread(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) { | |
1524 fputs("Failed to read 68K RAM from savestate\n", stderr); | |
1525 return 0; | |
1526 } | |
1527 for(curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) { | |
1528 context->mem_pointers[1][i++] = read_be_16(curpos); | |
1529 } | |
1530 } | |
1531 return pc; | |
1532 } | |
1533 | |
1534 uint8_t z80_load_gst(z80_context * context, FILE * gstfile) | |
1535 { | |
1536 uint8_t regdata[GST_Z80_REG_SIZE]; | |
1537 fseek(gstfile, GST_Z80_REGS, SEEK_SET); | |
1538 if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) { | |
1539 fputs("Failed to read Z80 registers from savestate\n", stderr); | |
1540 return 0; | |
1541 } | |
1542 uint8_t * curpos = regdata; | |
1543 uint8_t f = *(curpos++); | |
1544 context->flags[ZF_C] = f & 1; | |
1545 f >>= 1; | |
1546 context->flags[ZF_N] = f & 1; | |
1547 f >>= 1; | |
1548 context->flags[ZF_PV] = f & 1; | |
1549 f >>= 2; | |
1550 context->flags[ZF_H] = f & 1; | |
1551 f >>= 2; | |
1552 context->flags[ZF_Z] = f & 1; | |
1553 f >>= 1; | |
1554 context->flags[ZF_S] = f; | |
1555 | |
1556 context->regs[Z80_A] = *curpos; | |
1557 curpos += 3; | |
1558 for (int reg = Z80_C; reg <= Z80_IYH; reg++) { | |
1559 context->regs[reg++] = *(curpos++); | |
1560 context->regs[reg] = *curpos; | |
1561 curpos += 3; | |
1562 } | |
1563 uint16_t pc = read_le_16(curpos); | |
1564 curpos += 4; | |
1565 context->sp = read_le_16(curpos); | |
1566 curpos += 4; | |
1567 f = *(curpos++); | |
1568 context->alt_flags[ZF_C] = f & 1; | |
1569 f >>= 1; | |
1570 context->alt_flags[ZF_N] = f & 1; | |
1571 f >>= 1; | |
1572 context->alt_flags[ZF_PV] = f & 1; | |
1573 f >>= 2; | |
1574 context->alt_flags[ZF_H] = f & 1; | |
1575 f >>= 2; | |
1576 context->alt_flags[ZF_Z] = f & 1; | |
1577 f >>= 1; | |
1578 context->alt_flags[ZF_S] = f; | |
1579 context->alt_regs[Z80_A] = *curpos; | |
1580 curpos += 3; | |
1581 for (int reg = Z80_C; reg <= Z80_H; reg++) { | |
1582 context->alt_regs[reg++] = *(curpos++); | |
1583 context->alt_regs[reg] = *curpos; | |
1584 curpos += 3; | |
1585 } | |
1586 context->regs[Z80_I] = *curpos; | |
1587 curpos += 2; | |
1588 context->iff1 = context->iff2 = *curpos; | |
1589 curpos += 2; | |
1590 reset = !*(curpos++); | |
1591 busreq = *curpos; | |
1592 curpos += 3; | |
1593 uint32_t bank = read_le_32(curpos); | |
1594 if (bank < 0x400000) { | |
1595 context->mem_pointers[1] = context->mem_pointers[2] + bank; | |
1596 } else { | |
1597 context->mem_pointers[1] = NULL; | |
1598 } | |
1599 context->bank_reg = bank >> 15; | |
1600 fseek(gstfile, GST_Z80_RAM, SEEK_SET); | |
1601 if(fread(context->mem_pointers[0], 1, 8*1024, gstfile) != (8*1024)) { | |
1602 fputs("Failed to read Z80 RAM from savestate\n", stderr); | |
1603 return 0; | |
1604 } | |
1605 context->native_pc = z80_get_native_address_trans(context, pc); | |
1606 return 1; | |
1607 } | |
1608 | |
1609 uint32_t load_gst(genesis_context * gen, char * fname) | |
1610 { | |
1611 FILE * gstfile = fopen(fname, "rb"); | |
1612 if (!gstfile) { | |
1613 fprintf(stderr, "Could not open file %s for reading\n", fname); | |
1614 goto error; | |
1615 } | |
1616 char ident[5]; | |
1617 if (fread(ident, 1, sizeof(ident), gstfile) != sizeof(ident)) { | |
1618 fprintf(stderr, "Could not read ident code from %s\n", fname); | |
1619 goto error_close; | |
1620 } | |
1621 if (memcmp(ident, "GST\xE0\x40", 3) != 0) { | |
1622 fprintf(stderr, "%s doesn't appear to be a GST savestate. The ident code is %c%c%c\\x%X\\x%X instead of GST\\xE0\\x40.\n", fname, ident[0], ident[1], ident[2], ident[3], ident[4]); | |
1623 goto error_close; | |
1624 } | |
1625 uint32_t pc = m68k_load_gst(gen->m68k, gstfile); | |
1626 if (!pc) { | |
1627 goto error_close; | |
1628 } | |
1629 if (!vdp_load_gst(gen->vdp, gstfile)) { | |
1630 goto error_close; | |
1631 } | |
1632 if (!ym_load_gst(gen->ym, gstfile)) { | |
1633 goto error_close; | |
1634 } | |
1635 if (!z80_load_gst(gen->z80, gstfile)) { | |
1636 goto error_close; | |
1637 } | |
1638 gen->ports[0].control = 0x40; | |
1639 gen->ports[1].control = 0x40; | |
1640 adjust_int_cycle(gen->m68k, gen->vdp); | |
1641 fclose(gstfile); | |
1642 return pc; | |
1643 | |
1644 error_close: | |
1645 fclose(gstfile); | |
1646 error: | |
1647 return 0; | |
1648 } | 1513 } |
1649 | 1514 |
1650 #define ROM_END 0x1A4 | 1515 #define ROM_END 0x1A4 |
1651 #define RAM_ID 0x1B0 | 1516 #define RAM_ID 0x1B0 |
1652 #define RAM_FLAGS 0x1B2 | 1517 #define RAM_FLAGS 0x1B2 |
1656 #define RAM_FLAG_MASK 0x1800 | 1521 #define RAM_FLAG_MASK 0x1800 |
1657 | 1522 |
1658 const memmap_chunk static_map[] = { | 1523 const memmap_chunk static_map[] = { |
1659 {0, 0x400000, 0xFFFFFF, 0, MMAP_READ, cart, | 1524 {0, 0x400000, 0xFFFFFF, 0, MMAP_READ, cart, |
1660 NULL, NULL, NULL, NULL}, | 1525 NULL, NULL, NULL, NULL}, |
1661 {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, | 1526 {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, |
1662 NULL, NULL, NULL, NULL}, | 1527 NULL, NULL, NULL, NULL}, |
1663 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, NULL, | 1528 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, NULL, |
1664 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, | 1529 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, |
1665 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b}, | 1530 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b}, |
1666 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, NULL, | 1531 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, NULL, |
1709 if (ram_start >= rom_end) { | 1574 if (ram_start >= rom_end) { |
1710 memmap[0].end = rom_end; | 1575 memmap[0].end = rom_end; |
1711 memmap[0].mask = 0xFFFFFF; | 1576 memmap[0].mask = 0xFFFFFF; |
1712 memmap[0].flags = MMAP_READ; | 1577 memmap[0].flags = MMAP_READ; |
1713 memmap[0].buffer = cart; | 1578 memmap[0].buffer = cart; |
1714 | 1579 |
1715 ram_start &= 0xFFFFFE; | 1580 ram_start &= 0xFFFFFE; |
1716 ram_end |= 1; | 1581 ram_end |= 1; |
1717 memmap[1].start = ram_start; | 1582 memmap[1].start = ram_start; |
1718 gen->save_ram_mask = memmap[1].mask = ram_end-ram_start; | 1583 gen->save_ram_mask = memmap[1].mask = ram_end-ram_start; |
1719 ram_end += 1; | 1584 ram_end += 1; |
1726 } else if((ram_flags & RAM_FLAG_MASK) == RAM_FLAG_EVEN) { | 1591 } else if((ram_flags & RAM_FLAG_MASK) == RAM_FLAG_EVEN) { |
1727 memmap[1].flags |= MMAP_ONLY_EVEN; | 1592 memmap[1].flags |= MMAP_ONLY_EVEN; |
1728 size /= 2; | 1593 size /= 2; |
1729 } | 1594 } |
1730 memmap[1].buffer = gen->save_ram = malloc(size); | 1595 memmap[1].buffer = gen->save_ram = malloc(size); |
1731 | 1596 |
1732 memcpy(memmap+2, static_map+1, sizeof(static_map)-sizeof(static_map[0])); | 1597 memcpy(memmap+2, static_map+1, sizeof(static_map)-sizeof(static_map[0])); |
1733 num_chunks = sizeof(static_map)/sizeof(memmap_chunk)+1; | 1598 num_chunks = sizeof(static_map)/sizeof(memmap_chunk)+1; |
1734 } else { | 1599 } else { |
1735 //Assume the standard Sega mapper for now | 1600 //Assume the standard Sega mapper for now |
1736 memmap[0].end = 0x200000; | 1601 memmap[0].end = 0x200000; |
1737 memmap[0].mask = 0xFFFFFF; | 1602 memmap[0].mask = 0xFFFFFF; |
1738 memmap[0].flags = MMAP_READ; | 1603 memmap[0].flags = MMAP_READ; |
1739 memmap[0].buffer = cart; | 1604 memmap[0].buffer = cart; |
1740 | 1605 |
1741 memmap[1].start = 0x200000; | 1606 memmap[1].start = 0x200000; |
1742 memmap[1].end = 0x400000; | 1607 memmap[1].end = 0x400000; |
1743 memmap[1].mask = 0x1FFFFF; | 1608 memmap[1].mask = 0x1FFFFF; |
1744 ram_start &= 0xFFFFFE; | 1609 ram_start &= 0xFFFFFE; |
1745 ram_end |= 1; | 1610 ram_end |= 1; |
1755 memset(memmap+num_chunks, 0, sizeof(memmap[num_chunks])); | 1620 memset(memmap+num_chunks, 0, sizeof(memmap[num_chunks])); |
1756 memmap[num_chunks].start = 0xA13000; | 1621 memmap[num_chunks].start = 0xA13000; |
1757 memmap[num_chunks].end = 0xA13100; | 1622 memmap[num_chunks].end = 0xA13100; |
1758 memmap[num_chunks].mask = 0xFF; | 1623 memmap[num_chunks].mask = 0xFF; |
1759 memmap[num_chunks].write_16 = (write_16_fun)write_bank_reg_w; | 1624 memmap[num_chunks].write_16 = (write_16_fun)write_bank_reg_w; |
1760 memmap[num_chunks].write_8 = (write_8_fun)write_bank_reg_b; | 1625 memmap[num_chunks].write_8 = (write_8_fun)write_bank_reg_b; |
1761 num_chunks++; | 1626 num_chunks++; |
1762 ram_end++; | 1627 ram_end++; |
1763 size = ram_end-ram_start; | 1628 size = ram_end-ram_start; |
1764 if ((ram_flags & RAM_FLAG_MASK) != RAM_FLAG_BOTH) { | 1629 if ((ram_flags & RAM_FLAG_MASK) != RAM_FLAG_BOTH) { |
1765 size /= 2; | 1630 size /= 2; |
1784 atexit(save_sram); | 1649 atexit(save_sram); |
1785 } | 1650 } |
1786 init_x86_68k_opts(&opts, memmap, num_chunks); | 1651 init_x86_68k_opts(&opts, memmap, num_chunks); |
1787 opts.address_log = address_log; | 1652 opts.address_log = address_log; |
1788 init_68k_context(&context, opts.native_code_map, &opts); | 1653 init_68k_context(&context, opts.native_code_map, &opts); |
1789 | 1654 |
1790 context.video_context = gen->vdp; | 1655 context.video_context = gen->vdp; |
1791 context.system = gen; | 1656 context.system = gen; |
1792 //cartridge ROM | 1657 //cartridge ROM |
1793 context.mem_pointers[0] = cart; | 1658 context.mem_pointers[0] = cart; |
1794 context.target_cycle = context.sync_cycle = mclks_per_frame/MCLKS_PER_68K; | 1659 context.target_cycle = context.sync_cycle = mclks_per_frame/MCLKS_PER_68K; |
1801 address = cart[2] << 16 | cart[3]; | 1666 address = cart[2] << 16 | cart[3]; |
1802 translate_m68k_stream(address, &context); | 1667 translate_m68k_stream(address, &context); |
1803 if (statefile) { | 1668 if (statefile) { |
1804 uint32_t pc = load_gst(gen, statefile); | 1669 uint32_t pc = load_gst(gen, statefile); |
1805 if (!pc) { | 1670 if (!pc) { |
1671 fprintf(stderr, "Failed to load save state %s\n", statefile); | |
1806 exit(1); | 1672 exit(1); |
1807 } | 1673 } |
1674 printf("Loaded %s\n", statefile); | |
1808 if (debug) { | 1675 if (debug) { |
1809 insert_breakpoint(&context, pc, (uint8_t *)debugger); | 1676 insert_breakpoint(&context, pc, (uint8_t *)debugger); |
1810 } | 1677 } |
1678 adjust_int_cycle(gen->m68k, gen->vdp); | |
1679 gen->z80->native_pc = z80_get_native_address_trans(gen->z80, gen->z80->pc); | |
1811 start_68k_context(&context, pc); | 1680 start_68k_context(&context, pc); |
1812 } else { | 1681 } else { |
1813 if (debug) { | 1682 if (debug) { |
1814 insert_breakpoint(&context, address, (uint8_t *)debugger); | 1683 insert_breakpoint(&context, address, (uint8_t *)debugger); |
1815 } | 1684 } |
1863 version_reg = NO_DISK | USA; | 1732 version_reg = NO_DISK | USA; |
1864 } else if (detect_specific_region('J')) { | 1733 } else if (detect_specific_region('J')) { |
1865 version_reg = NO_DISK | JAP; | 1734 version_reg = NO_DISK | JAP; |
1866 } else if (detect_specific_region('E') || detect_specific_region('A')) { | 1735 } else if (detect_specific_region('E') || detect_specific_region('A')) { |
1867 version_reg = NO_DISK | EUR; | 1736 version_reg = NO_DISK | EUR; |
1737 } else { | |
1738 char * def_region = tern_find_ptr(config, "default_region"); | |
1739 if (def_region) { | |
1740 switch(*def_region) | |
1741 { | |
1742 case 'j': | |
1743 case 'J': | |
1744 version_reg = NO_DISK | JAP; | |
1745 break; | |
1746 case 'u': | |
1747 case 'U': | |
1748 version_reg = NO_DISK | USA; | |
1749 break; | |
1750 case 'e': | |
1751 case 'E': | |
1752 version_reg = NO_DISK | EUR; | |
1753 break; | |
1754 } | |
1755 } | |
1868 } | 1756 } |
1869 } | 1757 } |
1870 | 1758 |
1871 int main(int argc, char ** argv) | 1759 int main(int argc, char ** argv) |
1872 { | 1760 { |
1873 if (argc < 2) { | 1761 if (argc < 2) { |
1874 fputs("Usage: blastem FILENAME\n", stderr); | 1762 fputs("Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n", stderr); |
1875 return 1; | 1763 return 1; |
1876 } | 1764 } |
1877 if(!load_rom(argv[1])) { | 1765 config = load_config(argv[0]); |
1878 fprintf(stderr, "Failed to open %s for reading\n", argv[1]); | |
1879 return 1; | |
1880 } | |
1881 detect_region(); | 1766 detect_region(); |
1882 int width = -1; | 1767 int width = -1; |
1883 int height = -1; | 1768 int height = -1; |
1884 int debug = 0; | 1769 int debug = 0; |
1885 int ym_log = 0; | 1770 int ym_log = 0; |
1771 int loaded = 0; | |
1772 uint8_t force_version = 0; | |
1773 char * romfname = NULL; | |
1886 FILE *address_log = NULL; | 1774 FILE *address_log = NULL; |
1887 char * statefile = NULL; | 1775 char * statefile = NULL; |
1888 for (int i = 2; i < argc; i++) { | 1776 uint8_t fullscreen = 0; |
1777 for (int i = 1; i < argc; i++) { | |
1889 if (argv[i][0] == '-') { | 1778 if (argv[i][0] == '-') { |
1890 switch(argv[i][1]) { | 1779 switch(argv[i][1]) { |
1891 case 'd': | 1780 case 'd': |
1892 debug = 1; | 1781 debug = 1; |
1893 break; | 1782 break; |
1894 case 'f': | 1783 case 'f': |
1895 frame_limit = 1; | 1784 fullscreen = 1; |
1896 break; | 1785 break; |
1897 case 'l': | 1786 case 'l': |
1898 address_log = fopen("address.log", "w"); | 1787 address_log = fopen("address.log", "w"); |
1899 break; | 1788 break; |
1900 case 'v': | 1789 case 'v': |
1901 headless = 1; | 1790 printf("blastem %s\n", BLASTEM_VERSION); |
1791 return 0; | |
1902 break; | 1792 break; |
1903 case 'n': | 1793 case 'n': |
1904 z80_enabled = 0; | 1794 z80_enabled = 0; |
1905 break; | 1795 break; |
1906 case 'r': | 1796 case 'r': |
1911 } | 1801 } |
1912 switch (argv[i][0]) | 1802 switch (argv[i][0]) |
1913 { | 1803 { |
1914 case 'j': | 1804 case 'j': |
1915 case 'J': | 1805 case 'J': |
1916 version_reg = NO_DISK | JAP; | 1806 force_version = NO_DISK | JAP; |
1917 break; | 1807 break; |
1918 case 'u': | 1808 case 'u': |
1919 case 'U': | 1809 case 'U': |
1920 version_reg = NO_DISK | USA; | 1810 force_version = NO_DISK | USA; |
1921 break; | 1811 break; |
1922 case 'e': | 1812 case 'e': |
1923 case 'E': | 1813 case 'E': |
1924 version_reg = NO_DISK | EUR; | 1814 force_version = NO_DISK | EUR; |
1925 break; | 1815 break; |
1926 default: | 1816 default: |
1927 fprintf(stderr, "'%c' is not a valid region character for the -r option\n", argv[i][0]); | 1817 fprintf(stderr, "'%c' is not a valid region character for the -r option\n", argv[i][0]); |
1928 return 1; | 1818 return 1; |
1929 } | 1819 } |
1937 statefile = argv[i]; | 1827 statefile = argv[i]; |
1938 break; | 1828 break; |
1939 case 'y': | 1829 case 'y': |
1940 ym_log = 1; | 1830 ym_log = 1; |
1941 break; | 1831 break; |
1832 case 'h': | |
1833 puts( | |
1834 "Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n" | |
1835 "Options:\n" | |
1836 " -h Print this help text\n" | |
1837 " -r (J|U|E) Force region to Japan, US or Europe respectively\n" | |
1838 " -f Start in fullscreen mode\n" | |
1839 " -s FILE Load a GST format savestate from FILE\n" | |
1840 " -d Enter debugger on startup\n" | |
1841 " -n Disable Z80\n" | |
1842 " -v Display version number and exit\n" | |
1843 " -l Log 68K code addresses (useful for assemblers)\n" | |
1844 " -y Log individual YM-2612 channels to WAVE files\n" | |
1845 ); | |
1846 return 0; | |
1942 default: | 1847 default: |
1943 fprintf(stderr, "Unrecognized switch %s\n", argv[i]); | 1848 fprintf(stderr, "Unrecognized switch %s\n", argv[i]); |
1944 return 1; | 1849 return 1; |
1945 } | 1850 } |
1851 } else if (!loaded) { | |
1852 if(!load_rom(argv[i])) { | |
1853 fprintf(stderr, "Failed to open %s for reading\n", argv[i]); | |
1854 return 1; | |
1855 } | |
1856 romfname = argv[i]; | |
1857 loaded = 1; | |
1946 } else if (width < 0) { | 1858 } else if (width < 0) { |
1947 width = atoi(argv[i]); | 1859 width = atoi(argv[i]); |
1948 } else if (height < 0) { | 1860 } else if (height < 0) { |
1949 height = atoi(argv[i]); | 1861 height = atoi(argv[i]); |
1950 } | 1862 } |
1951 } | 1863 } |
1864 if (!loaded) { | |
1865 fputs("You must specify a ROM filename!\n", stderr); | |
1866 return 1; | |
1867 } | |
1868 if (force_version) { | |
1869 version_reg = force_version; | |
1870 } | |
1952 update_title(); | 1871 update_title(); |
1953 width = width < 320 ? 640 : width; | 1872 int def_width = 0; |
1873 char *config_width = tern_find_ptr(config, "videowidth"); | |
1874 if (config_width) { | |
1875 def_width = atoi(config_width); | |
1876 } | |
1877 if (!def_width) { | |
1878 def_width = 640; | |
1879 } | |
1880 width = width < 320 ? def_width : width; | |
1954 height = height < 240 ? (width/320) * 240 : height; | 1881 height = height < 240 ? (width/320) * 240 : height; |
1955 uint32_t fps = 60; | 1882 uint32_t fps = 60; |
1956 if (version_reg & 0x40) { | 1883 if (version_reg & 0x40) { |
1957 mclks_per_frame = MCLKS_LINE * LINES_PAL; | 1884 mclks_per_frame = MCLKS_LINE * LINES_PAL; |
1958 fps = 50; | 1885 fps = 50; |
1959 } | 1886 } |
1960 if (!headless) { | 1887 if (!headless) { |
1961 render_init(width, height, title, fps, 0); | 1888 render_init(width, height, title, fps, fullscreen, 0); |
1962 } | 1889 } |
1963 vdp_context v_context; | 1890 vdp_context v_context; |
1964 | 1891 genesis_context gen; |
1892 memset(&gen, 0, sizeof(gen)); | |
1893 gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL; | |
1894 | |
1965 init_vdp_context(&v_context); | 1895 init_vdp_context(&v_context); |
1966 | 1896 |
1967 ym2612_context y_context; | 1897 ym2612_context y_context; |
1968 ym_init(&y_context, render_sample_rate(), fps == 60 ? MCLKS_NTSC : MCLKS_PAL, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); | 1898 ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); |
1969 | 1899 |
1970 psg_context p_context; | 1900 psg_context p_context; |
1971 psg_init(&p_context, render_sample_rate(), fps == 60 ? MCLKS_NTSC : MCLKS_PAL, MCLKS_PER_PSG, render_audio_buffer()); | 1901 psg_init(&p_context, render_sample_rate(), gen.master_clock, MCLKS_PER_PSG, render_audio_buffer()); |
1972 | 1902 |
1973 z80_context z_context; | 1903 z80_context z_context; |
1974 x86_z80_options z_opts; | 1904 x86_z80_options z_opts; |
1975 init_x86_z80_opts(&z_opts); | 1905 init_x86_z80_opts(&z_opts); |
1976 init_z80_context(&z_context, &z_opts); | 1906 init_z80_context(&z_context, &z_opts); |
1977 | |
1978 genesis_context gen; | |
1979 memset(&gen, 0, sizeof(gen)); | |
1980 | 1907 |
1981 z_context.system = &gen; | 1908 z_context.system = &gen; |
1982 z_context.mem_pointers[0] = z80_ram; | 1909 z_context.mem_pointers[0] = z80_ram; |
1983 z_context.sync_cycle = z_context.target_cycle = mclks_per_frame/MCLKS_PER_Z80; | 1910 z_context.sync_cycle = z_context.target_cycle = mclks_per_frame/MCLKS_PER_Z80; |
1984 z_context.int_cycle = CYCLE_NEVER; | 1911 z_context.int_cycle = CYCLE_NEVER; |
1985 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; | 1912 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; |
1986 | 1913 |
1987 gen.z80 = &z_context; | 1914 gen.z80 = &z_context; |
1988 gen.vdp = &v_context; | 1915 gen.vdp = &v_context; |
1989 gen.ym = &y_context; | 1916 gen.ym = &y_context; |
1990 gen.psg = &p_context; | 1917 gen.psg = &p_context; |
1991 genesis = &gen; | 1918 genesis = &gen; |
1992 | 1919 |
1993 int fname_size = strlen(argv[1]); | 1920 int fname_size = strlen(romfname); |
1994 sram_filename = malloc(fname_size+6); | 1921 sram_filename = malloc(fname_size+6); |
1995 memcpy(sram_filename, argv[1], fname_size); | 1922 memcpy(sram_filename, romfname, fname_size); |
1996 int i; | 1923 int i; |
1997 for (i = fname_size-1; fname_size >= 0; --i) { | 1924 for (i = fname_size-1; fname_size >= 0; --i) { |
1998 if (sram_filename[i] == '.') { | 1925 if (sram_filename[i] == '.') { |
1999 strcpy(sram_filename + i + 1, "sram"); | 1926 strcpy(sram_filename + i + 1, "sram"); |
2000 break; | 1927 break; |
2002 } | 1929 } |
2003 if (i < 0) { | 1930 if (i < 0) { |
2004 strcpy(sram_filename + fname_size, ".sram"); | 1931 strcpy(sram_filename + fname_size, ".sram"); |
2005 } | 1932 } |
2006 set_keybindings(); | 1933 set_keybindings(); |
2007 | 1934 |
2008 init_run_cpu(&gen, debug, address_log, statefile); | 1935 init_run_cpu(&gen, debug, address_log, statefile); |
2009 return 0; | 1936 return 0; |
2010 } | 1937 } |