comparison blastem.c @ 343:467bfa17004a

Mostly working runtime generation of memory map read/write functions
author Mike Pavone <pavone@retrodev.com>
date Sat, 18 May 2013 11:44:42 -0700
parents 13f994c88c34
children b46771135442
comparison
equal deleted inserted replaced
342:13f994c88c34 343:467bfa17004a
233 return context; 233 return context;
234 } 234 }
235 235
236 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) 236 m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value)
237 { 237 {
238 if (vdp_port & 0x2700E0) {
239 printf("machine freeze due to write to address %X\n", 0xC00000 | vdp_port);
240 exit(1);
241 }
242 vdp_port &= 0x1F;
238 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); 243 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle);
239 sync_components(context, 0); 244 sync_components(context, 0);
240 vdp_context * v_context = context->video_context; 245 vdp_context * v_context = context->video_context;
241 if (vdp_port < 0x10) { 246 if (vdp_port < 0x10) {
242 int blocked; 247 int blocked;
243 if (vdp_port < 4) { 248 if (vdp_port < 4) {
249 uint32_t before_cycle = v_context->cycles;
244 while (vdp_data_port_write(v_context, value) < 0) { 250 while (vdp_data_port_write(v_context, value) < 0) {
245 while(v_context->flags & FLAG_DMA_RUN) { 251 while(v_context->flags & FLAG_DMA_RUN) {
246 vdp_run_dma_done(v_context, mclks_per_frame); 252 vdp_run_dma_done(v_context, mclks_per_frame);
247 if (v_context->cycles >= mclks_per_frame) { 253 if (v_context->cycles >= mclks_per_frame) {
248 if (!headless) { 254 if (!headless) {
291 //TODO: Implement undocumented test register(s) 297 //TODO: Implement undocumented test register(s)
292 } 298 }
293 return context; 299 return context;
294 } 300 }
295 301
296 m68k_context * vdp_port_read(uint32_t vdp_port, m68k_context * context) 302 m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8_t value)
297 { 303 {
304 return vdp_port_write(vdp_port, context, value | value << 8);
305 }
306
307 uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context)
308 {
309 if (vdp_port & 0x2700E0) {
310 printf("machine freeze due to read from address %X\n", 0xC00000 | vdp_port);
311 exit(1);
312 }
313 vdp_port &= 0x1F;
314 uint16_t value;
298 sync_components(context, 0); 315 sync_components(context, 0);
299 vdp_context * v_context = context->video_context; 316 vdp_context * v_context = context->video_context;
300 if (vdp_port < 0x10) { 317 if (vdp_port < 0x10) {
301 if (vdp_port < 4) { 318 if (vdp_port < 4) {
302 context->value = vdp_data_port_read(v_context); 319 value = vdp_data_port_read(v_context);
303 } else if(vdp_port < 8) { 320 } else if(vdp_port < 8) {
304 context->value = vdp_control_port_read(v_context); 321 value = vdp_control_port_read(v_context);
305 } else { 322 } else {
306 context->value = vdp_hv_counter_read(v_context); 323 value = vdp_hv_counter_read(v_context);
307 //printf("HV Counter: %X at cycle %d\n", context->value, v_context->cycles); 324 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles);
308 } 325 }
309 context->current_cycle = v_context->cycles/MCLKS_PER_68K; 326 context->current_cycle = v_context->cycles/MCLKS_PER_68K;
310 } else { 327 } else {
311 printf("Illegal read from PSG or test register port %X\n", vdp_port); 328 printf("Illegal read from PSG or test register port %X\n", vdp_port);
312 exit(1); 329 exit(1);
313 } 330 }
314 return context; 331 return value;
332 }
333
334 uint8_t vdp_port_read_b(uint32_t vdp_port, m68k_context * context)
335 {
336 uint16_t value = vdp_port_read(vdp_port, context);
337 if (vdp_port & 1) {
338 return value;
339 } else {
340 return value >> 8;
341 }
315 } 342 }
316 343
317 #define TH 0x40 344 #define TH 0x40
318 #define TH_TIMEOUT 8000 345 #define TH_TIMEOUT 8000
319 346
349 } 376 }
350 } 377 }
351 pad->output = value; 378 pad->output = value;
352 } 379 }
353 380
354 void io_data_read(io_port * pad, m68k_context * context) 381 uint8_t io_data_read(io_port * pad, m68k_context * context)
355 { 382 {
356 uint8_t control = pad->control | 0x80; 383 uint8_t control = pad->control | 0x80;
357 uint8_t th = control & pad->output; 384 uint8_t th = control & pad->output;
358 uint8_t input; 385 uint8_t input;
359 if (context->current_cycle >= pad->timeout_cycle) { 386 if (context->current_cycle >= pad->timeout_cycle) {
375 input = pad->input[GAMEPAD_TH0] & 0x30; 402 input = pad->input[GAMEPAD_TH0] & 0x30;
376 } else { 403 } else {
377 input = pad->input[GAMEPAD_TH0] | 0xC; 404 input = pad->input[GAMEPAD_TH0] | 0xC;
378 } 405 }
379 } 406 }
380 context->value = ((~input) & (~control)) | (pad->output & control); 407 uint8_t value = ((~input) & (~control)) | (pad->output & control);
381 /*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { 408 /*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) {
382 printf ("value: %X\n", context->value); 409 printf ("value: %X\n", value);
383 }*/ 410 }*/
411 return value;
384 } 412 }
385 413
386 uint32_t zram_counter = 0; 414 uint32_t zram_counter = 0;
387 #define Z80_ACK_DELAY 3 415 #define Z80_ACK_DELAY 3
388 #define Z80_BUSY_DELAY 1//TODO: Find the actual value for this 416 #define Z80_BUSY_DELAY 1//TODO: Find the actual value for this
594 #define JAP 0x00 622 #define JAP 0x00
595 #define EUR 0xC0 623 #define EUR 0xC0
596 #define NO_DISK 0x20 624 #define NO_DISK 0x20
597 uint8_t version_reg = NO_DISK | USA; 625 uint8_t version_reg = NO_DISK | USA;
598 626
599 m68k_context * io_read(uint32_t location, m68k_context * context) 627 uint8_t io_read(uint32_t location, m68k_context * context)
600 { 628 {
629 uint8_t value;
601 genesis_context *gen = context->system; 630 genesis_context *gen = context->system;
602 if (location < 0x10000) { 631 if (location < 0x10000) {
603 if (busack_cycle <= context->current_cycle) { 632 if (busack_cycle <= context->current_cycle) {
604 busack = new_busack; 633 busack = new_busack;
605 busack_cycle = CYCLE_NEVER; 634 busack_cycle = CYCLE_NEVER;
606 } 635 }
607 if (!(busack==Z80_REQ_BUSY || reset)) { 636 if (!(busack==Z80_REQ_BUSY || reset)) {
608 location &= 0x7FFF; 637 location &= 0x7FFF;
609 if (location < 0x4000) { 638 if (location < 0x4000) {
610 context->value = z80_ram[location & 0x1FFF]; 639 value = z80_ram[location & 0x1FFF];
611 } else if (location < 0x6000) { 640 } else if (location < 0x6000) {
612 ym_run(gen->ym, context->current_cycle); 641 ym_run(gen->ym, context->current_cycle);
613 context->value = ym_read_status(gen->ym); 642 value = ym_read_status(gen->ym);
614 } else { 643 } else {
615 context->value = 0xFF; 644 value = 0xFF;
616 } 645 }
617 } else { 646 } else {
618 context->value = 0xFF; 647 value = 0xFF;
648 }
649 } else {
650 location &= 0x1FFF;
651 if (location < 0x100) {
652 switch(location/2)
653 {
654 case 0x0:
655 //version bits should be 0 for now since we're not emulating TMSS
656 value = version_reg;
657 break;
658 case 0x1:
659 value = io_data_read(&gamepad_1, context);
660 break;
661 case 0x2:
662 value = io_data_read(&gamepad_2, context);
663 break;
664 case 0x3://PORT C Data
665 break;
666 case 0x4:
667 value = gamepad_1.control;
668 break;
669 case 0x5:
670 value = gamepad_2.control;
671 break;
672 default:
673 value = 0xFF;
674 }
675 } else {
676 if (location == 0x1100) {
677 if (busack_cycle <= context->current_cycle) {
678 busack = new_busack;
679 busack_cycle = CYCLE_NEVER;
680 }
681 value = Z80_RES_BUSACK || busack;
682 dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d, busack: %d, busack_cycle %d)\n", value, context->current_cycle, reset, busack, busack_cycle);
683 } else if (location == 0x1200) {
684 value = !reset;
685 } else {
686 value = 0xFF;
687 printf("Byte read of unknown IO location: %X\n", location);
688 }
689 }
690 }
691 return value;
692 }
693
694 uint16_t io_read_w(uint32_t location, m68k_context * context)
695 {
696 uint16_t value;
697 genesis_context * gen = context->system;
698 if (location < 0x10000) {
699 if (busack_cycle <= context->current_cycle) {
700 busack = new_busack;
701 busack_cycle = CYCLE_NEVER;
702 }
703 if (!(busack==Z80_REQ_BUSY || reset)) {
704 location &= 0x7FFF;
705 if (location < 0x4000) {
706 value = z80_ram[location & 0x1FFE];
707 } else if (location < 0x6000) {
708 ym_run(gen->ym, context->current_cycle);
709 value = ym_read_status(gen->ym);
710 } else {
711 value = 0xFF;
712 }
713 value = value | (value << 8);
714 } else {
715 value = 0xFFFF;
619 } 716 }
620 } else { 717 } else {
621 location &= 0x1FFF; 718 location &= 0x1FFF;
622 if (location < 0x100) { 719 if (location < 0x100) {
623 switch(location/2) 720 switch(location/2)
624 { 721 {
625 case 0x0: 722 case 0x0:
626 //version bits should be 0 for now since we're not emulating TMSS 723 //version bits should be 0 for now since we're not emulating TMSS
627 //Not sure about the other bits 724 //Not sure about the other bits
628 context->value = version_reg; 725 value = version_reg;
629 break; 726 break;
630 case 0x1: 727 case 0x1:
631 io_data_read(&gamepad_1, context); 728 value = io_data_read(&gamepad_1, context);
632 break; 729 break;
633 case 0x2: 730 case 0x2:
634 io_data_read(&gamepad_2, context); 731 value = io_data_read(&gamepad_2, context);
635 break; 732 break;
636 case 0x3://PORT C Data 733 case 0x3://PORT C Data
637 break; 734 break;
638 case 0x4: 735 case 0x4:
639 context->value = gamepad_1.control; 736 value = gamepad_1.control;
640 break; 737 break;
641 case 0x5: 738 case 0x5:
642 context->value = gamepad_2.control; 739 value = gamepad_2.control;
643 break; 740 break;
644 } 741 case 0x6:
742 //PORT C Control
743 value = 0;
744 break;
745 default:
746 value = 0;
747 }
748 value = value | (value << 8);
749 //printf("Word read to %X returned %d\n", location, value);
645 } else { 750 } else {
646 if (location == 0x1100) { 751 if (location == 0x1100) {
647 if (busack_cycle <= context->current_cycle) { 752 if (busack_cycle <= context->current_cycle) {
648 busack = new_busack; 753 busack = new_busack;
649 busack_cycle = CYCLE_NEVER; 754 busack_cycle = CYCLE_NEVER;
650 } 755 }
651 context->value = Z80_RES_BUSACK || busack; 756 value = (Z80_RES_BUSACK || busack) << 8;
652 dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d, busack: %d, busack_cycle %d)\n", context->value, context->current_cycle, reset, busack, busack_cycle); 757 //printf("Word read of BUSREQ returned %d\n", value);
653 } else if (location == 0x1200) { 758 } else if (location == 0x1200) {
654 context->value = !reset; 759 value = (!reset) << 8;
655 } else {
656 printf("Byte read of unknown IO location: %X\n", location);
657 }
658 }
659 }
660 return context;
661 }
662
663 m68k_context * io_read_w(uint32_t location, m68k_context * context)
664 {
665 genesis_context * gen = context->system;
666 if (location < 0x10000) {
667 if (busack_cycle <= context->current_cycle) {
668 busack = new_busack;
669 busack_cycle = CYCLE_NEVER;
670 }
671 if (!(busack==Z80_REQ_BUSY || reset)) {
672 location &= 0x7FFF;
673 uint16_t value;
674 if (location < 0x4000) {
675 value = z80_ram[location & 0x1FFE];
676 } else if (location < 0x6000) {
677 ym_run(gen->ym, context->current_cycle);
678 value = ym_read_status(gen->ym);
679 } else {
680 value = 0xFF;
681 }
682 context->value = value | (value << 8);
683 } else {
684 context->value = 0xFFFF;
685 }
686 } else {
687 location &= 0x1FFF;
688 if (location < 0x100) {
689 switch(location/2)
690 {
691 case 0x0:
692 //version bits should be 0 for now since we're not emulating TMSS
693 //Not sure about the other bits
694 context->value = 0;
695 break;
696 case 0x1:
697 io_data_read(&gamepad_1, context);
698 break;
699 case 0x2:
700 io_data_read(&gamepad_2, context);
701 break;
702 case 0x3://PORT C Data
703 break;
704 case 0x4:
705 context->value = gamepad_1.control;
706 break;
707 case 0x5:
708 context->value = gamepad_2.control;
709 break;
710 case 0x6:
711 //PORT C Control
712 context->value = 0;
713 break;
714 }
715 context->value = context->value | (context->value << 8);
716 //printf("Word read to %X returned %d\n", location, context->value);
717 } else {
718 if (location == 0x1100) {
719 if (busack_cycle <= context->current_cycle) {
720 busack = new_busack;
721 busack_cycle = CYCLE_NEVER;
722 }
723 context->value = (Z80_RES_BUSACK || busack) << 8;
724 //printf("Word read of BUSREQ returned %d\n", context->value);
725 } else if (location == 0x1200) {
726 context->value = (!reset) << 8;
727 } else { 760 } else {
728 printf("Word read of unknown IO location: %X\n", location); 761 printf("Word read of unknown IO location: %X\n", location);
729 } 762 }
730 } 763 }
731 } 764 }
732 return context; 765 return value;
733 } 766 }
734 767
735 z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value) 768 z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value)
736 { 769 {
737 genesis_context * gen = context->system; 770 genesis_context * gen = context->system;
998 void init_run_cpu(genesis_context * gen, int debug, FILE * address_log) 1031 void init_run_cpu(genesis_context * gen, int debug, FILE * address_log)
999 { 1032 {
1000 m68k_context context; 1033 m68k_context context;
1001 x86_68k_options opts; 1034 x86_68k_options opts;
1002 gen->m68k = &context; 1035 gen->m68k = &context;
1003 init_x86_68k_opts(&opts); 1036 memmap_chunk memmap[] = {
1037 {0, 0x400000, 0xFFFFFF, 0, MMAP_READ | MMAP_WRITE, cart,
1038 NULL, NULL, NULL, NULL},
1039 {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram,
1040 NULL, NULL, NULL, NULL},
1041 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, NULL,
1042 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write,
1043 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
1044 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, NULL,
1045 (read_16_fun)io_read_w, (write_16_fun)io_write_w,
1046 (read_8_fun)io_read, (write_8_fun)io_write}
1047 };
1048 init_x86_68k_opts(&opts, memmap, sizeof(memmap)/sizeof(memmap_chunk));
1004 opts.address_log = address_log; 1049 opts.address_log = address_log;
1005 init_68k_context(&context, opts.native_code_map, &opts); 1050 init_68k_context(&context, opts.native_code_map, &opts);
1006 1051
1007 context.video_context = gen->vdp; 1052 context.video_context = gen->vdp;
1008 context.system = gen; 1053 context.system = gen;
1066 return cart[REGION_START/2] & 0xFF == region || (cart[REGION_START/2]) >> 8 == region || cart[REGION_START/2+1] & 0xFF == region; 1111 return cart[REGION_START/2] & 0xFF == region || (cart[REGION_START/2]) >> 8 == region || cart[REGION_START/2+1] & 0xFF == region;
1067 } 1112 }
1068 1113
1069 void detect_region() 1114 void detect_region()
1070 { 1115 {
1071 if (detect_specific_region('U')) { 1116 if (detect_specific_region('U')|| detect_specific_region('B') || detect_specific_region('4')) {
1072 version_reg = NO_DISK | USA; 1117 version_reg = NO_DISK | USA;
1073 } else if (detect_specific_region('J')) { 1118 } else if (detect_specific_region('J')) {
1074 version_reg = NO_DISK | JAP; 1119 version_reg = NO_DISK | JAP;
1075 } if (detect_specific_region('E') || detect_specific_region('A') || detect_specific_region('B') || detect_specific_region('4')) { 1120 } else if (detect_specific_region('E') || detect_specific_region('A')) {
1076 version_reg = NO_DISK | EUR; 1121 version_reg = NO_DISK | EUR;
1077 } 1122 }
1078 } 1123 }
1079 1124
1080 int main(int argc, char ** argv) 1125 int main(int argc, char ** argv)