Mercurial > repos > blastem
comparison ym2612.c @ 2081:cfd53c94fffb
Initial stab at RF5C164 emulation
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 03 Feb 2022 23:15:42 -0800 |
parents | 1e7a63f0ccf4 |
children | 0d1d5dccdd28 |
comparison
equal
deleted
inserted
replaced
2080:bafb757e1cd2 | 2081:cfd53c94fffb |
---|---|
170 context->timer_a_load = 0; | 170 context->timer_a_load = 0; |
171 context->timer_b_load = 0; | 171 context->timer_b_load = 0; |
172 //TODO: Confirm these on hardware | 172 //TODO: Confirm these on hardware |
173 context->timer_a = TIMER_A_MAX; | 173 context->timer_a = TIMER_A_MAX; |
174 context->timer_b = TIMER_B_MAX; | 174 context->timer_b = TIMER_B_MAX; |
175 | 175 |
176 //TODO: Reset LFO state | 176 //TODO: Reset LFO state |
177 | 177 |
178 //some games seem to expect that the LR flags start out as 1 | 178 //some games seem to expect that the LR flags start out as 1 |
179 for (int i = 0; i < NUM_CHANNELS; i++) { | 179 for (int i = 0; i < NUM_CHANNELS; i++) { |
180 context->channels[i].lr = 0xC0; | 180 context->channels[i].lr = 0xC0; |
181 context->channels[i].logfile = savedlogs[i]; | 181 context->channels[i].logfile = savedlogs[i]; |
182 if (i < 3) { | 182 if (i < 3) { |
197 static uint8_t registered_finalize; | 197 static uint8_t registered_finalize; |
198 dfopen(debug_file, "ym_debug.txt", "w"); | 198 dfopen(debug_file, "ym_debug.txt", "w"); |
199 memset(context, 0, sizeof(*context)); | 199 memset(context, 0, sizeof(*context)); |
200 context->clock_inc = clock_div * 6; | 200 context->clock_inc = clock_div * 6; |
201 context->busy_cycles = BUSY_CYCLES * context->clock_inc; | 201 context->busy_cycles = BUSY_CYCLES * context->clock_inc; |
202 context->audio = render_audio_source(master_clock, context->clock_inc * NUM_OPERATORS, 2); | 202 context->audio = render_audio_source("YM2612", master_clock, context->clock_inc * NUM_OPERATORS, 2); |
203 //TODO: pick a randomish high initial value and lower it over time | 203 //TODO: pick a randomish high initial value and lower it over time |
204 context->invalid_status_decay = 225000 * context->clock_inc; | 204 context->invalid_status_decay = 225000 * context->clock_inc; |
205 context->status_address_mask = (options & YM_OPT_3834) ? 0 : 3; | 205 context->status_address_mask = (options & YM_OPT_3834) ? 0 : 3; |
206 | 206 |
207 //some games seem to expect that the LR flags start out as 1 | 207 //some games seem to expect that the LR flags start out as 1 |
208 for (int i = 0; i < NUM_CHANNELS; i++) { | 208 for (int i = 0; i < NUM_CHANNELS; i++) { |
209 if (options & YM_OPT_WAVE_LOG) { | 209 if (options & YM_OPT_WAVE_LOG) { |
210 char fname[64]; | 210 char fname[64]; |
211 sprintf(fname, "ym_channel_%d.wav", i); | 211 sprintf(fname, "ym_channel_%d.wav", i); |
478 } | 478 } |
479 //envelope value is 10-bits, but it will be used as a 4.8 value | 479 //envelope value is 10-bits, but it will be used as a 4.8 value |
480 operator->envelope += envelope_inc << 2; | 480 operator->envelope += envelope_inc << 2; |
481 //clamp to max attenuation value | 481 //clamp to max attenuation value |
482 if ( | 482 if ( |
483 operator->envelope > MAX_ENVELOPE | 483 operator->envelope > MAX_ENVELOPE |
484 || (operator->env_phase == PHASE_RELEASE && operator->envelope >= SSG_CENTER) | 484 || (operator->env_phase == PHASE_RELEASE && operator->envelope >= SSG_CENTER) |
485 ) { | 485 ) { |
486 operator->envelope = MAX_ENVELOPE; | 486 operator->envelope = MAX_ENVELOPE; |
487 } | 487 } |
488 } | 488 } |
522 } | 522 } |
523 } else if (!(operator->ssg & SSG_HOLD)) { | 523 } else if (!(operator->ssg & SSG_HOLD)) { |
524 phase = operator->phase_counter = 0; | 524 phase = operator->phase_counter = 0; |
525 } | 525 } |
526 if ( | 526 if ( |
527 (operator->env_phase == PHASE_DECAY || operator->env_phase == PHASE_SUSTAIN) | 527 (operator->env_phase == PHASE_DECAY || operator->env_phase == PHASE_SUSTAIN) |
528 && !(operator->ssg & SSG_HOLD) | 528 && !(operator->ssg & SSG_HOLD) |
529 ) { | 529 ) { |
530 start_envelope(operator, chan); | 530 start_envelope(operator, chan); |
531 env = operator->envelope; | 531 env = operator->envelope; |
532 } | 532 } |
663 context->current_op++; | 663 context->current_op++; |
664 if (context->current_op == NUM_OPERATORS) { | 664 if (context->current_op == NUM_OPERATORS) { |
665 context->current_op = 0; | 665 context->current_op = 0; |
666 ym_output_sample(context); | 666 ym_output_sample(context); |
667 } | 667 } |
668 | 668 |
669 } | 669 } |
670 //printf("Done running YM2612 at cycle %d\n", context->current_cycle, to_cycle); | 670 //printf("Done running YM2612 at cycle %d\n", context->current_cycle, to_cycle); |
671 } | 671 } |
672 | 672 |
673 void ym_address_write_part1(ym2612_context * context, uint8_t address) | 673 void ym_address_write_part1(ym2612_context * context, uint8_t address) |
797 //skip invalid registers | 797 //skip invalid registers |
798 continue; | 798 continue; |
799 } | 799 } |
800 vgm_ym2612_part1_write(context->vgm, context->current_cycle, reg, context->part1_regs[reg - YM_PART1_START]); | 800 vgm_ym2612_part1_write(context->vgm, context->current_cycle, reg, context->part1_regs[reg - YM_PART1_START]); |
801 } | 801 } |
802 | 802 |
803 for (uint8_t reg = YM_PART2_START; reg < YM_REG_END; reg++) { | 803 for (uint8_t reg = YM_PART2_START; reg < YM_REG_END; reg++) { |
804 if ((reg & 3) == 3 || (reg >= REG_FNUM_LOW_CH3 && reg < REG_ALG_FEEDBACK)) { | 804 if ((reg & 3) == 3 || (reg >= REG_FNUM_LOW_CH3 && reg < REG_ALG_FEEDBACK)) { |
805 //skip invalid registers | 805 //skip invalid registers |
806 continue; | 806 continue; |
807 } | 807 } |
811 | 811 |
812 void ym_data_write(ym2612_context * context, uint8_t value) | 812 void ym_data_write(ym2612_context * context, uint8_t value) |
813 { | 813 { |
814 context->write_cycle = context->current_cycle; | 814 context->write_cycle = context->current_cycle; |
815 context->busy_start = context->current_cycle + context->clock_inc; | 815 context->busy_start = context->current_cycle + context->clock_inc; |
816 | 816 |
817 if (context->selected_reg >= YM_REG_END) { | 817 if (context->selected_reg >= YM_REG_END) { |
818 return; | 818 return; |
819 } | 819 } |
820 if (context->selected_part) { | 820 if (context->selected_part) { |
821 if (context->selected_reg < YM_PART2_START) { | 821 if (context->selected_reg < YM_PART2_START) { |
910 uint8_t channel = value & 0x7; | 910 uint8_t channel = value & 0x7; |
911 if (channel != 3 && channel != 7) { | 911 if (channel != 3 && channel != 7) { |
912 if (channel > 2) { | 912 if (channel > 2) { |
913 channel--; | 913 channel--; |
914 } | 914 } |
915 uint8_t changes = channel == 2 | 915 uint8_t changes = channel == 2 |
916 ? (value | context->csm_keyon) ^ (context->channels[channel].keyon | context->csm_keyon) | 916 ? (value | context->csm_keyon) ^ (context->channels[channel].keyon | context->csm_keyon) |
917 : value ^ context->channels[channel].keyon; | 917 : value ^ context->channels[channel].keyon; |
918 context->channels[channel].keyon = value & 0xF0; | 918 context->channels[channel].keyon = value & 0xF0; |
919 for (uint8_t op = channel * 4, bit = 0; op < (channel + 1) * 4; op++, bit++) { | 919 for (uint8_t op = channel * 4, bit = 0; op < (channel + 1) * 4; op++, bit++) { |
920 if (changes & keyon_bits[bit]) { | 920 if (changes & keyon_bits[bit]) { |
1035 //operator 3 modulated by operator 2 | 1035 //operator 3 modulated by operator 2 |
1036 //this uses a special op2 result reg on HW, but that reg will have the most recent | 1036 //this uses a special op2 result reg on HW, but that reg will have the most recent |
1037 //result from op2 when op3 starts executing | 1037 //result from op2 when op3 starts executing |
1038 context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+2].output; | 1038 context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+2].output; |
1039 context->operators[channel*4+1].mod_src[1] = NULL; | 1039 context->operators[channel*4+1].mod_src[1] = NULL; |
1040 | 1040 |
1041 //operator 2 modulated by operator 1 | 1041 //operator 2 modulated by operator 1 |
1042 context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; | 1042 context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; |
1043 | 1043 |
1044 //operator 4 modulated by operator 3 | 1044 //operator 4 modulated by operator 3 |
1045 context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output; | 1045 context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output; |
1046 context->operators[channel*4+3].mod_src[1] = NULL; | 1046 context->operators[channel*4+3].mod_src[1] = NULL; |
1047 break; | 1047 break; |
1048 case 1: | 1048 case 1: |
1051 //not available and instead the previous result is used | 1051 //not available and instead the previous result is used |
1052 context->operators[channel*4+1].mod_src[0] = &context->channels[channel].op1_old; | 1052 context->operators[channel*4+1].mod_src[0] = &context->channels[channel].op1_old; |
1053 //this uses a special op2 result reg on HW, but that reg will have the most recent | 1053 //this uses a special op2 result reg on HW, but that reg will have the most recent |
1054 //result from op2 when op3 starts executing | 1054 //result from op2 when op3 starts executing |
1055 context->operators[channel*4+1].mod_src[1] = &context->operators[channel*4+2].output; | 1055 context->operators[channel*4+1].mod_src[1] = &context->operators[channel*4+2].output; |
1056 | 1056 |
1057 //operator 2 unmodulated | 1057 //operator 2 unmodulated |
1058 context->operators[channel*4+2].mod_src[0] = NULL; | 1058 context->operators[channel*4+2].mod_src[0] = NULL; |
1059 | 1059 |
1060 //operator 4 modulated by operator 3 | 1060 //operator 4 modulated by operator 3 |
1061 context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output; | 1061 context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output; |
1062 context->operators[channel*4+3].mod_src[1] = NULL; | 1062 context->operators[channel*4+3].mod_src[1] = NULL; |
1063 break; | 1063 break; |
1064 case 2: | 1064 case 2: |
1065 //operator 3 modulated by operator 2 | 1065 //operator 3 modulated by operator 2 |
1066 //this uses a special op2 result reg on HW, but that reg will have the most recent | 1066 //this uses a special op2 result reg on HW, but that reg will have the most recent |
1067 //result from op2 when op3 starts executing | 1067 //result from op2 when op3 starts executing |
1068 context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+2].output; | 1068 context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+2].output; |
1069 context->operators[channel*4+1].mod_src[1] = NULL; | 1069 context->operators[channel*4+1].mod_src[1] = NULL; |
1070 | 1070 |
1071 //operator 2 unmodulated | 1071 //operator 2 unmodulated |
1072 context->operators[channel*4+2].mod_src[0] = NULL; | 1072 context->operators[channel*4+2].mod_src[0] = NULL; |
1073 | 1073 |
1074 //operator 4 modulated by operator 1+3 | 1074 //operator 4 modulated by operator 1+3 |
1075 //this uses a special op1 result reg on HW, but that reg will have the most recent | 1075 //this uses a special op1 result reg on HW, but that reg will have the most recent |
1076 //result from op1 when op4 starts executing | 1076 //result from op1 when op4 starts executing |
1077 context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+0].output; | 1077 context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+0].output; |
1078 context->operators[channel*4+3].mod_src[1] = &context->operators[channel*4+1].output; | 1078 context->operators[channel*4+3].mod_src[1] = &context->operators[channel*4+1].output; |
1079 break; | 1079 break; |
1080 case 3: | 1080 case 3: |
1081 //operator 3 unmodulated | 1081 //operator 3 unmodulated |
1082 context->operators[channel*4+1].mod_src[0] = NULL; | 1082 context->operators[channel*4+1].mod_src[0] = NULL; |
1083 context->operators[channel*4+1].mod_src[1] = NULL; | 1083 context->operators[channel*4+1].mod_src[1] = NULL; |
1084 | 1084 |
1085 //operator 2 modulated by operator 1 | 1085 //operator 2 modulated by operator 1 |
1086 context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; | 1086 context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; |
1087 | 1087 |
1088 //operator 4 modulated by operator 2+3 | 1088 //operator 4 modulated by operator 2+3 |
1089 //op2 starts executing before this, but due to pipeline length the most current result is | 1089 //op2 starts executing before this, but due to pipeline length the most current result is |
1090 //not available and instead the previous result is used | 1090 //not available and instead the previous result is used |
1091 context->operators[channel*4+3].mod_src[0] = &context->channels[channel].op2_old; | 1091 context->operators[channel*4+3].mod_src[0] = &context->channels[channel].op2_old; |
1092 context->operators[channel*4+3].mod_src[1] = &context->operators[channel*4+1].output; | 1092 context->operators[channel*4+3].mod_src[1] = &context->operators[channel*4+1].output; |
1093 break; | 1093 break; |
1094 case 4: | 1094 case 4: |
1095 //operator 3 unmodulated | 1095 //operator 3 unmodulated |
1096 context->operators[channel*4+1].mod_src[0] = NULL; | 1096 context->operators[channel*4+1].mod_src[0] = NULL; |
1097 context->operators[channel*4+1].mod_src[1] = NULL; | 1097 context->operators[channel*4+1].mod_src[1] = NULL; |
1098 | 1098 |
1099 //operator 2 modulated by operator 1 | 1099 //operator 2 modulated by operator 1 |
1100 context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; | 1100 context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; |
1101 | 1101 |
1102 //operator 4 modulated by operator 3 | 1102 //operator 4 modulated by operator 3 |
1103 context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output; | 1103 context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output; |
1104 context->operators[channel*4+3].mod_src[1] = NULL; | 1104 context->operators[channel*4+3].mod_src[1] = NULL; |
1105 break; | 1105 break; |
1106 case 5: | 1106 case 5: |
1107 //operator 3 modulated by operator 1 | 1107 //operator 3 modulated by operator 1 |
1108 //op1 starts executing before this, but due to pipeline length the most current result is | 1108 //op1 starts executing before this, but due to pipeline length the most current result is |
1109 //not available and instead the previous result is used | 1109 //not available and instead the previous result is used |
1110 context->operators[channel*4+1].mod_src[0] = &context->channels[channel].op1_old; | 1110 context->operators[channel*4+1].mod_src[0] = &context->channels[channel].op1_old; |
1111 context->operators[channel*4+1].mod_src[1] = NULL; | 1111 context->operators[channel*4+1].mod_src[1] = NULL; |
1112 | 1112 |
1113 //operator 2 modulated by operator 1 | 1113 //operator 2 modulated by operator 1 |
1114 context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; | 1114 context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; |
1115 | 1115 |
1116 //operator 4 modulated by operator 1 | 1116 //operator 4 modulated by operator 1 |
1117 //this uses a special op1 result reg on HW, but that reg will have the most recent | 1117 //this uses a special op1 result reg on HW, but that reg will have the most recent |
1118 //result from op1 when op4 starts executing | 1118 //result from op1 when op4 starts executing |
1119 context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+0].output; | 1119 context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+0].output; |
1120 context->operators[channel*4+3].mod_src[1] = NULL; | 1120 context->operators[channel*4+3].mod_src[1] = NULL; |
1121 break; | 1121 break; |
1122 case 6: | 1122 case 6: |
1123 //operator 3 unmodulated | 1123 //operator 3 unmodulated |
1124 context->operators[channel*4+1].mod_src[0] = NULL; | 1124 context->operators[channel*4+1].mod_src[0] = NULL; |
1125 context->operators[channel*4+1].mod_src[1] = NULL; | 1125 context->operators[channel*4+1].mod_src[1] = NULL; |
1126 | 1126 |
1127 //operator 2 modulated by operator 1 | 1127 //operator 2 modulated by operator 1 |
1128 context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; | 1128 context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; |
1129 | 1129 |
1130 //operator 4 unmodulated | 1130 //operator 4 unmodulated |
1131 context->operators[channel*4+3].mod_src[0] = NULL; | 1131 context->operators[channel*4+3].mod_src[0] = NULL; |
1132 context->operators[channel*4+3].mod_src[1] = NULL; | 1132 context->operators[channel*4+3].mod_src[1] = NULL; |
1133 break; | 1133 break; |
1134 case 7: | 1134 case 7: |
1135 //everything is an output so no modulation (except for op 1 feedback) | 1135 //everything is an output so no modulation (except for op 1 feedback) |
1136 context->operators[channel*4+1].mod_src[0] = NULL; | 1136 context->operators[channel*4+1].mod_src[0] = NULL; |
1137 context->operators[channel*4+1].mod_src[1] = NULL; | 1137 context->operators[channel*4+1].mod_src[1] = NULL; |
1138 | 1138 |
1139 context->operators[channel*4+2].mod_src[0] = NULL; | 1139 context->operators[channel*4+2].mod_src[0] = NULL; |
1140 | 1140 |
1141 context->operators[channel*4+3].mod_src[0] = NULL; | 1141 context->operators[channel*4+3].mod_src[0] = NULL; |
1142 context->operators[channel*4+3].mod_src[1] = NULL; | 1142 context->operators[channel*4+3].mod_src[1] = NULL; |
1143 break; | 1143 break; |
1144 } | 1144 } |
1145 context->channels[channel].feedback = value >> 3 & 0x7; | 1145 context->channels[channel].feedback = value >> 3 & 0x7; |
1180 } | 1180 } |
1181 context->last_status = status; | 1181 context->last_status = status; |
1182 context->last_status_cycle = cycle; | 1182 context->last_status_cycle = cycle; |
1183 } | 1183 } |
1184 return status; | 1184 return status; |
1185 | 1185 |
1186 } | 1186 } |
1187 | 1187 |
1188 void ym_print_channel_info(ym2612_context *context, int channel) | 1188 void ym_print_channel_info(ym2612_context *context, int channel) |
1189 { | 1189 { |
1190 ym_channel *chan = context->channels + channel; | 1190 ym_channel *chan = context->channels + channel; |