Mercurial > repos > blastem
diff cdd_mcu.c @ 2062:07ed42bd7b4c segacd
Some progress on CDC and CDD emulation. Now passes first 3 "CDC INIT" tests in mcd-verificator
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 28 Jan 2022 00:50:17 -0800 |
parents | 7c1760b5b3e5 |
children | 91e4d2fe5cd9 |
line wrap: on
line diff
--- a/cdd_mcu.c Thu Jan 27 00:33:41 2022 -0800 +++ b/cdd_mcu.c Fri Jan 28 00:50:17 2022 -0800 @@ -6,6 +6,7 @@ #define CDD_MCU_DIVIDER 8 #define SECTOR_CLOCKS (CD_BLOCK_CLKS/75) #define NIBBLE_CLOCKS (CDD_MCU_DIVIDER * 77) +#define BYTE_CLOCKS (SECTOR_CLOCKS/2352) // 96 //lead in start max diameter 46 mm //program area start max diameter 50 mm @@ -102,6 +103,24 @@ handle_seek(context); if (!context->seeking) { context->head_pba++; + uint32_t lba = context->head_pba - LEADIN_SECTORS; + for (uint32_t i = 0; i < context->media->num_tracks; i++) + { + if (lba < context->media->tracks[i].fake_pregap) { + context->in_fake_pregap = 1; + break; + } + lba -= context->media->tracks[i].fake_pregap; + if (lba < context->media->tracks[i].start_lba) { + context->in_fake_pregap = 1; + break; + } + if (lba < context->media->tracks[i].end_lba) { + fseek(context->media->f, lba * 2352, SEEK_SET); + context->in_fake_pregap = 0; + break; + } + } } break; case DS_PAUSE: @@ -115,7 +134,7 @@ if (context->head_pba > 3*context->media->num_tracks + 1) { context->toc_valid = 1; context->seeking = 1; - context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].start_lba + context->media->tracks[0].fake_pregap; + context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].start_lba; context->status = DS_PAUSE; } @@ -170,7 +189,7 @@ break; case SF_TOCO: if (context->toc_valid) { - lba_to_status(context, context->media->tracks[context->media->num_tracks - 1].end_lba + context->media->tracks[0].fake_pregap); + lba_to_status(context, context->media->tracks[context->media->num_tracks - 1].end_lba + (context->media->num_tracks > 1 ? context->media->tracks[1].fake_pregap : 0)); context->status_buffer.format = SF_TOCO; } else { context->status_buffer.format = SF_NOTREADY; @@ -190,7 +209,11 @@ break; case SF_TOCN: if (context->toc_valid) { - lba_to_status(context, context->media->tracks[context->requested_track].start_lba + context->media->tracks[0].fake_pregap); + uint32_t lba = context->media->tracks[context->requested_track - 1].start_lba; + if (context->requested_track > 1) { + lba += context->media->tracks[1].fake_pregap; + } + lba_to_status(context, lba); context->status_buffer.b.tocn.track_low = context->requested_track % 10; context->status_buffer.format = SF_TOCN; } else { @@ -213,7 +236,7 @@ } context->status_buffer.checksum = checksum((uint8_t *)&context->status_buffer); if (context->status_buffer.format != SF_NOTREADY) { - printf("CDD Status %d%d.%d%d%d%d%d%d.%d%d\n", + printf("CDD Status %X%X.%X%X%X%X%X%X.%X%X\n", context->status_buffer.status, context->status_buffer.format, context->status_buffer.b.time.min_high, context->status_buffer.b.time.min_low, context->status_buffer.b.time.sec_high, context->status_buffer.b.time.sec_low, @@ -242,6 +265,34 @@ puts("CDD CMD: STOP"); context->status = DS_STOP; break; + case CMD_READ: + case CMD_SEEK: { + if (context->status == DS_DOOR_OPEN || context->status == DS_TRAY_MOVING || context->status == DS_DISC_LEADOUT || context->status == DS_DISC_LEADIN) { + context->error_status = DS_CMD_ERROR; + break; + } + if (context->requested_format == SF_TOCT || context->requested_format == SF_TOCN) { + context->requested_format = SF_ABSOLUTE; + } + if (!context->toc_valid) { + context->error_status = DS_CMD_ERROR; + break; + } + uint32_t lba = context->cmd_buffer.b.time.min_high * 10 + context->cmd_buffer.b.time.min_low; + lba *= 60; + lba += context->cmd_buffer.b.time.sec_high * 10 + context->cmd_buffer.b.time.sec_low; + lba *= 75; + lba += context->cmd_buffer.b.time.frame_high * 10 + context->cmd_buffer.b.time.frame_low; + printf("READ/SEEK cmd for lba %d\n", lba); + if (lba >= context->media->tracks[0].fake_pregap + context->media->tracks[context->media->num_tracks - 1].end_lba) { + context->error_status = DS_CMD_ERROR; + break; + } + context->seek_pba = lba + LEADIN_SECTORS - 4; + context->seeking = 1; + context->status = context->cmd_buffer.cmd_type == CMD_READ ? DS_PLAY : DS_PAUSE; + break; + } case CMD_REPORT_REQUEST: switch (context->cmd_buffer.b.format.status_type) { @@ -275,6 +326,10 @@ case SF_TOCN: context->requested_track = context->cmd_buffer.b.format.track_high * 10; context->requested_track += context->cmd_buffer.b.format.track_low; + if (!context->media || context->requested_track > context->media->num_tracks) { + context->requested_format = SF_ABSOLUTE; + context->error_status = DS_CMD_ERROR; + } context->status = DS_TOC_READ; context->seeking = 1; context->seek_pba = 0; @@ -292,7 +347,7 @@ #define BIT_DRS 0x2 #define BIT_DTS 0x1 -void cdd_mcu_run(cdd_mcu *context, uint32_t cycle, uint16_t *gate_array) +void cdd_mcu_run(cdd_mcu *context, uint32_t cycle, uint16_t *gate_array, lc8951* cdc) { uint32_t cd_cycle = mclks_to_cd_block(cycle); if (!(gate_array[GAO_CDD_CTRL] & BIT_HOCK)) { @@ -304,6 +359,7 @@ uint32_t next_subcode = context->last_subcode_cycle + SECTOR_CLOCKS; uint32_t next_nibble = context->current_status_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER; uint32_t next_cmd_nibble = context->current_cmd_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER; + uint32_t next_byte = context->current_sector_byte >= 0 ? context->last_byte_cycle + BYTE_CLOCKS : CYCLE_NEVER; for (; context->cycle < cd_cycle; context->cycle += CDD_MCU_DIVIDER) { if (context->cycle >= next_subcode) { @@ -313,6 +369,10 @@ next_nibble = context->cycle; context->current_status_nibble = 0; gate_array[GAO_CDD_STATUS] |= BIT_DRS; + if (context->status == DS_PLAY && !context->seeking) { + next_byte = context->cycle; + context->current_sector_byte = 0; + } } if (context->cycle >= next_nibble) { if (context->current_status_nibble == sizeof(cdd_status)) { @@ -358,6 +418,37 @@ next_cmd_nibble = context->cycle + NIBBLE_CLOCKS; } } + if (context->cycle >= next_byte) { + uint8_t byte; + if (context->in_fake_pregap) { + if (!context->current_sector_byte || (context->current_sector_byte >= 16)) { + byte = 0; + //TODO: error detection and correction bytes + } else if (context->current_sector_byte < 12) { + byte = 0xFF; + } else if (context->current_sector_byte == 12) { + uint32_t minute = ((context->head_pba - LEADIN_SECTORS) / 75) / 60; + byte = (minute % 10) | ((minute / 10 ) << 4); + } else if (context->current_sector_byte == 13) { + uint32_t seconds = ((context->head_pba - LEADIN_SECTORS) / 75) % 60; + byte = (seconds % 10) | ((seconds / 10 ) << 4); + } else if (context->current_sector_byte == 14) { + uint32_t frames = (context->head_pba - LEADIN_SECTORS) % 75; + byte = (frames % 10) | ((frames / 10 ) << 4); + } else { + byte = 1; + } + } else { + byte = fgetc(context->media->f); + } + lc8951_write_byte(cdc, cd_block_to_mclks(context->cycle), context->current_sector_byte++, byte); + context->last_byte_cycle = context->cycle; + next_byte = context->cycle + BYTE_CLOCKS; + if (context->current_sector_byte == 2352) { + context->current_sector_byte = -1; + + } + } } } @@ -400,4 +491,7 @@ if (context->last_nibble_cycle != CYCLE_NEVER) { context->last_nibble_cycle -= cd_deduction; } + if (context->last_byte_cycle != CYCLE_NEVER) { + context->last_byte_cycle -= cd_deduction; + } }