Mercurial > repos > blastem
comparison cdd_mcu.c @ 2116:cd057d6fe030
Initial stab at subcode emulation
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 06 Mar 2022 22:03:52 -0800 |
parents | e93ced356a21 |
children | 03304d350339 |
comparison
equal
deleted
inserted
replaced
2115:e93ced356a21 | 2116:cd057d6fe030 |
---|---|
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 #define BYTE_CLOCKS (SECTOR_CLOCKS/2352) // 96 |
10 #define SUBCODE_CLOCKS (SECTOR_CLOCKS/98) | |
10 #define PROCESSING_DELAY 54000 //approximate, based on Wondermega M1 measurements | 11 #define PROCESSING_DELAY 54000 //approximate, based on Wondermega M1 measurements |
11 | 12 |
12 //lead in start max diameter 46 mm | 13 //lead in start max diameter 46 mm |
13 //program area start max diameter 50 mm | 14 //program area start max diameter 50 mm |
14 //difference 4 mm = 4000 um | 15 //difference 4 mm = 4000 um |
36 } | 37 } |
37 | 38 |
38 void cdd_mcu_init(cdd_mcu *context, system_media *media) | 39 void cdd_mcu_init(cdd_mcu *context, system_media *media) |
39 { | 40 { |
40 context->next_int_cycle = CYCLE_NEVER; | 41 context->next_int_cycle = CYCLE_NEVER; |
41 context->last_subcode_cycle = CYCLE_NEVER; | 42 context->next_subcode_int_cycle = CYCLE_NEVER; |
43 context->last_sector_cycle = CYCLE_NEVER; | |
42 context->last_nibble_cycle = CYCLE_NEVER; | 44 context->last_nibble_cycle = CYCLE_NEVER; |
43 context->next_byte_cycle = 0; | 45 context->next_byte_cycle = 0; |
46 context->next_subcode_cycle = CYCLE_NEVER; | |
44 context->requested_format = SF_NOTREADY; | 47 context->requested_format = SF_NOTREADY; |
45 context->media = media; | 48 context->media = media; |
46 context->current_status_nibble = -1; | 49 context->current_status_nibble = -1; |
47 context->current_cmd_nibble = -1; | 50 context->current_cmd_nibble = -1; |
48 context->current_sector_byte = -1; | 51 context->current_sector_byte = -1; |
52 context->current_subcode_byte = -1; | |
53 context->current_subcode_dest = 0; | |
49 } | 54 } |
50 | 55 |
51 enum { | 56 enum { |
52 GAO_CDD_CTRL, | 57 GAO_CDD_CTRL, |
53 GAO_CDD_STATUS, | 58 GAO_CDD_STATUS, |
54 GAO_CDD_CMD = GAO_CDD_STATUS+5 | 59 GAO_CDD_CMD = GAO_CDD_STATUS+5, |
60 GAO_SUBCODE_ADDR = (0x68-0x36)/2, | |
61 GAO_SUBCODE_START = (0x100-0x36)/2 | |
55 }; | 62 }; |
56 //GAO_CDD_CTRL | 63 //GAO_CDD_CTRL |
57 #define BIT_MUTE 0x100 | 64 #define BIT_MUTE 0x100 |
58 #define BIT_HOCK 0x0004 | 65 #define BIT_HOCK 0x0004 |
59 #define BIT_DRS 0x0002 | 66 #define BIT_DRS 0x0002 |
374 case CMD_SEEK: { | 381 case CMD_SEEK: { |
375 if (context->status == DS_DOOR_OPEN || context->status == DS_TRAY_MOVING || context->status == DS_DISC_LEADOUT || context->status == DS_DISC_LEADIN) { | 382 if (context->status == DS_DOOR_OPEN || context->status == DS_TRAY_MOVING || context->status == DS_DISC_LEADOUT || context->status == DS_DISC_LEADIN) { |
376 context->error_status = DS_CMD_ERROR; | 383 context->error_status = DS_CMD_ERROR; |
377 break; | 384 break; |
378 } | 385 } |
379 if (context->requested_format == SF_TOCT || context->requested_format == SF_TOCN) { | 386 if (context->requested_format == SF_TOCT || context->requested_format == SF_TOCN || context->requested_format == SF_TOCO) { |
380 context->requested_format = SF_ABSOLUTE; | 387 context->requested_format = SF_ABSOLUTE; |
381 } | 388 } |
382 if (!context->toc_valid) { | 389 if (!context->toc_valid) { |
383 context->error_status = DS_CMD_ERROR; | 390 context->error_status = DS_CMD_ERROR; |
384 break; | 391 break; |
539 } | 546 } |
540 } | 547 } |
541 gate_array[GAO_CDD_CTRL] |= BIT_MUTE; | 548 gate_array[GAO_CDD_CTRL] |= BIT_MUTE; |
542 return; | 549 return; |
543 } | 550 } |
544 uint32_t next_subcode = context->last_subcode_cycle + SECTOR_CLOCKS; | 551 uint32_t next_subcode = context->last_sector_cycle + SECTOR_CLOCKS; |
545 uint32_t next_nibble; | 552 uint32_t next_nibble; |
546 if (context->current_status_nibble > 0) { | 553 if (context->current_status_nibble > 0) { |
547 next_nibble = context->last_nibble_cycle + NIBBLE_CLOCKS; | 554 next_nibble = context->last_nibble_cycle + NIBBLE_CLOCKS; |
548 } else if (!context->current_status_nibble) { | 555 } else if (!context->current_status_nibble) { |
549 next_nibble = context->last_subcode_cycle + PROCESSING_DELAY; | 556 next_nibble = context->last_sector_cycle + PROCESSING_DELAY; |
550 } else { | 557 } else { |
551 next_nibble = CYCLE_NEVER; | 558 next_nibble = CYCLE_NEVER; |
552 } | 559 } |
553 uint32_t next_cmd_nibble = context->current_cmd_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER; | 560 uint32_t next_cmd_nibble = context->current_cmd_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER; |
554 | 561 |
555 for (; context->cycle < cd_cycle; context->cycle += CDD_MCU_DIVIDER) | 562 for (; context->cycle < cd_cycle; context->cycle += CDD_MCU_DIVIDER) |
556 { | 563 { |
557 if (context->cycle >= next_subcode) { | 564 if (context->cycle >= next_subcode) { |
558 context->last_subcode_cycle = context->cycle; | 565 context->last_sector_cycle = context->cycle; |
559 next_subcode = context->cycle + SECTOR_CLOCKS; | 566 next_subcode = context->cycle + SECTOR_CLOCKS; |
560 update_status(context, gate_array); | 567 update_status(context, gate_array); |
561 next_nibble = context->cycle + PROCESSING_DELAY; | 568 next_nibble = context->cycle + PROCESSING_DELAY; |
562 context->current_status_nibble = 0; | 569 context->current_status_nibble = 0; |
563 gate_array[GAO_CDD_STATUS] |= BIT_DRS; | 570 gate_array[GAO_CDD_STATUS] |= BIT_DRS; |
571 if (context->next_subcode_int_cycle != CYCLE_NEVER) { | |
572 context->subcode_int_pending = 1; | |
573 } | |
564 if ((context->status == DS_PLAY || context->status == DS_PAUSE) && context->head_pba >= LEADIN_SECTORS) { | 574 if ((context->status == DS_PLAY || context->status == DS_PAUSE) && context->head_pba >= LEADIN_SECTORS) { |
565 context->current_sector_byte = 0; | 575 context->current_sector_byte = 0; |
576 context->current_subcode_byte = 0; | |
577 context->next_subcode_cycle = context->cycle; | |
578 context->next_subcode_int_cycle = cd_block_to_mclks(next_subcode); | |
579 } else { | |
580 context->next_subcode_int_cycle = CYCLE_NEVER; | |
566 } | 581 } |
567 } | 582 } |
568 if (context->cycle >= next_nibble) { | 583 if (context->cycle >= next_nibble) { |
569 if (context->current_status_nibble == sizeof(cdd_status)) { | 584 if (context->current_status_nibble == sizeof(cdd_status)) { |
570 context->current_status_nibble = -1; | 585 context->current_status_nibble = -1; |
616 cdd_fader_data(fader, gate_array[GAO_CDD_CTRL] & BIT_MUTE ? 0 : byte); | 631 cdd_fader_data(fader, gate_array[GAO_CDD_CTRL] & BIT_MUTE ? 0 : byte); |
617 } else { | 632 } else { |
618 cdd_fader_data(fader, 0); | 633 cdd_fader_data(fader, 0); |
619 if (context->current_sector_byte >= 0) { | 634 if (context->current_sector_byte >= 0) { |
620 next_subcode += BYTE_CLOCKS; | 635 next_subcode += BYTE_CLOCKS; |
621 context->last_subcode_cycle += BYTE_CLOCKS; | 636 context->last_sector_cycle += BYTE_CLOCKS; |
622 } | 637 } |
623 } | 638 } |
624 if (context->current_sector_byte == 2352) { | 639 if (context->current_sector_byte == 2352) { |
625 context->current_sector_byte = -1; | 640 context->current_sector_byte = -1; |
626 } | 641 } |
627 context->next_byte_cycle += BYTE_CLOCKS; | 642 context->next_byte_cycle += BYTE_CLOCKS; |
643 } | |
644 if (context->cycle >= context->next_subcode_cycle) { | |
645 uint8_t byte; | |
646 if (!context->current_subcode_byte) { | |
647 byte = 0x9F; | |
648 //This probably happens after the second sync symbol, but doing it here simplifies things a little | |
649 context->current_subcode_dest &= 0x7E; | |
650 gate_array[GAO_SUBCODE_ADDR] = (context->current_subcode_dest - 96) & 0x7E; | |
651 } else if (context->current_subcode_byte == 1) { | |
652 byte = 0xFD; | |
653 } else { | |
654 byte = context->media->read_subcodes(context->media, context->current_subcode_byte - 2); | |
655 } | |
656 int offset = GAO_SUBCODE_START + (context->current_subcode_dest >> 1); | |
657 if (context->current_subcode_dest & 1) { | |
658 gate_array[offset] &= 0xFF00; | |
659 gate_array[offset] |= byte; | |
660 } else { | |
661 gate_array[offset] &= 0x00FF; | |
662 gate_array[offset] |= byte << 8; | |
663 } | |
664 context->current_subcode_byte++; | |
665 if (context->current_subcode_byte == 98) { | |
666 context->current_subcode_byte = 0; | |
667 } else if (context->current_subcode_byte == 32) { | |
668 gate_array[GAO_SUBCODE_ADDR] |= 0x80; | |
669 } | |
670 context->current_subcode_dest++; | |
671 context->current_subcode_dest &= 0x7F; | |
672 context->next_subcode_cycle += SUBCODE_CLOCKS; | |
628 } | 673 } |
629 } | 674 } |
630 } | 675 } |
631 | 676 |
632 void cdd_mcu_start_cmd_recv(cdd_mcu *context, uint16_t *gate_array) | 677 void cdd_mcu_start_cmd_recv(cdd_mcu *context, uint16_t *gate_array) |
641 } | 686 } |
642 } | 687 } |
643 | 688 |
644 void cdd_hock_enabled(cdd_mcu *context) | 689 void cdd_hock_enabled(cdd_mcu *context) |
645 { | 690 { |
646 context->last_subcode_cycle = context->cycle; | 691 context->last_sector_cycle = context->cycle; |
647 context->next_int_cycle = cd_block_to_mclks(context->cycle + SECTOR_CLOCKS + PROCESSING_DELAY + 7 * NIBBLE_CLOCKS); | 692 context->next_int_cycle = cd_block_to_mclks(context->cycle + SECTOR_CLOCKS + PROCESSING_DELAY + 7 * NIBBLE_CLOCKS); |
648 } | 693 } |
649 | 694 |
650 void cdd_hock_disabled(cdd_mcu *context) | 695 void cdd_hock_disabled(cdd_mcu *context) |
651 { | 696 { |
652 context->last_subcode_cycle = CYCLE_NEVER; | 697 context->last_sector_cycle = CYCLE_NEVER; |
653 context->next_int_cycle = CYCLE_NEVER; | 698 context->next_int_cycle = CYCLE_NEVER; |
654 context->last_nibble_cycle = CYCLE_NEVER; | 699 context->last_nibble_cycle = CYCLE_NEVER; |
655 context->current_status_nibble = -1; | 700 context->current_status_nibble = -1; |
656 context->current_cmd_nibble = -1; | 701 context->current_cmd_nibble = -1; |
657 } | 702 } |
665 context->cycle = 0; | 710 context->cycle = 0; |
666 } | 711 } |
667 if (context->next_int_cycle != CYCLE_NEVER) { | 712 if (context->next_int_cycle != CYCLE_NEVER) { |
668 context->next_int_cycle -= deduction; | 713 context->next_int_cycle -= deduction; |
669 } | 714 } |
670 if (context->last_subcode_cycle != CYCLE_NEVER) { | 715 if (context->last_sector_cycle != CYCLE_NEVER) { |
671 if (context->last_subcode_cycle > cd_deduction) { | 716 if (context->last_sector_cycle > cd_deduction) { |
672 context->last_subcode_cycle -= cd_deduction; | 717 context->last_sector_cycle -= cd_deduction; |
673 } else { | 718 } else { |
674 context->last_subcode_cycle = 0; | 719 context->last_sector_cycle = 0; |
675 } | 720 } |
676 } | 721 } |
677 if (context->last_nibble_cycle != CYCLE_NEVER) { | 722 if (context->last_nibble_cycle != CYCLE_NEVER) { |
678 if (context->last_nibble_cycle > cd_deduction) { | 723 if (context->last_nibble_cycle > cd_deduction) { |
679 context->last_nibble_cycle -= cd_deduction; | 724 context->last_nibble_cycle -= cd_deduction; |
680 } else { | 725 } else { |
681 context->last_nibble_cycle = 0; | 726 context->last_nibble_cycle = 0; |
682 } | 727 } |
683 } | 728 } |
684 context->next_byte_cycle -= cd_deduction; | 729 context->next_byte_cycle -= cd_deduction; |
685 } | 730 if (context->next_subcode_cycle != CYCLE_NEVER) { |
731 context->next_subcode_cycle -= cd_deduction; | |
732 } | |
733 } |