Mercurial > repos > blastem
comparison cdd_mcu.c @ 2141:793715149f16
More accurate seek emulation
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 22 Mar 2022 20:20:25 -0700 |
parents | 11a3d5b00a66 |
children | d9151d0894c7 |
comparison
equal
deleted
inserted
replaced
2140:6d0de02a068a | 2141:793715149f16 |
---|---|
2 #include "backend.h" | 2 #include "backend.h" |
3 | 3 |
4 #define SCD_MCLKS 50000000 | 4 #define SCD_MCLKS 50000000 |
5 #define CD_BLOCK_CLKS 16934400 | 5 #define CD_BLOCK_CLKS 16934400 |
6 #define CDD_MCU_DIVIDER 8 | 6 #define CDD_MCU_DIVIDER 8 |
7 #define SECTOR_CLOCKS (CD_BLOCK_CLKS/75) | 7 #define SECTORS_PER_SECOND 75 |
8 #define SECTOR_CLOCKS (CD_BLOCK_CLKS/SECTORS_PER_SECOND) | |
8 #define NIBBLE_CLOCKS (CDD_MCU_DIVIDER * 77) | 9 #define NIBBLE_CLOCKS (CDD_MCU_DIVIDER * 77) |
9 #define BYTE_CLOCKS (SECTOR_CLOCKS/2352) // 96 | 10 #define BYTE_CLOCKS (SECTOR_CLOCKS/2352) // 96 |
10 #define SUBCODE_CLOCKS (SECTOR_CLOCKS/98) | 11 #define SUBCODE_CLOCKS (SECTOR_CLOCKS/98) |
11 #define PROCESSING_DELAY 54000 //approximate, based on Wondermega M1 measurements | 12 #define PROCESSING_DELAY 54000 //approximate, based on Wondermega M1 measurements |
12 | 13 |
74 { | 75 { |
75 sum += buffer[i]; | 76 sum += buffer[i]; |
76 } | 77 } |
77 return (~sum) & 0xF; | 78 return (~sum) & 0xF; |
78 } | 79 } |
80 | |
81 #define MIN_CIRCUMFERENCE 144.51f | |
82 #define MAX_CIRCUMFERENCE 364.42f | |
83 #define SECTOR_LENGTH 17.3333f | |
84 // max diameter for program area 116 mm | |
85 // circumference ~ 364.42 mm | |
86 // ~ 21 sectors per physical track at edge | |
87 // ~8 sectors per physical track at start of lead-in | |
79 #define COARSE_SEEK 2200 //made up numbers | 88 #define COARSE_SEEK 2200 //made up numbers |
80 #define FINE_SEEK 10 | 89 #define FINE_SEEK 10 |
81 static void handle_seek(cdd_mcu *context) | 90 static void handle_seek(cdd_mcu *context) |
82 { | 91 { |
83 //TODO: more realistic seeking behavior | 92 //TODO: more realistic seeking behavior |
85 if (context->seek_pba == context->head_pba) { | 94 if (context->seek_pba == context->head_pba) { |
86 context->seeking = 0; | 95 context->seeking = 0; |
87 if (context->status == DS_PAUSE) { | 96 if (context->status == DS_PAUSE) { |
88 context->pause_pba = context->head_pba; | 97 context->pause_pba = context->head_pba; |
89 } | 98 } |
90 } else if (context->seek_pba > context->head_pba) { | |
91 if (context->seek_pba - context->head_pba >= COARSE_SEEK || context->head_pba < LEADIN_SECTORS) { | |
92 context->head_pba += COARSE_SEEK; | |
93 } else if (context->seek_pba - context->head_pba >= FINE_SEEK) { | |
94 context->head_pba += FINE_SEEK; | |
95 } else { | |
96 context->head_pba++; | |
97 } | |
98 } else { | 99 } else { |
99 if (context->head_pba - context->seek_pba >= COARSE_SEEK) { | 100 //TODO: better estimate of sectors per track at current head location |
100 context->head_pba -= COARSE_SEEK; | 101 float circumference = (MAX_CIRCUMFERENCE-MIN_CIRCUMFERENCE) * ((float)context->head_pba) / (74 * 60 * SECTORS_PER_SECOND) + MIN_CIRCUMFERENCE; |
101 } else if (context->head_pba >= FINE_SEEK) { | 102 float sectors_per_track = circumference / SECTOR_LENGTH; |
102 context->head_pba -= FINE_SEEK; | 103 uint32_t max_seek = sectors_per_track * 190; |
103 } else { | 104 uint32_t min_seek = sectors_per_track; |
104 context->head_pba = 0; | 105 |
106 | |
107 if (context->seek_pba > context->head_pba) { | |
108 uint32_t seek_amount; | |
109 for (seek_amount = max_seek; seek_amount >= min_seek; seek_amount >>= 1) | |
110 { | |
111 if (context->seek_pba - context->head_pba >= seek_amount) { | |
112 break; | |
113 } | |
114 } | |
115 if (seek_amount >= min_seek) { | |
116 context->head_pba += seek_amount; | |
117 } else { | |
118 context->head_pba++; | |
119 } | |
120 } else { | |
121 uint32_t seek_amount; | |
122 for (seek_amount = max_seek; seek_amount >= min_seek; seek_amount >>= 1) | |
123 { | |
124 if (context->head_pba - context->seek_pba >= seek_amount) { | |
125 break; | |
126 } | |
127 } | |
128 if (seek_amount >= min_seek) { | |
129 context->head_pba -= seek_amount; | |
130 } else if (context->head_pba >= min_seek){ | |
131 context->head_pba -= min_seek; | |
132 } else { | |
133 context->head_pba = 0; | |
134 } | |
105 } | 135 } |
106 } | 136 } |
107 } | 137 } |
108 } | 138 } |
109 | 139 |
404 ); | 434 ); |
405 if (lba >= context->media->tracks[0].fake_pregap + context->media->tracks[context->media->num_tracks - 1].end_lba) { | 435 if (lba >= context->media->tracks[0].fake_pregap + context->media->tracks[context->media->num_tracks - 1].end_lba) { |
406 context->error_status = DS_CMD_ERROR; | 436 context->error_status = DS_CMD_ERROR; |
407 break; | 437 break; |
408 } | 438 } |
409 context->seek_pba = lba + LEADIN_SECTORS - 4; | 439 context->seek_pba = lba + LEADIN_SECTORS - 3; |
410 context->seeking = 1; | 440 context->seeking = 1; |
411 context->status = context->cmd_buffer.cmd_type == CMD_READ ? DS_PLAY : DS_PAUSE; | 441 context->status = context->cmd_buffer.cmd_type == CMD_READ ? DS_PLAY : DS_PAUSE; |
412 break; | 442 break; |
413 } | 443 } |
414 case CMD_REPORT_REQUEST: | 444 case CMD_REPORT_REQUEST: |