Mercurial > repos > blastem
comparison cdd_mcu.c @ 2353:c66e051de8a6
More accurate CDD pause behavior
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 18 Oct 2023 23:27:55 -0700 |
parents | 2025ba21026a |
children | 0871f555eff6 |
comparison
equal
deleted
inserted
replaced
2352:76dfad6a53b5 | 2353:c66e051de8a6 |
---|---|
88 // ~ 23 sectors per physical track at edge | 88 // ~ 23 sectors per physical track at edge |
89 // ~9 sectors per physical track at start of lead-in | 89 // ~9 sectors per physical track at start of lead-in |
90 // seek test suggests average somewhere around 54-60 tracks for a long seek, with a peak around 80 | 90 // seek test suggests average somewhere around 54-60 tracks for a long seek, with a peak around 80 |
91 // Sonic CD title screen seems to need a much higher value to get reasonable sync | 91 // Sonic CD title screen seems to need a much higher value to get reasonable sync |
92 #define COARSE_SEEK_TRACKS 60 | 92 #define COARSE_SEEK_TRACKS 60 |
93 static float sectors_per_track_at_pba(uint32_t pba) | |
94 { | |
95 //TODO: better estimate of sectors per track at current head location | |
96 float circumference = (MAX_CIRCUMFERENCE-MIN_CIRCUMFERENCE) * ((float)pba) / ((74 * 60 + 41) * SECTORS_PER_SECOND + LEADIN_SECTORS + 22) + MIN_CIRCUMFERENCE; | |
97 return circumference / SECTOR_LENGTH; | |
98 } | |
99 | |
93 static void handle_seek(cdd_mcu *context) | 100 static void handle_seek(cdd_mcu *context) |
94 { | 101 { |
95 uint32_t old_coarse = context->coarse_seek; | 102 uint32_t old_coarse = context->coarse_seek; |
96 if (context->seeking) { | 103 if (context->seeking == 2) { |
104 context->head_pba = context->seek_pba; | |
105 context->coarse_seek = 6; | |
106 context->seeking = 0; | |
107 } else if (context->seeking) { | |
97 if (context->seek_pba == context->head_pba) { | 108 if (context->seek_pba == context->head_pba) { |
98 context->seeking = 0; | 109 context->seeking = 0; |
99 context->coarse_seek = 0; | 110 context->coarse_seek = 0; |
100 if (context->status == DS_PAUSE) { | 111 if (context->status == DS_PAUSE && !context->pause_pba) { |
101 context->pause_pba = context->head_pba; | 112 context->pause_pba = context->head_pba; |
102 } | 113 } |
103 } else { | 114 } else { |
104 //TODO: better estimate of sectors per track at current head location | 115 |
105 //TODO: drive will periodically lose tracking when seeking which slows | 116 //TODO: drive will periodically lose tracking when seeking which slows |
106 //things down from this ideal speed I'm curently estimating | 117 //things down periodically, I estimate the average |
107 float circumference = (MAX_CIRCUMFERENCE-MIN_CIRCUMFERENCE) * ((float)context->head_pba) / ((74 * 60 + 41) * SECTORS_PER_SECOND + LEADIN_SECTORS + 22) + MIN_CIRCUMFERENCE; | 118 float sectors_per_track = sectors_per_track_at_pba(context->head_pba); |
108 float sectors_per_track = circumference / SECTOR_LENGTH; | |
109 uint32_t max_seek = sectors_per_track * COARSE_SEEK_TRACKS; | 119 uint32_t max_seek = sectors_per_track * COARSE_SEEK_TRACKS; |
110 uint32_t min_seek = sectors_per_track; | 120 uint32_t min_seek = sectors_per_track; |
111 | 121 |
112 uint32_t old_pba = context->head_pba; | 122 uint32_t old_pba = context->head_pba; |
113 if (context->seek_pba > context->head_pba) { | 123 if (context->seek_pba > context->head_pba) { |
145 context->coarse_seek++; | 155 context->coarse_seek++; |
146 } else { | 156 } else { |
147 context->coarse_seek = 0; | 157 context->coarse_seek = 0; |
148 } | 158 } |
149 } | 159 } |
150 } | 160 } else { |
151 if (old_coarse && !context->coarse_seek) { | 161 context->coarse_seek = 0; |
152 } | 162 } |
153 } | 163 } |
154 | 164 |
155 static void lba_to_status(cdd_mcu *context, uint32_t lba) | 165 static void lba_to_status(cdd_mcu *context, uint32_t lba) |
156 { | 166 { |
189 break; | 199 break; |
190 case DS_PAUSE: | 200 case DS_PAUSE: |
191 handle_seek(context); | 201 handle_seek(context); |
192 if (!context->seeking) { | 202 if (!context->seeking) { |
193 context->head_pba++; | 203 context->head_pba++; |
194 //TODO: better estimate of sectors per track at current head location | 204 if (context->head_pba > context->pause_pba) { |
195 float circumference = (MAX_CIRCUMFERENCE-MIN_CIRCUMFERENCE) * ((float)context->head_pba) / (74 * 60 * SECTORS_PER_SECOND) + MIN_CIRCUMFERENCE; | 205 uint32_t back = sectors_per_track_at_pba(context->head_pba) + 0.5f; |
196 float sectors_per_track = circumference / SECTOR_LENGTH; | 206 if (back > context->head_pba) { |
197 //TODO: check the exact behavior during pause on hardware | 207 back = context->head_pba; |
198 uint32_t diff = sectors_per_track * 0.5f + 0.5f; | 208 } |
199 if (context->head_pba > context->pause_pba + diff) { | 209 context->head_pba -= back; |
200 context->head_pba = context->pause_pba - diff; | 210 context->coarse_seek = 6; |
201 if (context->head_pba < LEADIN_SECTORS) { | |
202 context->head_pba = LEADIN_SECTORS; | |
203 } | |
204 } | 211 } |
205 } | 212 } |
206 if (context->head_pba >= LEADIN_SECTORS) { | 213 if (context->head_pba >= LEADIN_SECTORS) { |
207 context->media->seek(context->media, context->head_pba - LEADIN_SECTORS); | 214 context->media->seek(context->media, context->head_pba - LEADIN_SECTORS); |
208 } | 215 } |
399 // Did not receive our first command so just send zeroes | 406 // Did not receive our first command so just send zeroes |
400 memset(&context->status_buffer, 0, sizeof(context->status_buffer) - 1); | 407 memset(&context->status_buffer, 0, sizeof(context->status_buffer) - 1); |
401 } | 408 } |
402 context->status_buffer.checksum = checksum((uint8_t *)&context->status_buffer); | 409 context->status_buffer.checksum = checksum((uint8_t *)&context->status_buffer); |
403 if (context->status_buffer.format != SF_NOTREADY) { | 410 if (context->status_buffer.format != SF_NOTREADY) { |
404 printf("CDD Status %X%X.%X%X%X%X%X%X.%X%X\n", | 411 printf("CDD Status %X%X.%X%X%X%X%X%X.%X%X (lba %u)\n", |
405 context->status_buffer.status, context->status_buffer.format, | 412 context->status_buffer.status, context->status_buffer.format, |
406 context->status_buffer.b.time.min_high, context->status_buffer.b.time.min_low, | 413 context->status_buffer.b.time.min_high, context->status_buffer.b.time.min_low, |
407 context->status_buffer.b.time.sec_high, context->status_buffer.b.time.sec_low, | 414 context->status_buffer.b.time.sec_high, context->status_buffer.b.time.sec_low, |
408 context->status_buffer.b.time.frame_high, context->status_buffer.b.time.frame_low, | 415 context->status_buffer.b.time.frame_high, context->status_buffer.b.time.frame_low, |
409 context->status_buffer.b.time.flags, context->status_buffer.checksum | 416 context->status_buffer.b.time.flags, context->status_buffer.checksum, context->head_pba - LEADIN_SECTORS |
410 ); | 417 ); |
411 } | 418 } |
412 } | 419 } |
413 | 420 |
414 static void run_command(cdd_mcu *context) | 421 static void run_command(cdd_mcu *context) |
526 if (context->status == DS_STOP) { | 533 if (context->status == DS_STOP) { |
527 context->seeking = 1; | 534 context->seeking = 1; |
528 context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].fake_pregap + context->media->tracks[0].start_lba; | 535 context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].fake_pregap + context->media->tracks[0].start_lba; |
529 printf("CDD CMD: PAUSE, seeking to %u\n", context->seek_pba); | 536 printf("CDD CMD: PAUSE, seeking to %u\n", context->seek_pba); |
530 } else { | 537 } else { |
531 puts("CDD CMD: PAUSE"); | 538 uint32_t lba = context->head_pba - LEADIN_SECTORS; |
539 uint32_t seconds = lba / 75; | |
540 uint32_t frames = lba % 75; | |
541 uint32_t minutes = seconds / 60; | |
542 seconds = seconds % 60; | |
543 printf("CDD CMD: PAUSE, current lba %u, MM:SS:FF %02u:%02u:%02u\n", lba, minutes, seconds, frames); | |
532 } | 544 } |
533 context->status = DS_PAUSE; | 545 context->status = DS_PAUSE; |
534 if (!context->seeking) { | 546 if (context->seeking) { |
547 //handle_seek will populate this | |
548 context->pause_pba = 0; | |
549 } else { | |
535 context->pause_pba = context->head_pba; | 550 context->pause_pba = context->head_pba; |
551 uint32_t back = 2.1f * sectors_per_track_at_pba(context->head_pba) + 0.5f; | |
552 if (back > context->head_pba) { | |
553 back = context->head_pba; | |
554 } | |
555 context->seek_pba = context->head_pba - back; | |
556 context->seeking = 2; | |
536 } | 557 } |
537 break; | 558 break; |
538 case CMD_PLAY: | 559 case CMD_PLAY: |
539 if (context->status == DS_DOOR_OPEN || context->status == DS_TRAY_MOVING || context->status == DS_DISC_LEADOUT || context->status == DS_DISC_LEADIN) { | 560 if (context->status == DS_DOOR_OPEN || context->status == DS_TRAY_MOVING || context->status == DS_DISC_LEADOUT || context->status == DS_DISC_LEADIN) { |
540 context->error_status = DS_CMD_ERROR; | 561 context->error_status = DS_CMD_ERROR; |
700 } | 721 } |
701 } | 722 } |
702 if (context->cycle >= context->next_byte_cycle) { | 723 if (context->cycle >= context->next_byte_cycle) { |
703 if (context->current_sector_byte >= 0 && (!fader->byte_counter || context->current_sector_byte)) { | 724 if (context->current_sector_byte >= 0 && (!fader->byte_counter || context->current_sector_byte)) { |
704 uint8_t byte = context->media->read(context->media, context->current_sector_byte); | 725 uint8_t byte = context->media->read(context->media, context->current_sector_byte); |
726 if (context->status != DS_PLAY) { | |
727 byte = 0; | |
728 } | |
705 lc8951_write_byte(cdc, cd_block_to_mclks(context->cycle), context->current_sector_byte++, byte); | 729 lc8951_write_byte(cdc, cd_block_to_mclks(context->cycle), context->current_sector_byte++, byte); |
706 cdd_fader_data(fader, gate_array[GAO_CDD_CTRL] & BIT_MUTE ? 0 : byte); | 730 cdd_fader_data(fader, gate_array[GAO_CDD_CTRL] & BIT_MUTE ? 0 : byte); |
707 } else { | 731 } else { |
708 lc8951_write_byte(cdc, cd_block_to_mclks(context->cycle), 0, 0); | 732 lc8951_write_byte(cdc, cd_block_to_mclks(context->cycle), 0, 0); |
709 cdd_fader_data(fader, 0); | 733 cdd_fader_data(fader, 0); |