Mercurial > repos > blastem
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) |