# HG changeset patch # User Michael Pavone # Date 1648281287 25200 # Node ID 10e4439d8f13446cea2b3a308e536a4a10990453 # Parent 67f20f9188b0fb04e4dec6f4da30dcb2f77ca60f Fix speed of CDC to PCM RAM DMA diff -r 67f20f9188b0 -r 10e4439d8f13 lc8951.c --- a/lc8951.c Fri Mar 25 21:41:33 2022 -0700 +++ b/lc8951.c Sat Mar 26 00:54:47 2022 -0700 @@ -85,11 +85,22 @@ //unclear if the difference is in the lc8951 or gate array context->regs[IFSTAT] = 0xFF; context->ar_mask = 0x1F; - context->clock_step = (2 + 2) * 6; // external divider, internal divider + DMA period + context->clock_step = (2 + 2); // external divider, internal divider + context->cycles_per_byte = context->clock_step * 6; context->byte_handler = byte_handler; context->handler_data = handler_data; context->decode_end = CYCLE_NEVER; context->transfer_end = CYCLE_NEVER; + context->next_byte_cycle = CYCLE_NEVER; +} + +void lc8951_set_dma_multiple(lc8951 *context, uint32_t multiple) +{ + context->cycles_per_byte = context->clock_step * multiple; + if (context->transfer_end != CYCLE_NEVER) { + uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8); + context->transfer_end = context->next_byte_cycle + transfer_size * context->cycles_per_byte; + } } void lc8951_reg_write(lc8951 *context, uint8_t value) @@ -130,7 +141,8 @@ if (context->ifctrl & BIT_DOUTEN) { context->regs[IFSTAT] &= ~BIT_DTBSY; uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8); - context->transfer_end = context->cycle + transfer_size * context->clock_step; + context->transfer_end = context->cycle + transfer_size * context->cycles_per_byte; + context->next_byte_cycle = context->cycle; printf("DTTRG: size %u, cycle %u, end %u\n", transfer_size, context->cycle, context->transfer_end); } break; @@ -251,8 +263,9 @@ } context->regs[STAT3] |= BIT_WLONG; } - if (context->transfer_end != CYCLE_NEVER) { + if (context->cycle >= context->next_byte_cycle) { if (context->byte_handler(context->handler_data, context->buffer[context->dac & (sizeof(context->buffer)-1)])) { + context->next_byte_cycle += context->cycles_per_byte; context->dac++; context->regs[DBCL]--; if (context->regs[DBCL] == 0xFF) { @@ -264,10 +277,12 @@ printf("Expected transfer end at %u but ended at %u\n", context->transfer_end, context->cycle); } context->transfer_end = CYCLE_NEVER; + context->next_byte_cycle = CYCLE_NEVER; } } } else { // pause transfer + context->next_byte_cycle = CYCLE_NEVER; context->transfer_end = CYCLE_NEVER; } } @@ -284,7 +299,8 @@ if (step_diff) { context->cycle -= step_diff * context->clock_step; } - context->transfer_end = context->cycle + transfer_size * context->clock_step; + context->transfer_end = context->cycle + transfer_size * context->cycles_per_byte; + context->next_byte_cycle = context->cycle; if (step_diff) { lc8951_run(context, cycle); } diff -r 67f20f9188b0 -r 10e4439d8f13 lc8951.h --- a/lc8951.h Fri Mar 25 21:41:33 2022 -0700 +++ b/lc8951.h Sat Mar 26 00:54:47 2022 -0700 @@ -10,8 +10,10 @@ void *handler_data; uint32_t cycle; uint32_t clock_step; + uint32_t cycles_per_byte; uint32_t decode_end; uint32_t transfer_end; + uint32_t next_byte_cycle; uint16_t sector_counter; uint8_t buffer[0x4000]; @@ -31,6 +33,7 @@ } lc8951; void lc8951_init(lc8951 *context, lcd8951_byte_recv_fun byte_handler, void *handler_data); +void lc8951_set_dma_multiple(lc8951 *context, uint32_t multiple); void lc8951_run(lc8951 *context, uint32_t cycle); void lc8951_reg_write(lc8951 *context, uint8_t value); uint8_t lc8951_reg_read(lc8951 *context); diff -r 67f20f9188b0 -r 10e4439d8f13 segacd.c --- a/segacd.c Fri Mar 25 21:41:33 2022 -0700 +++ b/segacd.c Sat Mar 26 00:54:47 2022 -0700 @@ -741,15 +741,29 @@ } break; } - case GA_CDC_CTRL: + case GA_CDC_CTRL: { cdd_run(cd, m68k->current_cycle); lc8951_ar_write(&cd->cdc, value); //cd->gate_array[reg] &= 0xC000; + uint16_t old_dest = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7; //apparently this clears EDT, should it also clear DSR? cd->gate_array[reg] = value & 0x0700; + uint16_t dest = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7; + if (dest != old_dest) { + if (dest == DST_PCM_RAM) { + lc8951_set_dma_multiple(&cd->cdc, 21); + } else { + lc8951_set_dma_multiple(&cd->cdc, 6); + } + if ((old_dest < DST_MAIN_CPU || old_dest == 6) && dest >= DST_MAIN_CPU && dest != 6) { + lc8951_resume_transfer(&cd->cdc, m68k->current_cycle); + } + calculate_target_cycle(m68k); + } cd->gate_array[GA_CDC_DMA_ADDR] = 0; cd->cdc_dst_low = 0; break; + } case GA_CDC_REG_DATA: cdd_run(cd, m68k->current_cycle); printf("CDC write %X: %X @ %u\n", cd->cdc.ar, value, m68k->current_cycle); @@ -1012,6 +1026,7 @@ cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3; break; default: + return 0; printf("Invalid CDC transfer destination %d\n", dest); } return 1;