Mercurial > repos > blastem
comparison segacd.c @ 2065:02a9846668d1 segacd
Implement transfer of data from CDC to elsewhere. Other miscellaneous CDD/CDC improvements
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 29 Jan 2022 17:43:37 -0800 |
parents | 07ed42bd7b4c |
children | a61a8a87410c |
comparison
equal
deleted
inserted
replaced
2064:91e4d2fe5cd9 | 2065:02a9846668d1 |
---|---|
71 #define MASK_PRIORITY (BIT_OVERWRITE|BIT_UNDERWRITE) | 71 #define MASK_PRIORITY (BIT_OVERWRITE|BIT_UNDERWRITE) |
72 #define BIT_MEM_MODE 0x0004 | 72 #define BIT_MEM_MODE 0x0004 |
73 #define BIT_DMNA 0x0002 | 73 #define BIT_DMNA 0x0002 |
74 #define BIT_RET 0x0001 | 74 #define BIT_RET 0x0001 |
75 | 75 |
76 //GA_CDC_CTRL | |
77 #define BIT_EDT 0x8000 | |
78 #define BIT_DSR 0x4000 | |
79 | |
80 enum { | |
81 DST_MAIN_CPU = 2, | |
82 DST_SUB_CPU, | |
83 DST_PCM_RAM, | |
84 DST_PROG_RAM, | |
85 DST_WORD_RAM = 7 | |
86 }; | |
87 | |
76 //GA_INT_MASK | 88 //GA_INT_MASK |
77 #define BIT_MASK_IEN1 0x0002 | 89 #define BIT_MASK_IEN1 0x0002 |
78 #define BIT_MASK_IEN2 0x0004 | 90 #define BIT_MASK_IEN2 0x0004 |
79 #define BIT_MASK_IEN3 0x0008 | 91 #define BIT_MASK_IEN3 0x0008 |
80 #define BIT_MASK_IEN4 0x0010 | 92 #define BIT_MASK_IEN4 0x0010 |
381 return value; | 393 return value; |
382 } | 394 } |
383 case GA_MEM_MODE: | 395 case GA_MEM_MODE: |
384 return cd->gate_array[reg] & 0xFF1F; | 396 return cd->gate_array[reg] & 0xFF1F; |
385 case GA_CDC_CTRL: | 397 case GA_CDC_CTRL: |
398 cdd_run(cd, m68k->current_cycle); | |
386 return cd->gate_array[reg] | cd->cdc.ar; | 399 return cd->gate_array[reg] | cd->cdc.ar; |
387 case GA_CDC_REG_DATA: | 400 case GA_CDC_REG_DATA: |
388 cdd_run(cd, m68k->current_cycle); | 401 cdd_run(cd, m68k->current_cycle); |
389 return lc8951_reg_read(&cd->cdc); | 402 return lc8951_reg_read(&cd->cdc); |
403 case GA_CDC_HOST_DATA: { | |
404 uint16_t dst = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7; | |
405 if (dst == DST_SUB_CPU) { | |
406 cdd_run(cd, m68k->current_cycle); | |
407 if (cd->gate_array[GA_CDC_CTRL] & BIT_DSR) { | |
408 cd->gate_array[GA_CDC_CTRL] &= ~BIT_DSR; | |
409 lc8951_resume_transfer(&cd->cdc); | |
410 } | |
411 calculate_target_cycle(cd->m68k); | |
412 return cd->gate_array[reg]; | |
413 } else { | |
414 return 0xFFFF; | |
415 } | |
416 } | |
390 case GA_STOP_WATCH: | 417 case GA_STOP_WATCH: |
391 case GA_TIMER: | 418 case GA_TIMER: |
392 timers_run(cd, m68k->current_cycle); | 419 timers_run(cd, m68k->current_cycle); |
393 return cd->gate_array[reg]; | 420 return cd->gate_array[reg]; |
394 case GA_CDD_STATUS0: | 421 case GA_CDD_STATUS0: |
506 case GA_CDC_REG_DATA: | 533 case GA_CDC_REG_DATA: |
507 cdd_run(cd, m68k->current_cycle); | 534 cdd_run(cd, m68k->current_cycle); |
508 lc8951_reg_write(&cd->cdc, value); | 535 lc8951_reg_write(&cd->cdc, value); |
509 calculate_target_cycle(m68k); | 536 calculate_target_cycle(m68k); |
510 break; | 537 break; |
538 case GA_CDC_DMA_ADDR: | |
539 cdd_run(cd, m68k->current_cycle); | |
540 cd->gate_array[reg] = value; | |
541 cd->cdc_dst_low = 0; | |
542 break; | |
511 case GA_STOP_WATCH: | 543 case GA_STOP_WATCH: |
512 //docs say you should only write zero to reset | 544 //docs say you should only write zero to reset |
513 //mcd-verificator comments suggest any value will reset | 545 //mcd-verificator comments suggest any value will reset |
514 timers_run(cd, m68k->current_cycle); | 546 timers_run(cd, m68k->current_cycle); |
515 cd->gate_array[reg] = 0; | 547 cd->gate_array[reg] = 0; |
619 } | 651 } |
620 } | 652 } |
621 return sub_gate_write16(address, vcontext, value16); | 653 return sub_gate_write16(address, vcontext, value16); |
622 } | 654 } |
623 | 655 |
656 static uint8_t handle_cdc_byte(void *vsys, uint8_t value) | |
657 { | |
658 segacd_context *cd = vsys; | |
659 uint16_t dest = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7; | |
660 uint32_t dma_addr = cd->gate_array[GA_CDC_DMA_ADDR] << 3; | |
661 dma_addr |= cd->cdc_dst_low; | |
662 switch (dest) | |
663 { | |
664 case DST_MAIN_CPU: | |
665 case DST_SUB_CPU: | |
666 if (cd->gate_array[GA_CDC_CTRL] & BIT_DSR) { | |
667 //host reg is already full, pause transfer | |
668 return 0; | |
669 } | |
670 if (cd->cdc_dst_low) { | |
671 cd->gate_array[GA_CDC_HOST_DATA] &= 0xFF00; | |
672 cd->gate_array[GA_CDC_HOST_DATA] |= value; | |
673 cd->cdc_dst_low = 0; | |
674 cd->gate_array[GA_CDC_CTRL] |= BIT_DSR; | |
675 } else { | |
676 cd->gate_array[GA_CDC_HOST_DATA] &= 0xFF; | |
677 cd->gate_array[GA_CDC_HOST_DATA] |= value << 8; | |
678 cd->cdc_dst_low = 1; | |
679 return 1; | |
680 } | |
681 break; | |
682 case DST_PCM_RAM: | |
683 dma_addr &= (1 << 13) - 1; | |
684 //TODO: write to currently visible 8K bank of PCM RAM I guess? | |
685 dma_addr++; | |
686 cd->cdc_dst_low = dma_addr & 7; | |
687 cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3; | |
688 break; | |
689 case DST_PROG_RAM: | |
690 ((uint8_t*)cd->prog_ram)[dma_addr ^ 1] = value; | |
691 m68k_invalidate_code_range(cd->m68k, dma_addr, dma_addr + 1); | |
692 dma_addr++; | |
693 cd->cdc_dst_low = dma_addr & 7; | |
694 cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3; | |
695 break; | |
696 case DST_WORD_RAM: | |
697 if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) { | |
698 //1M mode, write to bank assigned to Sub CPU | |
699 dma_addr &= (1 << 17) - 1; | |
700 ((uint8_t*)cd->m68k->mem_pointers[1])[dma_addr ^ 1] = value; | |
701 m68k_invalidate_code_range(cd->m68k, 0x0C0000 + dma_addr, 0x0C0000 + dma_addr + 1); | |
702 } else { | |
703 //2M mode, check if Sub CPU has access | |
704 if (!(cd->gate_array[GA_MEM_MODE] & BIT_RET)) { | |
705 dma_addr &= (1 << 18) - 1; | |
706 ((uint8_t*)cd->word_ram)[dma_addr ^ 1] = value; | |
707 m68k_invalidate_code_range(cd->m68k, 0x080000 + dma_addr, 0x080000 + dma_addr + 1); | |
708 } | |
709 } | |
710 dma_addr++; | |
711 cd->cdc_dst_low = dma_addr & 7; | |
712 cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3; | |
713 break; | |
714 default: | |
715 printf("Invalid CDC transfer destination %d\n", dest); | |
716 } | |
717 if (cd->cdc.cycle == cd->cdc.transfer_end) { | |
718 cd->gate_array[GA_CDC_CTRL] |= BIT_EDT; | |
719 } | |
720 return 1; | |
721 } | |
722 | |
624 static uint8_t can_main_access_prog(segacd_context *cd) | 723 static uint8_t can_main_access_prog(segacd_context *cd) |
625 { | 724 { |
626 //TODO: use actual busack | 725 //TODO: use actual busack |
627 return cd->busreq || !cd->reset; | 726 return cd->busreq || !cd->reset; |
628 } | 727 } |
723 case GA_MEM_MODE: | 822 case GA_MEM_MODE: |
724 //Main CPU can't read priority mode bits | 823 //Main CPU can't read priority mode bits |
725 return cd->gate_array[offset] & 0xFFE7; | 824 return cd->gate_array[offset] & 0xFFE7; |
726 case GA_HINT_VECTOR: | 825 case GA_HINT_VECTOR: |
727 return cd->rom_mut[0x72/2]; | 826 return cd->rom_mut[0x72/2]; |
827 case GA_CDC_HOST_DATA: { | |
828 uint16_t dst = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7; | |
829 if (dst == DST_MAIN_CPU) { | |
830 if (cd->gate_array[GA_CDC_CTRL] & BIT_DSR) { | |
831 cd->gate_array[GA_CDC_CTRL] &= ~BIT_DSR; | |
832 lc8951_resume_transfer(&cd->cdc); | |
833 } | |
834 calculate_target_cycle(cd->m68k); | |
835 return cd->gate_array[offset]; | |
836 } else { | |
837 return 0xFFFF; | |
838 } | |
839 } | |
728 case GA_CDC_DMA_ADDR: | 840 case GA_CDC_DMA_ADDR: |
729 //TODO: open bus maybe? | 841 //TODO: open bus maybe? |
730 return 0xFFFF; | 842 return 0xFFFF; |
731 default: | 843 default: |
732 if (offset < GA_TIMER) { | 844 if (offset < GA_TIMER) { |
925 cd->need_reset = 1; | 1037 cd->need_reset = 1; |
926 cd->reset = 1; //active low, so reset is not active on start | 1038 cd->reset = 1; //active low, so reset is not active on start |
927 cd->memptr_start_index = 0; | 1039 cd->memptr_start_index = 0; |
928 cd->gate_array[1] = 1; | 1040 cd->gate_array[1] = 1; |
929 cd->gate_array[0x1B] = 0x100; | 1041 cd->gate_array[0x1B] = 0x100; |
930 lc8951_init(&cd->cdc); | 1042 lc8951_init(&cd->cdc, handle_cdc_byte, cd); |
931 if (media->chain && media->type != MEDIA_CDROM) { | 1043 if (media->chain && media->type != MEDIA_CDROM) { |
932 media = media->chain; | 1044 media = media->chain; |
933 } | 1045 } |
934 cdd_mcu_init(&cd->cdd, media); | 1046 cdd_mcu_init(&cd->cdd, media); |
935 | 1047 |