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 }