comparison ym2612.c @ 359:cc39629e8d06

YM2612 WIP snapshot before register refactor
author Mike Pavone <pavone@retrodev.com>
date Mon, 27 May 2013 09:54:58 -0700
parents a8ee7934a1f8
children b7c3facee762
comparison
equal deleted inserted replaced
358:9498cfa7f7c8 359:cc39629e8d06
1 #include <string.h> 1 #include <string.h>
2 #include <math.h>
3 #include <stdio.h>
2 #include "ym2612.h" 4 #include "ym2612.h"
3 5
4 #define BUSY_CYCLES 17 6 #define BUSY_CYCLES 17
5 #define TIMERA_UPDATE_PERIOD 144 7 #define TIMERA_UPDATE_PERIOD 144
6 8
7 #define REG_TIMERA_HIGH 0x3 // 0x24 9 #define REG_TIMERA_HIGH 0x03 // 0x24
8 #define REG_TIMERA_LOW 0x4 // 0x25 10 #define REG_TIMERA_LOW 0x04 // 0x25
9 #define REG_TIMERB 0x5 // 0x26 11 #define REG_TIMERB 0x05 // 0x26
10 #define REG_TIME_CTRL 0x6 // 0x27 12 #define REG_TIME_CTRL 0x06 // 0x27
13 #define REG_DAC 0x0A // 0x2A
14 #define REG_DAC_ENABLE 0x0B // 0x2B
15
16 //offset to add to "shared" regs when looking for them in Part I
17 #define REG_SHARED 0x10
18
19
20 #define REG_ALG_FEEDBACK (0xB0-0x30)
21 #define REG_ATTACK_KS (0x50-0x30)
22 #define REG_DECAY_AM (0x60-0x30)
23 #define REG_SUSTAIN_RATE (0x70-0x30)
24
11 25
12 #define BIT_TIMERA_ENABLE 0x1 26 #define BIT_TIMERA_ENABLE 0x1
13 #define BIT_TIMERB_ENABLE 0x2 27 #define BIT_TIMERB_ENABLE 0x2
14 #define BIT_TIMERA_OVEREN 0x4 28 #define BIT_TIMERA_OVEREN 0x4
15 #define BIT_TIMERB_OVEREN 0x8 29 #define BIT_TIMERB_OVEREN 0x8
17 #define BIT_TIMERB_RESET 0x20 31 #define BIT_TIMERB_RESET 0x20
18 32
19 #define BIT_STATUS_TIMERA 0x1 33 #define BIT_STATUS_TIMERA 0x1
20 #define BIT_STATUS_TIMERB 0x2 34 #define BIT_STATUS_TIMERB 0x2
21 35
36 enum {
37 PHASE_ATTACK,
38 PHASE_DECAY,
39 PHASE_SUSTAIN,
40 PHASE_RELEASE
41 };
42
43 uint8_t did_tbl_init = 0;
44 //According to Nemesis, real hardware only uses a 256 entry quarter sine table; however,
45 //memory is cheap so using a half sine table will probably save some cycles
46 //a full sine table would be nice, but negative numbers don't get along with log2
47 #define SINE_TABLE_SIZE 512
48 uint16_t sine_table[SINE_TABLE_SIZE];
49 //Similar deal here with the power table for log -> linear conversion
50 //According to Nemesis, real hardware only uses a 256 entry table for the fractional part
51 //and uses the whole part as a shift amount.
52 #define POW_TABLE_SIZE (1 << 13)
53 uint16_t pow_table[POW_TABLE_SIZE];
54
55
56 uint16_t round_fixed_point(double value, int dec_bits)
57 {
58 return value * (1 << dec_bits) + 0.5;
59 }
60
22 void ym_init(ym2612_context * context) 61 void ym_init(ym2612_context * context)
23 { 62 {
24 memset(context, 0, sizeof(*context)); 63 memset(context, 0, sizeof(*context));
64 if (!did_tbl_init) {
65 //populate sine table
66 for (int32_t i = 0; i < 512; i++) {
67 double sine = sin( ((double)(i*2+1) / SINE_TABLE_SIZE) * M_PI_2 );
68
69 //table stores 4.8 fixed pointed representation of the base 2 log
70 sine_table[i] = round_fixed_point(-log2(sine), 8);
71 }
72 //populate power table
73 for (int32_t i = 0; i < POW_TABLE_SIZE; i++) {
74 double linear = pow(2, -((double)((i & 0xFF)+1) / 256.0));
75 int32_t tmp = round_fixed_point(linear, 11);
76 int32_t shift = (i >> 8) - 2;
77 if (shift < 0) {
78 tmp <<= 0-shift;
79 } else {
80 tmp >>= shift;
81 }
82 pow_table[i] = tmp;
83 }
84 }
25 } 85 }
26 86
27 void ym_run(ym2612_context * context, uint32_t to_cycle) 87 void ym_run(ym2612_context * context, uint32_t to_cycle)
28 { 88 {
29 uint32_t delta = to_cycle - context->current_cycle; 89 for (; context->current_cycle < to_cycle; context->current_cycle += 6) {
30 //Timers won't be perfect with this, but it's good enough for now 90 uint32_t update_cyc = context->current_cycle % 144;
31 //once actual FM emulation is in place the timers should just be 91 //Update timers at beginning of 144 cycle period
32 //decremented/reloaded on the appropriate ticks 92 if (!update_cyc && context->part1_regs[REG_TIME_CTRL] & BIT_TIMERA_ENABLE) {
33 uint32_t timer_delta = to_cycle / TIMERA_UPDATE_PERIOD; 93 if (context->timer_a) {
34 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERA_ENABLE) { 94 context->timer_a--;
35 if (timer_delta > context->timer_a) { 95 } else {
36 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERA_OVEREN) { 96 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERA_OVEREN) {
37 context->status |= BIT_STATUS_TIMERA; 97 context->status |= BIT_STATUS_TIMERA;
38 } 98 }
39 uint32_t rem_delta = timer_delta - (context->timer_a+1); 99 context->timer_a = (context->part1_regs[REG_TIMERA_HIGH] << 2) | (context->part1_regs[REG_TIMERA_LOW] & 0x3);
40 uint16_t timer_val = (context->part1_regs[REG_TIMERA_HIGH] << 2) | (context->part1_regs[REG_TIMERA_LOW] & 0x3); 100 }
41 context->timer_a = timer_val - (rem_delta % (timer_val + 1)); 101 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERB_ENABLE) {
42 } else { 102 uint32_t b_cyc = (context->current_cycle / 144) % 16;
43 context->timer_a -= timer_delta; 103 if (!b_cyc) {
44 } 104 if (context->timer_b) {
45 } 105 context->timer_b--;
46 timer_delta /= 16; //Timer B runs at 1/16th the speed of Timer A 106 } else {
47 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERB_ENABLE) { 107 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERB_OVEREN) {
48 if (timer_delta > context->timer_b) { 108 context->status |= BIT_STATUS_TIMERB;
49 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERB_OVEREN) { 109 }
50 context->status |= BIT_STATUS_TIMERB; 110 context->timer_b = context->part1_regs[REG_TIMERB];
51 } 111 }
52 uint32_t rem_delta = timer_delta - (context->timer_b+1); 112 }
53 uint8_t timer_val = context->part1_regs[REG_TIMERB]; 113 }
54 context->timer_b = timer_val - (rem_delta % (timer_val + 1)); 114 }
55 } else { 115 //Update Envelope Generator
56 context->timer_a -= timer_delta; 116 if (update_cyc == 0 || update_cyc == 72) {
57 } 117 uint32_t env_cyc = context->current_cycle / 72;
58 } 118 uint32_t op = env_cyc % 24;
59 context->current_cycle = to_cycle; 119 env_cyc /= 24;
60 if (to_cycle >= context->write_cycle + BUSY_CYCLES) { 120 uint8_t rate;
121 switch(context->env_phase[op])
122 {
123 case PHASE_ATTACK:
124 rate = (op < 3 ? context->part1_regs[REG_SHARED + REG_ATTACK_KS + op] : context->part2_regs[REG_ATTACK_KS + op - 3]) & 0x1F;
125 break;
126 case PHASE_DECAY:
127 rate = (op < 3 ? context->part1_regs[REG_SHARED + REG_DECAY_AM + op] : context->part2_regs[REG_DECAY_AM + op - 3]) & 0x1F;
128 break;
129 case PHASE_SUSTAIN:
130 rate = (op < 3 ? context->part1_regs[REG_SHARED + REG_SUSTAIN_RATE + op] : context->part2_regs[REG_SUSTAIN_RATE + op - 3]) & 0x1F;
131 break;
132 case PHASE_RELEASE:
133 rate = (op < 3 ? context->part1_regs[REG_SHARED + REG_DECAY_AM + op] : context->part2_regs[REG_DECAY_AM + op - 3]) << 1 & 0x1E | 1;
134 break;
135 }
136 if (rate) {
137 //apply key scaling
138 uint8_t shift = (op < 3 ?
139 context->part1_regs[REG_SHARED + REG_ATTACK_KS + op] :
140 context->part2_regs[REG_ATTACK_KS + op - 3]
141 ) >> 6;
142 uint8_t ks = context->keycode[op] >> (3 - shift);
143 rate = rate*2 + ks;
144 if (rate > 63) {
145 rate = 63;
146 }
147 }
148 }
149 //Update Phase Generator
150 uint32_t channel = update_cyc / 24;
151 if (channel != 6 || !(context->part1_regs[REG_DAC_ENABLE] & 0x80)) {
152 uint32_t op = (update_cyc) / 6;
153 uint8_t alg;
154 if (op < 3) {
155 alg = context->part1_regs[REG_SHARED + REG_ALG_FEEDBACK + op] & 0x7;
156 } else {
157 alg = context->part2_regs[REG_ALG_FEEDBACK + op-3] & 0x7;
158 }
159 context->phase_counter[op] += context->phase_inc[op];
160 uint16_t phase = context->phase_counter[op] >> 10 & 0x3FF;
161 //TODO: Modulate phase if necessary
162 uint16_t output = pow_table[sine_table[phase & 0x1FF] + context->envelope[op]];
163 if (phase & 0x200) {
164 output = -output;
165 }
166 context->op_out[op] = output;
167 //Update the channel output if we've updated all operators
168 if (op % 4 == 3) {
169 if (alg < 4) {
170 context->channel_out[channel] = context->op_out[channel * 4 + 3];
171 } else if(alg == 4) {
172 context->channel_out[channel] = context->op_out[channel * 4 + 3] + context->op_out[channel * 4 + 1];
173 } else {
174 output = 0;
175 for (uint32_t op = ((alg == 7) ? 0 : 1) + channel*4; op < (channel+1)*4; op++) {
176 output += context->op_out[op];
177 }
178 context->channel_out[channel] = output;
179 }
180 }
181 }
182
183 }
184 if (context->current_cycle >= context->write_cycle + BUSY_CYCLES) {
61 context->status &= 0x7F; 185 context->status &= 0x7F;
62 } 186 }
63 } 187 }
64 188
65 void ym_address_write_part1(ym2612_context * context, uint8_t address) 189 void ym_address_write_part1(ym2612_context * context, uint8_t address)