Mercurial > repos > blastem
comparison cdd_mcu.c @ 2064:91e4d2fe5cd9 segacd
Get CDD working well enough to get into BIOS CD player
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 28 Jan 2022 22:48:06 -0800 |
parents | 07ed42bd7b4c |
children | 02a9846668d1 |
comparison
equal
deleted
inserted
replaced
2063:d59ace2d7a6a | 2064:91e4d2fe5cd9 |
---|---|
71 context->head_pba += SEEK_SPEED; | 71 context->head_pba += SEEK_SPEED; |
72 if (context->head_pba > context->seek_pba) { | 72 if (context->head_pba > context->seek_pba) { |
73 context->head_pba = context->seek_pba; | 73 context->head_pba = context->seek_pba; |
74 } | 74 } |
75 } else { | 75 } else { |
76 context->head_pba -= SEEK_SPEED; | 76 if (context->head_pba >= SEEK_SPEED) { |
77 context->head_pba -= SEEK_SPEED; | |
78 } else { | |
79 context->head_pba = 0; | |
80 } | |
77 if (context->head_pba < context->seek_pba) { | 81 if (context->head_pba < context->seek_pba) { |
78 context->head_pba = context->seek_pba; | 82 context->head_pba = context->seek_pba; |
79 } | 83 } |
80 } | 84 } |
81 } | 85 } |
143 } | 147 } |
144 } | 148 } |
145 break; | 149 break; |
146 | 150 |
147 } | 151 } |
148 switch (context->requested_format) | 152 if (context->first_cmd_received) { |
149 { | 153 switch (context->requested_format) |
150 case SF_ABSOLUTE: | 154 { |
151 if (context->toc_valid) { | 155 case SF_ABSOLUTE: |
152 lba_to_status(context, context->head_pba - LEADIN_SECTORS); | 156 if (context->toc_valid) { |
153 context->status_buffer.format = SF_ABSOLUTE; | 157 lba_to_status(context, context->head_pba - LEADIN_SECTORS); |
158 context->status_buffer.format = SF_ABSOLUTE; | |
159 } else { | |
160 context->status_buffer.format = SF_NOTREADY; | |
161 } | |
162 break; | |
163 case SF_RELATIVE: | |
164 if (context->toc_valid) { | |
165 uint32_t lba =context->head_pba - LEADIN_SECTORS; | |
166 for (uint32_t i = 0; i < context->media->num_tracks; i++) | |
167 { | |
168 if (lba < context->media->tracks[i].end_lba) { | |
169 if (context->media->tracks[i].fake_pregap) { | |
170 if (lba > context->media->tracks[i].fake_pregap) { | |
171 lba -= context->media->tracks[i].fake_pregap; | |
172 } else { | |
173 //relative time counts down to 0 in pregap | |
174 lba = context->media->tracks[i].fake_pregap - lba; | |
175 break; | |
176 } | |
177 } | |
178 if (lba < context->media->tracks[i].start_lba) { | |
179 //relative time counts down to 0 in pregap | |
180 lba = context->media->tracks[i].start_lba - lba; | |
181 } else { | |
182 lba -= context->media->tracks[i].start_lba; | |
183 } | |
184 break; | |
185 } else if (context->media->tracks[i].fake_pregap) { | |
186 lba -= context->media->tracks[i].fake_pregap; | |
187 } | |
188 } | |
189 lba_to_status(context, lba); | |
190 context->status_buffer.format = SF_ABSOLUTE; | |
191 } else { | |
192 context->status_buffer.format = SF_NOTREADY; | |
193 } | |
194 break; | |
195 case SF_TOCO: | |
196 if (context->toc_valid) { | |
197 uint32_t total_fake_pregap = 0; | |
198 for (uint32_t i = 0; i < context->media->num_tracks; i++) | |
199 { | |
200 total_fake_pregap += context->media->tracks[i].fake_pregap; | |
201 } | |
202 lba_to_status(context, context->media->tracks[context->media->num_tracks - 1].end_lba + total_fake_pregap); | |
203 context->status_buffer.format = SF_TOCO; | |
204 } else { | |
205 context->status_buffer.format = SF_NOTREADY; | |
206 } | |
207 break; | |
208 case SF_TOCT: | |
209 if (context->toc_valid) { | |
210 context->status_buffer.b.toct.first_track_high = 0; | |
211 context->status_buffer.b.toct.first_track_low = 1; | |
212 context->status_buffer.b.toct.last_track_high = (context->media->num_tracks + 1) / 10; | |
213 context->status_buffer.b.toct.last_track_low = (context->media->num_tracks + 1) % 10; | |
214 context->status_buffer.b.toct.version = 0; | |
215 context->status_buffer.format = SF_TOCT; | |
216 } else { | |
217 context->status_buffer.format = SF_NOTREADY; | |
218 } | |
219 break; | |
220 case SF_TOCN: | |
221 if (context->toc_valid) { | |
222 uint32_t lba = context->media->tracks[context->requested_track - 1].start_lba; | |
223 if (context->requested_track > 1) { | |
224 lba += context->media->tracks[1].fake_pregap; | |
225 } | |
226 lba_to_status(context, lba); | |
227 context->status_buffer.b.tocn.track_low = context->requested_track % 10; | |
228 context->status_buffer.format = SF_TOCN; | |
229 } else { | |
230 context->status_buffer.format = SF_NOTREADY; | |
231 } | |
232 break; | |
233 case SF_NOTREADY: | |
234 memset(&context->status_buffer, 0, sizeof(context->status_buffer) - 1); | |
235 context->status_buffer.format = SF_NOTREADY; | |
236 break; | |
237 } | |
238 if (context->error_status == DS_STOP) { | |
239 if (context->requested_format >= SF_TOCO && context->requested_format <= SF_TOCN) { | |
240 context->status_buffer.status = DS_TOC_READ; | |
241 } else { | |
242 context->status_buffer.status = context->status; | |
243 } | |
154 } else { | 244 } else { |
245 context->status_buffer.status = context->error_status; | |
155 context->status_buffer.format = SF_NOTREADY; | 246 context->status_buffer.format = SF_NOTREADY; |
156 } | 247 context->error_status = DS_STOP; |
157 break; | 248 } |
158 case SF_RELATIVE: | 249 if (context->requested_format != SF_TOCN) { |
159 if (context->toc_valid) { | 250 context->status_buffer.b.time.flags = 1; //TODO: populate these |
160 uint32_t lba =context->head_pba - LEADIN_SECTORS; | 251 } |
161 for (uint32_t i = 0; i < context->media->num_tracks; i++) | 252 } else { |
162 { | 253 // Did not receive our first command so just send zeroes |
163 if (lba < context->media->tracks[i].end_lba) { | |
164 if (context->media->tracks[i].fake_pregap) { | |
165 if (lba > context->media->tracks[i].fake_pregap) { | |
166 lba -= context->media->tracks[i].fake_pregap; | |
167 } else { | |
168 //relative time counts down to 0 in pregap | |
169 lba = context->media->tracks[i].fake_pregap - lba; | |
170 break; | |
171 } | |
172 } | |
173 if (lba < context->media->tracks[i].start_lba) { | |
174 //relative time counts down to 0 in pregap | |
175 lba = context->media->tracks[i].start_lba - lba; | |
176 } else { | |
177 lba -= context->media->tracks[i].start_lba; | |
178 } | |
179 break; | |
180 } else if (context->media->tracks[i].fake_pregap) { | |
181 lba -= context->media->tracks[i].fake_pregap; | |
182 } | |
183 } | |
184 lba_to_status(context, lba); | |
185 context->status_buffer.format = SF_ABSOLUTE; | |
186 } else { | |
187 context->status_buffer.format = SF_NOTREADY; | |
188 } | |
189 break; | |
190 case SF_TOCO: | |
191 if (context->toc_valid) { | |
192 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)); | |
193 context->status_buffer.format = SF_TOCO; | |
194 } else { | |
195 context->status_buffer.format = SF_NOTREADY; | |
196 } | |
197 break; | |
198 case SF_TOCT: | |
199 if (context->toc_valid) { | |
200 context->status_buffer.b.toct.first_track_high = 0; | |
201 context->status_buffer.b.toct.first_track_low = 1; | |
202 context->status_buffer.b.toct.last_track_high = (context->media->num_tracks + 1) / 10; | |
203 context->status_buffer.b.toct.last_track_low = (context->media->num_tracks + 1) % 10; | |
204 context->status_buffer.b.toct.version = 0; | |
205 context->status_buffer.format = SF_TOCT; | |
206 } else { | |
207 context->status_buffer.format = SF_NOTREADY; | |
208 } | |
209 break; | |
210 case SF_TOCN: | |
211 if (context->toc_valid) { | |
212 uint32_t lba = context->media->tracks[context->requested_track - 1].start_lba; | |
213 if (context->requested_track > 1) { | |
214 lba += context->media->tracks[1].fake_pregap; | |
215 } | |
216 lba_to_status(context, lba); | |
217 context->status_buffer.b.tocn.track_low = context->requested_track % 10; | |
218 context->status_buffer.format = SF_TOCN; | |
219 } else { | |
220 context->status_buffer.format = SF_NOTREADY; | |
221 } | |
222 break; | |
223 case SF_NOTREADY: | |
224 memset(&context->status_buffer, 0, sizeof(context->status_buffer) - 1); | 254 memset(&context->status_buffer, 0, sizeof(context->status_buffer) - 1); |
225 context->status_buffer.format = SF_NOTREADY; | |
226 break; | |
227 } | |
228 if (context->error_status == DS_STOP) { | |
229 context->status_buffer.status = context->status; | |
230 } else { | |
231 context->status_buffer.status = context->error_status; | |
232 context->error_status = DS_STOP; | |
233 } | |
234 if (context->requested_format != SF_TOCN) { | |
235 context->status_buffer.b.time.flags = 0; //TODO: populate these | |
236 } | 255 } |
237 context->status_buffer.checksum = checksum((uint8_t *)&context->status_buffer); | 256 context->status_buffer.checksum = checksum((uint8_t *)&context->status_buffer); |
238 if (context->status_buffer.format != SF_NOTREADY) { | 257 if (context->status_buffer.format != SF_NOTREADY) { |
239 printf("CDD Status %X%X.%X%X%X%X%X%X.%X%X\n", | 258 printf("CDD Status %X%X.%X%X%X%X%X%X.%X%X\n", |
240 context->status_buffer.status, context->status_buffer.format, | 259 context->status_buffer.status, context->status_buffer.format, |
247 } | 266 } |
248 | 267 |
249 static void run_command(cdd_mcu *context) | 268 static void run_command(cdd_mcu *context) |
250 { | 269 { |
251 uint8_t check = checksum((uint8_t*)&context->cmd_buffer); | 270 uint8_t check = checksum((uint8_t*)&context->cmd_buffer); |
271 printf("cmd %X, checksum: %X, calc: %X\n", context->cmd_buffer.cmd_type, context->cmd_buffer.checksum, check); | |
252 if (check != context->cmd_buffer.checksum) { | 272 if (check != context->cmd_buffer.checksum) { |
253 context->error_status = DS_SUM_ERROR; | 273 context->error_status = DS_SUM_ERROR; |
254 return; | 274 return; |
255 } | 275 } |
256 if (context->cmd_buffer.must_be_zero) { | 276 if (context->cmd_buffer.must_be_zero) { |
257 context->error_status = DS_CMD_ERROR; | 277 context->error_status = DS_CMD_ERROR; |
258 return; | 278 return; |
259 } | 279 } |
280 context->first_cmd_received = 1; | |
260 switch (context->cmd_buffer.cmd_type) | 281 switch (context->cmd_buffer.cmd_type) |
261 { | 282 { |
262 case CMD_NOP: | 283 case CMD_NOP: |
263 break; | 284 break; |
264 case CMD_STOP: | 285 case CMD_STOP: |
265 puts("CDD CMD: STOP"); | 286 puts("CDD CMD: STOP"); |
266 context->status = DS_STOP; | 287 context->status = DS_STOP; |
288 context->requested_format = SF_ABSOLUTE; | |
267 break; | 289 break; |
268 case CMD_READ: | 290 case CMD_READ: |
269 case CMD_SEEK: { | 291 case CMD_SEEK: { |
270 if (context->status == DS_DOOR_OPEN || context->status == DS_TRAY_MOVING || context->status == DS_DISC_LEADOUT || context->status == DS_DISC_LEADIN) { | 292 if (context->status == DS_DOOR_OPEN || context->status == DS_TRAY_MOVING || context->status == DS_DISC_LEADOUT || context->status == DS_DISC_LEADIN) { |
271 context->error_status = DS_CMD_ERROR; | 293 context->error_status = DS_CMD_ERROR; |
351 { | 373 { |
352 uint32_t cd_cycle = mclks_to_cd_block(cycle); | 374 uint32_t cd_cycle = mclks_to_cd_block(cycle); |
353 if (!(gate_array[GAO_CDD_CTRL] & BIT_HOCK)) { | 375 if (!(gate_array[GAO_CDD_CTRL] & BIT_HOCK)) { |
354 //it's a little unclear if this gates the actual cd block clock or just handshaking | 376 //it's a little unclear if this gates the actual cd block clock or just handshaking |
355 //assum it's actually the clock for now | 377 //assum it's actually the clock for now |
356 context->cycle = cycle; | 378 context->cycle = cd_cycle; |
357 return; | 379 return; |
358 } | 380 } |
359 uint32_t next_subcode = context->last_subcode_cycle + SECTOR_CLOCKS; | 381 uint32_t next_subcode = context->last_subcode_cycle + SECTOR_CLOCKS; |
360 uint32_t next_nibble = context->current_status_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER; | 382 uint32_t next_nibble = context->current_status_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER; |
361 uint32_t next_cmd_nibble = context->current_cmd_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER; | 383 uint32_t next_cmd_nibble = context->current_cmd_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER; |