Mercurial > repos > blastem
diff lc8951.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/lc8951.c Fri Jan 28 22:48:06 2022 -0800 +++ b/lc8951.c Sat Jan 29 17:43:37 2022 -0800 @@ -64,13 +64,17 @@ //3 cycles for memory operation //6 cycles min for DMA-mode host transfer -void lc8951_init(lc8951 *context) +void lc8951_init(lc8951 *context, lcd8951_byte_recv_fun byte_handler, void *handler_data) { //This seems to vary somewhat between Sega CD models //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->byte_handler = byte_handler; + context->handler_data = handler_data; + context->decode_end = CYCLE_NEVER; + context->transfer_end = CYCLE_NEVER; } void lc8951_reg_write(lc8951 *context, uint8_t value) @@ -91,6 +95,7 @@ } if (!(value & BIT_DOUTEN)) { context->regs[IFSTAT] |= BIT_DTBSY; + context->transfer_end = CYCLE_NEVER; } break; case DBCL: @@ -108,10 +113,11 @@ context->dac |= value << 8; break; case DTTRG: - if (value & BIT_DOUTEN) { + 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; + printf("DTTRG: size %u, cycle %u, end %u\n", transfer_size, context->cycle, context->transfer_end); } break; case DTACK: @@ -208,23 +214,39 @@ printf("Decode done %X:%X:%X mode %X\n", context->regs[HEAD0], context->regs[HEAD1], context->regs[HEAD2], context->regs[HEAD3]); } if (context->transfer_end != CYCLE_NEVER) { - //TODO: transfer byte to gate array destination - context->dac++; - context->regs[DBCL]--; - if (!context->regs[DBCL]) { - context->regs[DBCH]--; - if (!context->regs[DBCH]) { - context->regs[IFSTAT] &= ~BIT_DTEI; - if (context->cycle != context->transfer_end) { - printf("Expected transfer end at %u but ended at %u\n", context->transfer_end, context->cycle); + if (context->byte_handler(context->handler_data, context->buffer[context->dac & (sizeof(context->buffer)-1)])) { + context->dac++; + context->regs[DBCL]--; + if (context->regs[DBCL] == 0xFF) { + context->regs[DBCH]--; + if (context->regs[DBCH] == 0xFF) { + context->regs[IFSTAT] &= ~BIT_DTEI; + context->regs[IFSTAT] |= BIT_DTBSY; + if (context->cycle != context->transfer_end) { + printf("Expected transfer end at %u but ended at %u\n", context->transfer_end, context->cycle); + } + context->transfer_end = CYCLE_NEVER; } - context->transfer_end = CYCLE_NEVER; } + } else { + // pause transfer + context->transfer_end = CYCLE_NEVER; } } } } +void lc8951_resume_transfer(lc8951 *context) +{ + if (context->transfer_end == CYCLE_NEVER && (context->ifctrl & BIT_DOUTEN)) { + uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8); + if (transfer_size) { + context->transfer_end = context->cycle + transfer_size * context->clock_step; + printf("RESUME: size %u, cycle %u, end %u\n", transfer_size, context->cycle, context->transfer_end); + } + } +} + void lc8951_write_byte(lc8951 *context, uint32_t cycle, int sector_offset, uint8_t byte) { lc8951_run(context, cycle); @@ -251,7 +273,6 @@ } } if ((context->ctrl0 & (BIT_DECEN|BIT_WRRQ)) == (BIT_DECEN|BIT_WRRQ)) { - printf("lc8951_write_byte: %X - [%X] = %X\n", sector_offset, current_write_addr, byte); context->buffer[current_write_addr & (sizeof(context->buffer)-1)] = byte; context->regs[WAL]++; if (!context->regs[WAL]) { @@ -262,7 +283,7 @@ uint32_t lc8951_next_interrupt(lc8951 *context) { - if ((!context->regs[IFSTAT]) & context->ifctrl & (BIT_CMDI|BIT_DTEI|BIT_DECI)) { + if ((~context->regs[IFSTAT]) & context->ifctrl & (BIT_CMDI|BIT_DTEI|BIT_DECI)) { //interrupt already pending return context->cycle; }