Mercurial > repos > blastem
comparison blastem.c @ 288:a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 05 May 2013 22:56:42 -0700 |
parents | 9ee64039ddeb |
children | 1cc0850ab6bc |
comparison
equal
deleted
inserted
replaced
287:fb840e0a48cd | 288:a8ee7934a1f8 |
---|---|
163 } | 163 } |
164 | 164 |
165 m68k_context * sync_components(m68k_context * context, uint32_t address) | 165 m68k_context * sync_components(m68k_context * context, uint32_t address) |
166 { | 166 { |
167 //TODO: Handle sync targets smaller than a single frame | 167 //TODO: Handle sync targets smaller than a single frame |
168 vdp_context * v_context = context->video_context; | 168 genesis_context * gen = context->system; |
169 z80_context * z_context = context->next_cpu; | 169 vdp_context * v_context = gen->vdp; |
170 z80_context * z_context = gen->z80; | |
170 uint32_t mclks = context->current_cycle * MCLKS_PER_68K; | 171 uint32_t mclks = context->current_cycle * MCLKS_PER_68K; |
171 sync_z80(z_context, mclks); | 172 sync_z80(z_context, mclks); |
172 if (mclks >= MCLKS_PER_FRAME) { | 173 if (mclks >= MCLKS_PER_FRAME) { |
174 ym_run(gen->ym, context->current_cycle); | |
175 gen->ym->current_cycle -= MCLKS_PER_FRAME/MCLKS_PER_68K; | |
173 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); | 176 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); |
174 vdp_run_context(v_context, MCLKS_PER_FRAME); | 177 vdp_run_context(v_context, MCLKS_PER_FRAME); |
175 if (!headless) { | 178 if (!headless) { |
176 break_on_sync |= wait_render_frame(v_context); | 179 break_on_sync |= wait_render_frame(v_context); |
177 } | 180 } |
352 | 355 |
353 uint32_t zram_counter = 0; | 356 uint32_t zram_counter = 0; |
354 | 357 |
355 m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) | 358 m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) |
356 { | 359 { |
360 genesis_context * gen = context->system; | |
357 if (location < 0x10000) { | 361 if (location < 0x10000) { |
358 if (busack_cycle > context->current_cycle) { | 362 if (busack_cycle > context->current_cycle) { |
359 busack = new_busack; | 363 busack = new_busack; |
360 busack_cycle = CYCLE_NEVER; | 364 busack_cycle = CYCLE_NEVER; |
361 } | 365 } |
362 if (!(busack || reset)) { | 366 if (!(busack || reset)) { |
363 location &= 0x7FFF; | 367 location &= 0x7FFF; |
364 if (location < 0x4000) { | 368 if (location < 0x4000) { |
365 z80_ram[location & 0x1FFF] = value; | 369 z80_ram[location & 0x1FFF] = value; |
366 z80_handle_code_write(location & 0x1FFF, context->next_cpu); | 370 z80_handle_code_write(location & 0x1FFF, gen->z80); |
371 } else if (location < 0x6000) { | |
372 ym_run(gen->ym, context->current_cycle); | |
373 if (location & 1) { | |
374 ym_data_write(gen->ym, value); | |
375 } else if(location & 2) { | |
376 ym_address_write_part2(gen->ym, value); | |
377 } else { | |
378 ym_address_write_part1(gen->ym, value); | |
379 } | |
367 } | 380 } |
368 } | 381 } |
369 } else { | 382 } else { |
370 location &= 0x1FFF; | 383 location &= 0x1FFF; |
371 if (location < 0x100) { | 384 if (location < 0x100) { |
386 gamepad_2.control = value; | 399 gamepad_2.control = value; |
387 break; | 400 break; |
388 } | 401 } |
389 } else { | 402 } else { |
390 if (location == 0x1100) { | 403 if (location == 0x1100) { |
391 sync_z80(context->next_cpu, context->current_cycle * MCLKS_PER_68K); | 404 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); |
392 if (busack_cycle > context->current_cycle) { | 405 if (busack_cycle > context->current_cycle) { |
393 busack = new_busack; | 406 busack = new_busack; |
394 busack_cycle = CYCLE_NEVER; | 407 busack_cycle = CYCLE_NEVER; |
395 } | 408 } |
396 if (value & 1) { | 409 if (value & 1) { |
408 sprintf(fname, "zram-%d", zram_counter++); | 421 sprintf(fname, "zram-%d", zram_counter++); |
409 FILE * f = fopen(fname, "wb"); | 422 FILE * f = fopen(fname, "wb"); |
410 fwrite(z80_ram, 1, sizeof(z80_ram), f); | 423 fwrite(z80_ram, 1, sizeof(z80_ram), f); |
411 fclose(f); | 424 fclose(f); |
412 #endif | 425 #endif |
413 z80_context * z_context = context->next_cpu; | |
414 //TODO: Add necessary delay between release of busreq and resumption of execution | 426 //TODO: Add necessary delay between release of busreq and resumption of execution |
415 z_context->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; | 427 gen->z80->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; |
416 } | 428 } |
417 busreq = 0; | 429 busreq = 0; |
418 busack_cycle = CYCLE_NEVER; | 430 busack_cycle = CYCLE_NEVER; |
419 busack = 1; | 431 busack = 1; |
420 } | 432 } |
421 } else if (location == 0x1200) { | 433 } else if (location == 0x1200) { |
422 sync_z80(context->next_cpu, context->current_cycle * MCLKS_PER_68K); | 434 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); |
423 if (value & 1) { | 435 if (value & 1) { |
424 if (reset && busreq) { | 436 if (reset && busreq) { |
425 new_busack = 0; | 437 new_busack = 0; |
426 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | 438 busack_cycle = context->current_cycle + Z80_ACK_DELAY; |
427 } | 439 } |
428 //TODO: Deal with the scenario in which reset is not asserted long enough | 440 //TODO: Deal with the scenario in which reset is not asserted long enough |
429 if (reset) { | 441 if (reset) { |
430 z80_context * z_context = context->next_cpu; | |
431 need_reset = 1; | 442 need_reset = 1; |
432 //TODO: Add necessary delay between release of reset and start of execution | 443 //TODO: Add necessary delay between release of reset and start of execution |
433 z_context->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; | 444 gen->z80->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; |
434 } | 445 } |
435 reset = 0; | 446 reset = 0; |
436 } else { | 447 } else { |
437 reset = 1; | 448 reset = 1; |
438 } | 449 } |
442 return context; | 453 return context; |
443 } | 454 } |
444 | 455 |
445 m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value) | 456 m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value) |
446 { | 457 { |
458 genesis_context * gen = context->system; | |
447 if (location < 0x10000) { | 459 if (location < 0x10000) { |
448 if (busack_cycle > context->current_cycle) { | 460 if (busack_cycle > context->current_cycle) { |
449 busack = new_busack; | 461 busack = new_busack; |
450 busack_cycle = CYCLE_NEVER; | 462 busack_cycle = CYCLE_NEVER; |
451 } | 463 } |
452 if (!(busack || reset)) { | 464 if (!(busack || reset)) { |
453 location &= 0x7FFF; | 465 location &= 0x7FFF; |
454 if (location < 0x4000) { | 466 if (location < 0x4000) { |
455 z80_ram[location & 0x1FFE] = value >> 8; | 467 z80_ram[location & 0x1FFE] = value >> 8; |
456 z80_handle_code_write(location & 0x1FFE, context->next_cpu); | 468 z80_handle_code_write(location & 0x1FFE, gen->z80); |
469 } else if (location < 0x6000) { | |
470 ym_run(gen->ym, context->current_cycle); | |
471 if (location & 1) { | |
472 ym_data_write(gen->ym, value >> 8); | |
473 } else if(location & 2) { | |
474 ym_address_write_part2(gen->ym, value >> 8); | |
475 } else { | |
476 ym_address_write_part1(gen->ym, value >> 8); | |
477 } | |
457 } | 478 } |
458 } | 479 } |
459 } else { | 480 } else { |
460 location &= 0x1FFF; | 481 location &= 0x1FFF; |
461 if (location < 0x100) { | 482 if (location < 0x100) { |
477 break; | 498 break; |
478 } | 499 } |
479 } else { | 500 } else { |
480 //printf("IO Write of %X to %X @ %d\n", value, location, context->current_cycle); | 501 //printf("IO Write of %X to %X @ %d\n", value, location, context->current_cycle); |
481 if (location == 0x1100) { | 502 if (location == 0x1100) { |
482 sync_z80(context->next_cpu, context->current_cycle * MCLKS_PER_68K); | 503 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); |
483 if (busack_cycle > context->current_cycle) { | 504 if (busack_cycle > context->current_cycle) { |
484 busack = new_busack; | 505 busack = new_busack; |
485 busack_cycle = CYCLE_NEVER; | 506 busack_cycle = CYCLE_NEVER; |
486 } | 507 } |
487 if (value & 0x100) { | 508 if (value & 0x100) { |
499 sprintf(fname, "zram-%d", zram_counter++); | 520 sprintf(fname, "zram-%d", zram_counter++); |
500 FILE * f = fopen(fname, "wb"); | 521 FILE * f = fopen(fname, "wb"); |
501 fwrite(z80_ram, 1, sizeof(z80_ram), f); | 522 fwrite(z80_ram, 1, sizeof(z80_ram), f); |
502 fclose(f); | 523 fclose(f); |
503 #endif | 524 #endif |
504 z80_context * z_context = context->next_cpu; | |
505 //TODO: Add necessary delay between release of busreq and resumption of execution | 525 //TODO: Add necessary delay between release of busreq and resumption of execution |
506 z_context->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; | 526 gen->z80->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; |
507 } | 527 } |
508 busreq = 0; | 528 busreq = 0; |
509 busack_cycle = CYCLE_NEVER; | 529 busack_cycle = CYCLE_NEVER; |
510 busack = 1; | 530 busack = 1; |
511 } | 531 } |
512 } else if (location == 0x1200) { | 532 } else if (location == 0x1200) { |
513 sync_z80(context->next_cpu, context->current_cycle * MCLKS_PER_68K); | 533 sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); |
514 if (value & 0x100) { | 534 if (value & 0x100) { |
515 if (reset && busreq) { | 535 if (reset && busreq) { |
516 new_busack = 0; | 536 new_busack = 0; |
517 busack_cycle = context->current_cycle + Z80_ACK_DELAY; | 537 busack_cycle = context->current_cycle + Z80_ACK_DELAY; |
518 } | 538 } |
519 //TODO: Deal with the scenario in which reset is not asserted long enough | 539 //TODO: Deal with the scenario in which reset is not asserted long enough |
520 if (reset) { | 540 if (reset) { |
521 z80_context * z_context = context->next_cpu; | |
522 need_reset = 1; | 541 need_reset = 1; |
523 //TODO: Add necessary delay between release of reset and start of execution | 542 //TODO: Add necessary delay between release of reset and start of execution |
524 z_context->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; | 543 gen->z80->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80; |
525 } | 544 } |
526 reset = 0; | 545 reset = 0; |
527 } else { | 546 } else { |
528 reset = 1; | 547 reset = 1; |
529 } | 548 } |
539 #define NO_DISK 0x20 | 558 #define NO_DISK 0x20 |
540 uint8_t version_reg = NO_DISK | USA; | 559 uint8_t version_reg = NO_DISK | USA; |
541 | 560 |
542 m68k_context * io_read(uint32_t location, m68k_context * context) | 561 m68k_context * io_read(uint32_t location, m68k_context * context) |
543 { | 562 { |
563 genesis_context *gen = context->system; | |
544 if (location < 0x10000) { | 564 if (location < 0x10000) { |
545 if (busack_cycle > context->current_cycle) { | 565 if (busack_cycle > context->current_cycle) { |
546 busack = new_busack; | 566 busack = new_busack; |
547 busack_cycle = CYCLE_NEVER; | 567 busack_cycle = CYCLE_NEVER; |
548 } | 568 } |
549 if (!(busack || reset)) { | 569 if (!(busack || reset)) { |
550 location &= 0x7FFF; | 570 location &= 0x7FFF; |
551 if (location < 0x4000) { | 571 if (location < 0x4000) { |
552 context->value = z80_ram[location & 0x1FFF]; | 572 context->value = z80_ram[location & 0x1FFF]; |
573 } else if (location < 0x6000) { | |
574 ym_run(gen->ym, context->current_cycle); | |
575 context->value = ym_read_status(gen->ym); | |
553 } else { | 576 } else { |
554 context->value = 0xFF; | 577 context->value = 0xFF; |
555 } | 578 } |
556 } else { | 579 } else { |
557 context->value = 0xFF; | 580 context->value = 0xFF; |
599 return context; | 622 return context; |
600 } | 623 } |
601 | 624 |
602 m68k_context * io_read_w(uint32_t location, m68k_context * context) | 625 m68k_context * io_read_w(uint32_t location, m68k_context * context) |
603 { | 626 { |
627 genesis_context * gen = context->system; | |
604 if (location < 0x10000) { | 628 if (location < 0x10000) { |
605 if (busack_cycle > context->current_cycle) { | 629 if (busack_cycle > context->current_cycle) { |
606 busack = new_busack; | 630 busack = new_busack; |
607 busack_cycle = CYCLE_NEVER; | 631 busack_cycle = CYCLE_NEVER; |
608 } | 632 } |
609 if (!(busack || reset)) { | 633 if (!(busack || reset)) { |
610 location &= 0x7FFF; | 634 location &= 0x7FFF; |
635 uint16_t value; | |
611 if (location < 0x4000) { | 636 if (location < 0x4000) { |
612 context->value = z80_ram[location & 0x1FFE]; | 637 value = z80_ram[location & 0x1FFE]; |
613 context->value |= context->value << 8; | 638 } else if (location < 0x6000) { |
639 ym_run(gen->ym, context->current_cycle); | |
640 value = ym_read_status(gen->ym); | |
614 } else { | 641 } else { |
615 context->value = 0xFFFF; | 642 value = 0xFF; |
616 } | 643 } |
644 context->value = value | (value << 8); | |
617 } else { | 645 } else { |
618 context->value = 0xFFFF; | 646 context->value = 0xFFFF; |
619 } | 647 } |
620 } else { | 648 } else { |
621 location &= 0x1FFF; | 649 location &= 0x1FFF; |
892 } | 920 } |
893 } | 921 } |
894 return context; | 922 return context; |
895 } | 923 } |
896 | 924 |
897 void init_run_cpu(vdp_context * vcontext, z80_context * zcontext, int debug, FILE * address_log) | 925 void init_run_cpu(genesis_context * gen, int debug, FILE * address_log) |
898 { | 926 { |
899 m68k_context context; | 927 m68k_context context; |
900 x86_68k_options opts; | 928 x86_68k_options opts; |
929 gen->m68k = &context; | |
901 init_x86_68k_opts(&opts); | 930 init_x86_68k_opts(&opts); |
902 opts.address_log = address_log; | 931 opts.address_log = address_log; |
903 init_68k_context(&context, opts.native_code_map, &opts); | 932 init_68k_context(&context, opts.native_code_map, &opts); |
904 | 933 |
905 context.video_context = vcontext; | 934 context.video_context = gen->vdp; |
906 context.next_cpu = zcontext; | 935 context.system = gen; |
907 //cartridge ROM | 936 //cartridge ROM |
908 context.mem_pointers[0] = cart; | 937 context.mem_pointers[0] = cart; |
909 context.target_cycle = context.sync_cycle = MCLKS_PER_FRAME/MCLKS_PER_68K; | 938 context.target_cycle = context.sync_cycle = MCLKS_PER_FRAME/MCLKS_PER_68K; |
910 //work RAM | 939 //work RAM |
911 context.mem_pointers[1] = ram; | 940 context.mem_pointers[1] = ram; |
970 } | 999 } |
971 vdp_context v_context; | 1000 vdp_context v_context; |
972 | 1001 |
973 init_vdp_context(&v_context); | 1002 init_vdp_context(&v_context); |
974 | 1003 |
1004 ym2612_context y_context; | |
1005 ym_init(&y_context); | |
1006 | |
975 z80_context z_context; | 1007 z80_context z_context; |
976 x86_z80_options z_opts; | 1008 x86_z80_options z_opts; |
977 init_x86_z80_opts(&z_opts); | 1009 init_x86_z80_opts(&z_opts); |
978 init_z80_context(&z_context, &z_opts); | 1010 init_z80_context(&z_context, &z_opts); |
979 z_context.next_context = &v_context; | 1011 z_context.next_context = &v_context; |
980 z_context.mem_pointers[0] = z80_ram; | 1012 z_context.mem_pointers[0] = z80_ram; |
981 z_context.sync_cycle = z_context.target_cycle = MCLKS_PER_FRAME/MCLKS_PER_Z80; | 1013 z_context.sync_cycle = z_context.target_cycle = MCLKS_PER_FRAME/MCLKS_PER_Z80; |
982 z_context.int_cycle = CYCLE_NEVER; | 1014 z_context.int_cycle = CYCLE_NEVER; |
983 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; | 1015 z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; |
984 | 1016 |
985 init_run_cpu(&v_context, &z_context, debug, address_log); | 1017 genesis_context gen; |
1018 gen.z80 = &z_context; | |
1019 gen.vdp = &v_context; | |
1020 gen.ym = &y_context; | |
1021 | |
1022 init_run_cpu(&gen, debug, address_log); | |
986 return 0; | 1023 return 0; |
987 } | 1024 } |