Mercurial > repos > blastem
diff 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 |
line wrap: on
line diff
--- a/segacd.c Fri Jan 28 22:48:06 2022 -0800 +++ b/segacd.c Sat Jan 29 17:43:37 2022 -0800 @@ -73,6 +73,18 @@ #define BIT_DMNA 0x0002 #define BIT_RET 0x0001 +//GA_CDC_CTRL +#define BIT_EDT 0x8000 +#define BIT_DSR 0x4000 + +enum { + DST_MAIN_CPU = 2, + DST_SUB_CPU, + DST_PCM_RAM, + DST_PROG_RAM, + DST_WORD_RAM = 7 +}; + //GA_INT_MASK #define BIT_MASK_IEN1 0x0002 #define BIT_MASK_IEN2 0x0004 @@ -383,10 +395,25 @@ case GA_MEM_MODE: return cd->gate_array[reg] & 0xFF1F; case GA_CDC_CTRL: + cdd_run(cd, m68k->current_cycle); return cd->gate_array[reg] | cd->cdc.ar; case GA_CDC_REG_DATA: cdd_run(cd, m68k->current_cycle); return lc8951_reg_read(&cd->cdc); + case GA_CDC_HOST_DATA: { + uint16_t dst = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7; + if (dst == DST_SUB_CPU) { + cdd_run(cd, m68k->current_cycle); + if (cd->gate_array[GA_CDC_CTRL] & BIT_DSR) { + cd->gate_array[GA_CDC_CTRL] &= ~BIT_DSR; + lc8951_resume_transfer(&cd->cdc); + } + calculate_target_cycle(cd->m68k); + return cd->gate_array[reg]; + } else { + return 0xFFFF; + } + } case GA_STOP_WATCH: case GA_TIMER: timers_run(cd, m68k->current_cycle); @@ -508,6 +535,11 @@ lc8951_reg_write(&cd->cdc, value); calculate_target_cycle(m68k); break; + case GA_CDC_DMA_ADDR: + cdd_run(cd, m68k->current_cycle); + cd->gate_array[reg] = value; + cd->cdc_dst_low = 0; + break; case GA_STOP_WATCH: //docs say you should only write zero to reset //mcd-verificator comments suggest any value will reset @@ -621,6 +653,73 @@ return sub_gate_write16(address, vcontext, value16); } +static uint8_t handle_cdc_byte(void *vsys, uint8_t value) +{ + segacd_context *cd = vsys; + uint16_t dest = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7; + uint32_t dma_addr = cd->gate_array[GA_CDC_DMA_ADDR] << 3; + dma_addr |= cd->cdc_dst_low; + switch (dest) + { + case DST_MAIN_CPU: + case DST_SUB_CPU: + if (cd->gate_array[GA_CDC_CTRL] & BIT_DSR) { + //host reg is already full, pause transfer + return 0; + } + if (cd->cdc_dst_low) { + cd->gate_array[GA_CDC_HOST_DATA] &= 0xFF00; + cd->gate_array[GA_CDC_HOST_DATA] |= value; + cd->cdc_dst_low = 0; + cd->gate_array[GA_CDC_CTRL] |= BIT_DSR; + } else { + cd->gate_array[GA_CDC_HOST_DATA] &= 0xFF; + cd->gate_array[GA_CDC_HOST_DATA] |= value << 8; + cd->cdc_dst_low = 1; + return 1; + } + break; + case DST_PCM_RAM: + dma_addr &= (1 << 13) - 1; + //TODO: write to currently visible 8K bank of PCM RAM I guess? + dma_addr++; + cd->cdc_dst_low = dma_addr & 7; + cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3; + break; + case DST_PROG_RAM: + ((uint8_t*)cd->prog_ram)[dma_addr ^ 1] = value; + m68k_invalidate_code_range(cd->m68k, dma_addr, dma_addr + 1); + dma_addr++; + cd->cdc_dst_low = dma_addr & 7; + cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3; + break; + case DST_WORD_RAM: + if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) { + //1M mode, write to bank assigned to Sub CPU + dma_addr &= (1 << 17) - 1; + ((uint8_t*)cd->m68k->mem_pointers[1])[dma_addr ^ 1] = value; + m68k_invalidate_code_range(cd->m68k, 0x0C0000 + dma_addr, 0x0C0000 + dma_addr + 1); + } else { + //2M mode, check if Sub CPU has access + if (!(cd->gate_array[GA_MEM_MODE] & BIT_RET)) { + dma_addr &= (1 << 18) - 1; + ((uint8_t*)cd->word_ram)[dma_addr ^ 1] = value; + m68k_invalidate_code_range(cd->m68k, 0x080000 + dma_addr, 0x080000 + dma_addr + 1); + } + } + dma_addr++; + cd->cdc_dst_low = dma_addr & 7; + cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3; + break; + default: + printf("Invalid CDC transfer destination %d\n", dest); + } + if (cd->cdc.cycle == cd->cdc.transfer_end) { + cd->gate_array[GA_CDC_CTRL] |= BIT_EDT; + } + return 1; +} + static uint8_t can_main_access_prog(segacd_context *cd) { //TODO: use actual busack @@ -725,6 +824,19 @@ return cd->gate_array[offset] & 0xFFE7; case GA_HINT_VECTOR: return cd->rom_mut[0x72/2]; + case GA_CDC_HOST_DATA: { + uint16_t dst = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7; + if (dst == DST_MAIN_CPU) { + if (cd->gate_array[GA_CDC_CTRL] & BIT_DSR) { + cd->gate_array[GA_CDC_CTRL] &= ~BIT_DSR; + lc8951_resume_transfer(&cd->cdc); + } + calculate_target_cycle(cd->m68k); + return cd->gate_array[offset]; + } else { + return 0xFFFF; + } + } case GA_CDC_DMA_ADDR: //TODO: open bus maybe? return 0xFFFF; @@ -927,7 +1039,7 @@ cd->memptr_start_index = 0; cd->gate_array[1] = 1; cd->gate_array[0x1B] = 0x100; - lc8951_init(&cd->cdc); + lc8951_init(&cd->cdc, handle_cdc_byte, cd); if (media->chain && media->type != MEDIA_CDROM) { media = media->chain; }