comparison 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
comparison
equal deleted inserted replaced
2061:7c1760b5b3e5 2062:07ed42bd7b4c
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 SECTOR_CLOCKS (CD_BLOCK_CLKS/75)
8 #define NIBBLE_CLOCKS (CDD_MCU_DIVIDER * 77) 8 #define NIBBLE_CLOCKS (CDD_MCU_DIVIDER * 77)
9 #define BYTE_CLOCKS (SECTOR_CLOCKS/2352) // 96
9 10
10 //lead in start max diameter 46 mm 11 //lead in start max diameter 46 mm
11 //program area start max diameter 50 mm 12 //program area start max diameter 50 mm
12 //difference 4 mm = 4000 um 13 //difference 4 mm = 4000 um
13 //radius difference 2 mm = 2000 um 14 //radius difference 2 mm = 2000 um
100 { 101 {
101 case DS_PLAY: 102 case DS_PLAY:
102 handle_seek(context); 103 handle_seek(context);
103 if (!context->seeking) { 104 if (!context->seeking) {
104 context->head_pba++; 105 context->head_pba++;
106 uint32_t lba = context->head_pba - LEADIN_SECTORS;
107 for (uint32_t i = 0; i < context->media->num_tracks; i++)
108 {
109 if (lba < context->media->tracks[i].fake_pregap) {
110 context->in_fake_pregap = 1;
111 break;
112 }
113 lba -= context->media->tracks[i].fake_pregap;
114 if (lba < context->media->tracks[i].start_lba) {
115 context->in_fake_pregap = 1;
116 break;
117 }
118 if (lba < context->media->tracks[i].end_lba) {
119 fseek(context->media->f, lba * 2352, SEEK_SET);
120 context->in_fake_pregap = 0;
121 break;
122 }
123 }
105 } 124 }
106 break; 125 break;
107 case DS_PAUSE: 126 case DS_PAUSE:
108 handle_seek(context); 127 handle_seek(context);
109 break; 128 break;
113 context->head_pba++; 132 context->head_pba++;
114 if (context->media && context->media->type == MEDIA_CDROM && context->media->num_tracks) { 133 if (context->media && context->media->type == MEDIA_CDROM && context->media->num_tracks) {
115 if (context->head_pba > 3*context->media->num_tracks + 1) { 134 if (context->head_pba > 3*context->media->num_tracks + 1) {
116 context->toc_valid = 1; 135 context->toc_valid = 1;
117 context->seeking = 1; 136 context->seeking = 1;
118 context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].start_lba + context->media->tracks[0].fake_pregap; 137 context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].start_lba;
119 context->status = DS_PAUSE; 138 context->status = DS_PAUSE;
120 } 139 }
121 140
122 } else { 141 } else {
123 context->status = DS_NO_DISC; 142 context->status = DS_NO_DISC;
168 context->status_buffer.format = SF_NOTREADY; 187 context->status_buffer.format = SF_NOTREADY;
169 } 188 }
170 break; 189 break;
171 case SF_TOCO: 190 case SF_TOCO:
172 if (context->toc_valid) { 191 if (context->toc_valid) {
173 lba_to_status(context, context->media->tracks[context->media->num_tracks - 1].end_lba + context->media->tracks[0].fake_pregap); 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));
174 context->status_buffer.format = SF_TOCO; 193 context->status_buffer.format = SF_TOCO;
175 } else { 194 } else {
176 context->status_buffer.format = SF_NOTREADY; 195 context->status_buffer.format = SF_NOTREADY;
177 } 196 }
178 break; 197 break;
188 context->status_buffer.format = SF_NOTREADY; 207 context->status_buffer.format = SF_NOTREADY;
189 } 208 }
190 break; 209 break;
191 case SF_TOCN: 210 case SF_TOCN:
192 if (context->toc_valid) { 211 if (context->toc_valid) {
193 lba_to_status(context, context->media->tracks[context->requested_track].start_lba + context->media->tracks[0].fake_pregap); 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);
194 context->status_buffer.b.tocn.track_low = context->requested_track % 10; 217 context->status_buffer.b.tocn.track_low = context->requested_track % 10;
195 context->status_buffer.format = SF_TOCN; 218 context->status_buffer.format = SF_TOCN;
196 } else { 219 } else {
197 context->status_buffer.format = SF_NOTREADY; 220 context->status_buffer.format = SF_NOTREADY;
198 } 221 }
211 if (context->requested_format != SF_TOCN) { 234 if (context->requested_format != SF_TOCN) {
212 context->status_buffer.b.time.flags = 0; //TODO: populate these 235 context->status_buffer.b.time.flags = 0; //TODO: populate these
213 } 236 }
214 context->status_buffer.checksum = checksum((uint8_t *)&context->status_buffer); 237 context->status_buffer.checksum = checksum((uint8_t *)&context->status_buffer);
215 if (context->status_buffer.format != SF_NOTREADY) { 238 if (context->status_buffer.format != SF_NOTREADY) {
216 printf("CDD Status %d%d.%d%d%d%d%d%d.%d%d\n", 239 printf("CDD Status %X%X.%X%X%X%X%X%X.%X%X\n",
217 context->status_buffer.status, context->status_buffer.format, 240 context->status_buffer.status, context->status_buffer.format,
218 context->status_buffer.b.time.min_high, context->status_buffer.b.time.min_low, 241 context->status_buffer.b.time.min_high, context->status_buffer.b.time.min_low,
219 context->status_buffer.b.time.sec_high, context->status_buffer.b.time.sec_low, 242 context->status_buffer.b.time.sec_high, context->status_buffer.b.time.sec_low,
220 context->status_buffer.b.time.frame_high, context->status_buffer.b.time.frame_low, 243 context->status_buffer.b.time.frame_high, context->status_buffer.b.time.frame_low,
221 context->status_buffer.b.time.flags, context->status_buffer.checksum 244 context->status_buffer.b.time.flags, context->status_buffer.checksum
240 break; 263 break;
241 case CMD_STOP: 264 case CMD_STOP:
242 puts("CDD CMD: STOP"); 265 puts("CDD CMD: STOP");
243 context->status = DS_STOP; 266 context->status = DS_STOP;
244 break; 267 break;
268 case CMD_READ:
269 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) {
271 context->error_status = DS_CMD_ERROR;
272 break;
273 }
274 if (context->requested_format == SF_TOCT || context->requested_format == SF_TOCN) {
275 context->requested_format = SF_ABSOLUTE;
276 }
277 if (!context->toc_valid) {
278 context->error_status = DS_CMD_ERROR;
279 break;
280 }
281 uint32_t lba = context->cmd_buffer.b.time.min_high * 10 + context->cmd_buffer.b.time.min_low;
282 lba *= 60;
283 lba += context->cmd_buffer.b.time.sec_high * 10 + context->cmd_buffer.b.time.sec_low;
284 lba *= 75;
285 lba += context->cmd_buffer.b.time.frame_high * 10 + context->cmd_buffer.b.time.frame_low;
286 printf("READ/SEEK cmd for lba %d\n", lba);
287 if (lba >= context->media->tracks[0].fake_pregap + context->media->tracks[context->media->num_tracks - 1].end_lba) {
288 context->error_status = DS_CMD_ERROR;
289 break;
290 }
291 context->seek_pba = lba + LEADIN_SECTORS - 4;
292 context->seeking = 1;
293 context->status = context->cmd_buffer.cmd_type == CMD_READ ? DS_PLAY : DS_PAUSE;
294 break;
295 }
245 case CMD_REPORT_REQUEST: 296 case CMD_REPORT_REQUEST:
246 switch (context->cmd_buffer.b.format.status_type) 297 switch (context->cmd_buffer.b.format.status_type)
247 { 298 {
248 case SF_ABSOLUTE: 299 case SF_ABSOLUTE:
249 case SF_RELATIVE: 300 case SF_RELATIVE:
273 context->requested_format = SF_TOCT; 324 context->requested_format = SF_TOCT;
274 break; 325 break;
275 case SF_TOCN: 326 case SF_TOCN:
276 context->requested_track = context->cmd_buffer.b.format.track_high * 10; 327 context->requested_track = context->cmd_buffer.b.format.track_high * 10;
277 context->requested_track += context->cmd_buffer.b.format.track_low; 328 context->requested_track += context->cmd_buffer.b.format.track_low;
329 if (!context->media || context->requested_track > context->media->num_tracks) {
330 context->requested_format = SF_ABSOLUTE;
331 context->error_status = DS_CMD_ERROR;
332 }
278 context->status = DS_TOC_READ; 333 context->status = DS_TOC_READ;
279 context->seeking = 1; 334 context->seeking = 1;
280 context->seek_pba = 0; 335 context->seek_pba = 0;
281 context->requested_format = SF_TOCN; 336 context->requested_format = SF_TOCN;
282 break; 337 break;
290 345
291 #define BIT_HOCK 0x4 346 #define BIT_HOCK 0x4
292 #define BIT_DRS 0x2 347 #define BIT_DRS 0x2
293 #define BIT_DTS 0x1 348 #define BIT_DTS 0x1
294 349
295 void cdd_mcu_run(cdd_mcu *context, uint32_t cycle, uint16_t *gate_array) 350 void cdd_mcu_run(cdd_mcu *context, uint32_t cycle, uint16_t *gate_array, lc8951* cdc)
296 { 351 {
297 uint32_t cd_cycle = mclks_to_cd_block(cycle); 352 uint32_t cd_cycle = mclks_to_cd_block(cycle);
298 if (!(gate_array[GAO_CDD_CTRL] & BIT_HOCK)) { 353 if (!(gate_array[GAO_CDD_CTRL] & BIT_HOCK)) {
299 //it's a little unclear if this gates the actual cd block clock or just handshaking 354 //it's a little unclear if this gates the actual cd block clock or just handshaking
300 //assum it's actually the clock for now 355 //assum it's actually the clock for now
302 return; 357 return;
303 } 358 }
304 uint32_t next_subcode = context->last_subcode_cycle + SECTOR_CLOCKS; 359 uint32_t next_subcode = context->last_subcode_cycle + SECTOR_CLOCKS;
305 uint32_t next_nibble = context->current_status_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER; 360 uint32_t next_nibble = context->current_status_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER;
306 uint32_t next_cmd_nibble = context->current_cmd_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;
362 uint32_t next_byte = context->current_sector_byte >= 0 ? context->last_byte_cycle + BYTE_CLOCKS : CYCLE_NEVER;
307 for (; context->cycle < cd_cycle; context->cycle += CDD_MCU_DIVIDER) 363 for (; context->cycle < cd_cycle; context->cycle += CDD_MCU_DIVIDER)
308 { 364 {
309 if (context->cycle >= next_subcode) { 365 if (context->cycle >= next_subcode) {
310 context->last_subcode_cycle = context->cycle; 366 context->last_subcode_cycle = context->cycle;
311 next_subcode = context->cycle + SECTOR_CLOCKS; 367 next_subcode = context->cycle + SECTOR_CLOCKS;
312 update_status(context); 368 update_status(context);
313 next_nibble = context->cycle; 369 next_nibble = context->cycle;
314 context->current_status_nibble = 0; 370 context->current_status_nibble = 0;
315 gate_array[GAO_CDD_STATUS] |= BIT_DRS; 371 gate_array[GAO_CDD_STATUS] |= BIT_DRS;
372 if (context->status == DS_PLAY && !context->seeking) {
373 next_byte = context->cycle;
374 context->current_sector_byte = 0;
375 }
316 } 376 }
317 if (context->cycle >= next_nibble) { 377 if (context->cycle >= next_nibble) {
318 if (context->current_status_nibble == sizeof(cdd_status)) { 378 if (context->current_status_nibble == sizeof(cdd_status)) {
319 context->current_status_nibble = -1; 379 context->current_status_nibble = -1;
320 gate_array[GAO_CDD_STATUS] &= ~BIT_DRS; 380 gate_array[GAO_CDD_STATUS] &= ~BIT_DRS;
356 context->current_cmd_nibble++; 416 context->current_cmd_nibble++;
357 context->last_nibble_cycle = context->cycle; 417 context->last_nibble_cycle = context->cycle;
358 next_cmd_nibble = context->cycle + NIBBLE_CLOCKS; 418 next_cmd_nibble = context->cycle + NIBBLE_CLOCKS;
359 } 419 }
360 } 420 }
421 if (context->cycle >= next_byte) {
422 uint8_t byte;
423 if (context->in_fake_pregap) {
424 if (!context->current_sector_byte || (context->current_sector_byte >= 16)) {
425 byte = 0;
426 //TODO: error detection and correction bytes
427 } else if (context->current_sector_byte < 12) {
428 byte = 0xFF;
429 } else if (context->current_sector_byte == 12) {
430 uint32_t minute = ((context->head_pba - LEADIN_SECTORS) / 75) / 60;
431 byte = (minute % 10) | ((minute / 10 ) << 4);
432 } else if (context->current_sector_byte == 13) {
433 uint32_t seconds = ((context->head_pba - LEADIN_SECTORS) / 75) % 60;
434 byte = (seconds % 10) | ((seconds / 10 ) << 4);
435 } else if (context->current_sector_byte == 14) {
436 uint32_t frames = (context->head_pba - LEADIN_SECTORS) % 75;
437 byte = (frames % 10) | ((frames / 10 ) << 4);
438 } else {
439 byte = 1;
440 }
441 } else {
442 byte = fgetc(context->media->f);
443 }
444 lc8951_write_byte(cdc, cd_block_to_mclks(context->cycle), context->current_sector_byte++, byte);
445 context->last_byte_cycle = context->cycle;
446 next_byte = context->cycle + BYTE_CLOCKS;
447 if (context->current_sector_byte == 2352) {
448 context->current_sector_byte = -1;
449
450 }
451 }
361 } 452 }
362 } 453 }
363 454
364 void cdd_mcu_start_cmd_recv(cdd_mcu *context, uint16_t *gate_array) 455 void cdd_mcu_start_cmd_recv(cdd_mcu *context, uint16_t *gate_array)
365 { 456 {
398 context->last_subcode_cycle -= cd_deduction; 489 context->last_subcode_cycle -= cd_deduction;
399 } 490 }
400 if (context->last_nibble_cycle != CYCLE_NEVER) { 491 if (context->last_nibble_cycle != CYCLE_NEVER) {
401 context->last_nibble_cycle -= cd_deduction; 492 context->last_nibble_cycle -= cd_deduction;
402 } 493 }
403 } 494 if (context->last_byte_cycle != CYCLE_NEVER) {
495 context->last_byte_cycle -= cd_deduction;
496 }
497 }