# HG changeset patch # User Michael Pavone # Date 1643530918 28800 # Node ID a61a8a87410c3b04a86406180f28b7bff2097b64 # Parent 02a9846668d1a2cacd3f506a191527a7b8c2c55f Fix a bunch of CDC/CDD related mcd-verificator failures diff -r 02a9846668d1 -r a61a8a87410c lc8951.c --- a/lc8951.c Sat Jan 29 17:43:37 2022 -0800 +++ b/lc8951.c Sun Jan 30 00:21:58 2022 -0800 @@ -60,6 +60,8 @@ //STAT3 #define BIT_VALST 0x80 +#define DECI_AUTO_CLEAR 575 + //datasheet timing info //3 cycles for memory operation //6 cycles min for DMA-mode host transfer @@ -75,11 +77,11 @@ context->handler_data = handler_data; context->decode_end = CYCLE_NEVER; context->transfer_end = CYCLE_NEVER; + context->deci_clear = CYCLE_NEVER; } void lc8951_reg_write(lc8951 *context, uint8_t value) { - printf("CDC write %X: %X\n", context->ar, value); switch (context->ar) { case SBOUT: @@ -94,7 +96,7 @@ context->regs[IFSTAT] |= BIT_STBSY; } if (!(value & BIT_DOUTEN)) { - context->regs[IFSTAT] |= BIT_DTBSY; + context->regs[IFSTAT] |= BIT_DTBSY|BIT_DTEI; context->transfer_end = CYCLE_NEVER; } break; @@ -173,6 +175,7 @@ } if (context->ar == STAT3) { context->regs[IFSTAT] |= BIT_DECI; + context->deci_clear = CYCLE_NEVER; } if (context->ar >= sizeof(context->regs)) { value = 0xFF; @@ -203,6 +206,7 @@ if (context->cycle >= context->decode_end) { context->decode_end = CYCLE_NEVER; context->regs[IFSTAT] &= ~BIT_DECI; + context->deci_clear = context->cycle + DECI_AUTO_CLEAR; context->regs[STAT3] &= ~BIT_VALST; uint16_t block_start = (context->regs[PTL] | (context->regs[PTH] << 8)) & (sizeof(context->buffer)-1); for (int reg = HEAD0; reg < PTL; reg++) @@ -233,16 +237,28 @@ context->transfer_end = CYCLE_NEVER; } } + if (context->cycle >= context->deci_clear) { + context->regs[IFSTAT] |= BIT_DECI; + context->deci_clear = CYCLE_NEVER; + } } } -void lc8951_resume_transfer(lc8951 *context) +void lc8951_resume_transfer(lc8951 *context, uint32_t cycle) { if (context->transfer_end == CYCLE_NEVER && (context->ifctrl & BIT_DOUTEN)) { uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8); - if (transfer_size) { + if (transfer_size != 0xFFFF) { + //HACK!!! Work around Sub CPU running longer than we would like and dragging other components with it + uint32_t step_diff = (context->cycle - cycle) / context->clock_step; + if (step_diff) { + context->cycle -= step_diff * context->clock_step; + } 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); + if (step_diff) { + lc8951_run(context, cycle); + } } } } @@ -297,3 +313,16 @@ } return deci_cycle < dtei_cycle ? deci_cycle : dtei_cycle; } + +void lc8951_adjust_cycles(lc8951 *context, uint32_t deduction) +{ + if (context->decode_end != CYCLE_NEVER) { + context->decode_end -= deduction; + } + if (context->transfer_end != CYCLE_NEVER) { + context->transfer_end -= deduction; + } + if (context->deci_clear != CYCLE_NEVER) { + context->transfer_end -= deduction; + } +} diff -r 02a9846668d1 -r a61a8a87410c lc8951.h --- a/lc8951.h Sat Jan 29 17:43:37 2022 -0800 +++ b/lc8951.h Sun Jan 30 00:21:58 2022 -0800 @@ -12,6 +12,7 @@ uint32_t clock_step; uint32_t decode_end; uint32_t transfer_end; + uint32_t deci_clear; uint8_t buffer[0x4000]; @@ -37,6 +38,7 @@ void lc8951_ar_write(lc8951 *context, uint8_t value); void lc8951_write_byte(lc8951 *context, uint32_t cycle, int sector_offset, uint8_t byte); uint32_t lc8951_next_interrupt(lc8951 *context); -void lc8951_resume_transfer(lc8951 *context); +void lc8951_resume_transfer(lc8951 *context, uint32_t cycle); +void lc8951_adjust_cycles(lc8951 *context, uint32_t deduction); #endif //LC8951_H_ diff -r 02a9846668d1 -r a61a8a87410c segacd.c --- a/segacd.c Sat Jan 29 17:43:37 2022 -0800 +++ b/segacd.c Sun Jan 30 00:21:58 2022 -0800 @@ -332,6 +332,14 @@ if (mask < 5) { if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN5) { uint32_t cdc_cycle = lc8951_next_interrupt(&cd->cdc); + //CDC interrupts only generated on falling edge of !INT signal + if (cd->cdc_int_ack) { + if (cdc_cycle > cd->cdc.cycle) { + cd->cdc_int_ack = 0; + } else { + cdc_cycle = CYCLE_NEVER; + } + } if (cdc_cycle < context->int_cycle) { context->int_cycle = cdc_cycle; context->int_num = 5; @@ -401,18 +409,17 @@ cdd_run(cd, m68k->current_cycle); return lc8951_reg_read(&cd->cdc); case GA_CDC_HOST_DATA: { + cdd_run(cd, m68k->current_cycle); 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); + lc8951_resume_transfer(&cd->cdc, cd->cdc.cycle); } calculate_target_cycle(cd->m68k); - return cd->gate_array[reg]; - } else { - return 0xFFFF; + } + return cd->gate_array[reg]; } case GA_STOP_WATCH: case GA_TIMER: @@ -527,11 +534,14 @@ case GA_CDC_CTRL: cdd_run(cd, m68k->current_cycle); lc8951_ar_write(&cd->cdc, value); - cd->gate_array[reg] &= 0xC000; + //cd->gate_array[reg] &= 0xC000; + //apparently this clears EDT, should it also clear DSR? cd->gate_array[reg] = value & 0x0700; + 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); lc8951_reg_write(&cd->cdc, value); calculate_target_cycle(m68k); break; @@ -630,10 +640,11 @@ case GA_CDC_CTRL: if (address & 1) { lc8951_ar_write(&cd->cdc, value); + return vcontext; } else { - cd->gate_array[reg] = value << 8; + value16 = cd->cdc.ar | (value << 8); } - return vcontext; + break; case GA_CDD_CMD4: if (!address) { //byte write to $FF804A should not trigger transfer @@ -656,39 +667,48 @@ static uint8_t handle_cdc_byte(void *vsys, uint8_t value) { segacd_context *cd = vsys; + if (cd->gate_array[GA_CDC_CTRL] & BIT_DSR) { + //host reg is already full, pause transfer + return 0; + } + if (cd->cdc.cycle == cd->cdc.transfer_end) { + cd->gate_array[GA_CDC_CTRL] |= BIT_EDT; + printf("EDT set at %u\n", cd->cdc.cycle); + } uint16_t dest = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7; + if (!(cd->cdc_dst_low & 1)) { + cd->gate_array[GA_CDC_HOST_DATA] &= 0xFF; + cd->gate_array[GA_CDC_HOST_DATA] |= value << 8; + cd->cdc_dst_low++; + if (dest != DST_PCM_RAM) { + //PCM RAM writes a byte at a time + return 1; + } + } else { + cd->gate_array[GA_CDC_HOST_DATA] &= 0xFF00; + cd->gate_array[GA_CDC_HOST_DATA] |= value; + } + 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; - } + cd->cdc_dst_low = 0; + cd->gate_array[GA_CDC_CTRL] |= BIT_DSR; + printf("DSR set at %u, (transfer_end %u, dbcl %X, dbch %X)\n", cd->cdc.cycle, cd->cdc.transfer_end, cd->cdc.regs[2], cd->cdc.regs[3]); break; case DST_PCM_RAM: dma_addr &= (1 << 13) - 1; //TODO: write to currently visible 8K bank of PCM RAM I guess? - dma_addr++; + dma_addr += 2; 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); + cd->prog_ram[dma_addr >> 1] = cd->gate_array[GA_CDC_HOST_DATA]; + m68k_invalidate_code_range(cd->m68k, dma_addr - 1, dma_addr + 1); dma_addr++; cd->cdc_dst_low = dma_addr & 7; cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3; @@ -697,13 +717,13 @@ 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); + cd->m68k->mem_pointers[1][dma_addr >> 1] = cd->gate_array[GA_CDC_HOST_DATA]; + m68k_invalidate_code_range(cd->m68k, 0x0C0000 + dma_addr - 1, 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; + cd->word_ram[dma_addr >> 1] = cd->gate_array[GA_CDC_HOST_DATA]; m68k_invalidate_code_range(cd->m68k, 0x080000 + dma_addr, 0x080000 + dma_addr + 1); } } @@ -714,9 +734,6 @@ 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; } @@ -746,6 +763,10 @@ break; case 4: cd->cdd.int_pending = 0; + break; + case 5: + cd->cdc_int_ack = 1; + break; } context->int_ack = 0; calculate_target_cycle(context); @@ -755,17 +776,20 @@ void scd_run(segacd_context *cd, uint32_t cycle) { uint8_t m68k_run = !can_main_access_prog(cd); - if (m68k_run) { - cd->m68k->sync_cycle = cycle; - if (cd->need_reset) { - cd->need_reset = 0; - m68k_reset(cd->m68k); + if (cycle > cd->m68k->current_cycle) { + if (m68k_run) { + uint32_t start = cd->m68k->current_cycle; + cd->m68k->sync_cycle = cycle; + if (cd->need_reset) { + cd->need_reset = 0; + m68k_reset(cd->m68k); + } else { + calculate_target_cycle(cd->m68k); + resume_68k(cd->m68k); + } } else { - calculate_target_cycle(cd->m68k); - resume_68k(cd->m68k); + cd->m68k->current_cycle = cycle; } - } else { - cd->m68k->current_cycle = cycle; } scd_peripherals_run(cd, cycle); } @@ -791,6 +815,7 @@ cd->periph_reset_cycle -= deduction; } cdd_mcu_adjust_cycle(&cd->cdd, deduction); + lc8951_adjust_cycles(&cd->cdc, deduction); } static uint16_t main_gate_read16(uint32_t address, void *vcontext) @@ -828,20 +853,26 @@ 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) { + printf("DSR cleared at %u (%u)\n", scd_cycle, cd->cdc.cycle); cd->gate_array[GA_CDC_CTRL] &= ~BIT_DSR; - lc8951_resume_transfer(&cd->cdc); + lc8951_resume_transfer(&cd->cdc, scd_cycle); + } else { + printf("Read of CDC host data with DSR clear at %u\n", scd_cycle); } calculate_target_cycle(cd->m68k); - return cd->gate_array[offset]; - } else { - return 0xFFFF; } + return cd->gate_array[offset]; } case GA_CDC_DMA_ADDR: //TODO: open bus maybe? return 0xFFFF; default: if (offset < GA_TIMER) { + if (offset == GA_CDC_CTRL) { + printf("CDC read(main): %X - %X @ %u (%u)\n", address, cd->gate_array[offset], m68k->current_cycle, scd_cycle); + } else if (offset >= GA_COMM_FLAG && offset <= GA_COMM_STATUS7) { + printf("COMM read(main): %X - %X @ %u (%u)\n", address, cd->gate_array[offset], m68k->current_cycle, scd_cycle); + } return cd->gate_array[offset]; } //TODO: open bus maybe? @@ -929,6 +960,7 @@ //Main CPU can only write the upper byte; cd->gate_array[reg] &= 0xFF; cd->gate_array[reg] |= value & 0xFF00; + printf("COMM write(main): %X - %X @ %u (%u)\n", address, value, m68k->current_cycle, scd_cycle); break; case GA_COMM_CMD0: case GA_COMM_CMD1: @@ -939,6 +971,7 @@ case GA_COMM_CMD6: case GA_COMM_CMD7: //no effects for these other than saving the value + printf("COMM write(main): %X - %X @ %u (%u)\n", address, value, m68k->current_cycle, scd_cycle); cd->gate_array[reg] = value; break; default: diff -r 02a9846668d1 -r a61a8a87410c segacd.h --- a/segacd.h Sat Jan 29 17:43:37 2022 -0800 +++ b/segacd.h Sun Jan 30 00:21:58 2022 -0800 @@ -30,6 +30,7 @@ lc8951 cdc; cdd_mcu cdd; uint8_t cdc_dst_low; + uint8_t cdc_int_ack; } segacd_context; segacd_context *alloc_configure_segacd(system_media *media, uint32_t opts, uint8_t force_region, rom_info *info);