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);