Mercurial > repos > blastem
annotate ym2612.c @ 364:62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 29 May 2013 00:57:19 -0700 |
parents | b7c3facee762 |
children | 3ba3b6656fff |
rev | line source |
---|---|
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
1 #include <string.h> |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
2 #include <math.h> |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
3 #include <stdio.h> |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
4 #include <stdlib.h> |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
5 #include "ym2612.h" |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
6 #include "render.h" |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
7 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
8 #define BUSY_CYCLES 17 |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
9 #define OP_UPDATE_PERIOD 144 |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
10 |
362 | 11 enum { |
12 REG_TIMERA_HIGH = 0x24, | |
13 REG_TIMERA_LOW, | |
14 REG_TIMERB, | |
15 REG_TIME_CTRL, | |
16 REG_KEY_ONOFF, | |
17 REG_DAC = 0x2A, | |
18 REG_DAC_ENABLE, | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
19 |
362 | 20 REG_DETUNE_MULT = 0x30, |
21 REG_TOTAL_LEVEL = 0x40, | |
22 REG_ATTACK_KS = 0x50, | |
23 REG_DECAY_AM = 0x60, | |
24 REG_SUSTAIN_RATE = 0x70, | |
25 REG_S_LVL_R_RATE = 0x80, | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
26 |
362 | 27 REG_FNUM_LOW = 0xA0, |
28 REG_BLOCK_FNUM_H = 0xA4, | |
29 REG_FNUM_LOW_CH3 = 0xA8, | |
30 REG_BLOCK_FN_CH3 = 0xAC, | |
31 REG_ALG_FEEDBACK = 0xB0, | |
32 REG_LR_AMS_PMS = 0xB4 | |
33 }; | |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
34 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
35 #define BIT_TIMERA_ENABLE 0x1 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
36 #define BIT_TIMERB_ENABLE 0x2 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
37 #define BIT_TIMERA_OVEREN 0x4 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
38 #define BIT_TIMERB_OVEREN 0x8 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
39 #define BIT_TIMERA_RESET 0x10 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
40 #define BIT_TIMERB_RESET 0x20 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
41 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
42 #define BIT_STATUS_TIMERA 0x1 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
43 #define BIT_STATUS_TIMERB 0x2 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
44 |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
45 enum { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
46 PHASE_ATTACK, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
47 PHASE_DECAY, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
48 PHASE_SUSTAIN, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
49 PHASE_RELEASE |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
50 }; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
51 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
52 uint8_t did_tbl_init = 0; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
53 //According to Nemesis, real hardware only uses a 256 entry quarter sine table; however, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
54 //memory is cheap so using a half sine table will probably save some cycles |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
55 //a full sine table would be nice, but negative numbers don't get along with log2 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
56 #define SINE_TABLE_SIZE 512 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
57 uint16_t sine_table[SINE_TABLE_SIZE]; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
58 //Similar deal here with the power table for log -> linear conversion |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
59 //According to Nemesis, real hardware only uses a 256 entry table for the fractional part |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
60 //and uses the whole part as a shift amount. |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
61 #define POW_TABLE_SIZE (1 << 13) |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
62 uint16_t pow_table[POW_TABLE_SIZE]; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
63 |
362 | 64 uint16_t rate_table_base[] = { |
65 //main portion | |
66 0,1,0,1,0,1,0,1, | |
67 0,1,0,1,1,1,0,1, | |
68 0,1,1,1,0,1,1,1, | |
69 0,1,1,1,1,1,1,1, | |
70 //top end | |
71 1,1,1,1,1,1,1,1, | |
72 1,1,1,2,1,1,1,2, | |
73 1,2,1,2,1,2,1,2, | |
74 1,2,2,2,1,2,2,2, | |
75 }; | |
76 | |
77 uint16_t rate_table[64]; | |
78 | |
79 #define MAX_ENVELOPE 0xFFC | |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
80 #define YM_DIVIDER 2 |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
81 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
82 uint16_t round_fixed_point(double value, int dec_bits) |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
83 { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
84 return value * (1 << dec_bits) + 0.5; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
85 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
86 |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
87 void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t clock_rate, uint32_t sample_limit) |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
88 { |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
89 memset(context, 0, sizeof(*context)); |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
90 context->audio_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
91 context->back_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
92 context->buffer_inc = (double)sample_rate / (double)(clock_rate/OP_UPDATE_PERIOD); |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
93 context->sample_limit = sample_limit*2; |
362 | 94 for (int i = 0; i < NUM_OPERATORS; i++) { |
95 context->operators[i].envelope = MAX_ENVELOPE; | |
96 context->operators[i].env_phase = PHASE_RELEASE; | |
97 } | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
98 if (!did_tbl_init) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
99 //populate sine table |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
100 for (int32_t i = 0; i < 512; i++) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
101 double sine = sin( ((double)(i*2+1) / SINE_TABLE_SIZE) * M_PI_2 ); |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
102 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
103 //table stores 4.8 fixed pointed representation of the base 2 log |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
104 sine_table[i] = round_fixed_point(-log2(sine), 8); |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
105 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
106 //populate power table |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
107 for (int32_t i = 0; i < POW_TABLE_SIZE; i++) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
108 double linear = pow(2, -((double)((i & 0xFF)+1) / 256.0)); |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
109 int32_t tmp = round_fixed_point(linear, 11); |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
110 int32_t shift = (i >> 8) - 2; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
111 if (shift < 0) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
112 tmp <<= 0-shift; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
113 } else { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
114 tmp >>= shift; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
115 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
116 pow_table[i] = tmp; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
117 } |
362 | 118 //populate envelope generator rate table, from small base table |
119 for (int rate = 0; rate < 64; rate++) { | |
120 for (int cycle = 0; cycle < 7; cycle++) { | |
121 uint16_t value; | |
122 if (rate < 3) { | |
123 value = 0; | |
124 } else if (value >= 60) { | |
125 value = 8; | |
126 } else if (value < 8) { | |
127 value = rate_table_base[((rate & 6) == 6 ? 16 : 8) + cycle]; | |
128 } else if (value < 48) { | |
129 value = rate_table_base[(rate & 0x3) * 8 + cycle]; | |
130 } else { | |
131 value = rate_table_base[32 + (rate & 0x3) * 8 + cycle] << (rate >> 2); | |
132 } | |
133 } | |
134 } | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
135 } |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
136 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
137 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
138 void ym_run(ym2612_context * context, uint32_t to_cycle) |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
139 { |
362 | 140 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); |
141 //TODO: Fix channel update order OR remap channels in register write | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
142 for (; context->current_cycle < to_cycle; context->current_cycle += 6) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
143 //Update timers at beginning of 144 cycle period |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
144 if (!context->current_op && context->timer_control & BIT_TIMERA_ENABLE) { |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
145 if (context->timer_a) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
146 context->timer_a--; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
147 } else { |
362 | 148 if (context->timer_control & BIT_TIMERA_OVEREN) { |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
149 context->status |= BIT_STATUS_TIMERA; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
150 } |
362 | 151 context->timer_a = context->timer_a_load; |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
152 } |
362 | 153 if (context->timer_control & BIT_TIMERB_ENABLE) { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
154 uint32_t b_cyc = (context->current_cycle / OP_UPDATE_PERIOD) % 16; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
155 if (!b_cyc) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
156 if (context->timer_b) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
157 context->timer_b--; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
158 } else { |
362 | 159 if (context->timer_control & BIT_TIMERB_OVEREN) { |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
160 context->status |= BIT_STATUS_TIMERB; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
161 } |
362 | 162 context->timer_b = context->timer_b_load; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
163 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
164 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
165 } |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
166 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
167 //Update Envelope Generator |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
168 if (!(context->current_op % 3)) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
169 uint32_t env_cyc = context->env_counter; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
170 uint32_t op = context->current_env_op; |
362 | 171 ym_operator * operator = context->operators + op; |
172 ym_channel * channel = context->channels + op/4; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
173 uint8_t rate; |
362 | 174 for(;;) { |
175 rate = operator->rates[operator->env_phase]; | |
176 if (rate) { | |
177 uint8_t ks = channel->keycode >> operator->key_scaling;; | |
178 rate = rate*2 + ks; | |
179 if (rate > 63) { | |
180 rate = 63; | |
181 } | |
182 } | |
183 //Deal with "infinite" rates | |
184 //It's possible this should be handled in key-on as well | |
185 if (rate == 63 && operator->env_phase < PHASE_SUSTAIN) { | |
186 if (operator->env_phase == PHASE_ATTACK) { | |
187 operator->env_phase = PHASE_DECAY; | |
188 operator->envelope = operator->total_level; | |
189 } else { | |
190 operator->env_phase = PHASE_SUSTAIN; | |
191 operator->envelope = operator->sustain_level; | |
192 } | |
193 } else { | |
194 break; | |
195 } | |
196 } | |
197 uint32_t cycle_shift = rate < 0x30 ? ((0x2F - rate) >> 2) : 0; | |
198 if (!(env_cyc & ((1 << cycle_shift) - 1))) { | |
199 uint32_t update_cycle = env_cyc >> cycle_shift & 0x7; | |
200 //envelope value is 10-bits, but it will be used as a 4.8 value | |
201 uint16_t envelope_inc = rate_table[rate * 8 + update_cycle] << 2; | |
202 if (operator->env_phase == PHASE_ATTACK) { | |
203 //this can probably be optimized to a single shift rather than a multiply + shift | |
204 operator->envelope += (~operator->envelope * envelope_inc) >> 4; | |
205 operator->envelope &= MAX_ENVELOPE; | |
206 if (operator->envelope <= operator->total_level) { | |
207 operator->envelope = operator->total_level; | |
208 operator->env_phase = PHASE_DECAY; | |
209 } | |
210 } else { | |
211 operator->envelope += envelope_inc; | |
212 //clamp to max attenuation value | |
213 if (operator->envelope > MAX_ENVELOPE) { | |
214 operator->envelope = MAX_ENVELOPE; | |
215 } | |
216 if (operator->env_phase == PHASE_DECAY && operator->envelope >= operator->sustain_level) { | |
217 operator->envelope = operator->sustain_level; | |
218 operator->env_phase = PHASE_SUSTAIN; | |
219 } | |
220 } | |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
221 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
222 context->current_env_op++; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
223 if (context->current_env_op == NUM_OPERATORS) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
224 context->current_env_op = 0; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
225 context->env_counter++; |
362 | 226 } |
227 } | |
228 | |
229 //Update Phase Generator | |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
230 uint32_t channel = context->current_op / 4; |
362 | 231 if (channel != 5 || !context->dac_enable) { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
232 uint32_t op = context->current_op; |
362 | 233 //printf("updating operator %d of channel %d\n", op, channel); |
234 ym_operator * operator = context->operators + op; | |
235 ym_channel * chan = context->channels + channel; | |
236 //TODO: Modulate phase by LFO if necessary | |
237 operator->phase_counter += operator->phase_inc; | |
238 uint16_t phase = operator->phase_counter >> 10 & 0x3FF; | |
239 switch (op % 4) | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
240 { |
362 | 241 case 0://Operator 1 |
242 //TODO: Feedback | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
243 break; |
362 | 244 case 1://Operator 3 |
245 switch(chan->algorithm) | |
246 { | |
247 case 0: | |
248 case 2: | |
249 //modulate by operator 2 | |
250 phase += context->operators[op+1].output >> 4; | |
251 break; | |
252 case 1: | |
253 //modulate by operator 1+2 | |
254 phase += (context->operators[op-1].output + context->operators[op+1].output) >> 4; | |
255 break; | |
256 case 5: | |
257 //modulate by operator 1 | |
258 phase += context->operators[op-1].output >> 4; | |
259 } | |
260 break; | |
261 case 2://Operator 2 | |
262 if (chan->algorithm != 1 && chan->algorithm != 2 || chan->algorithm != 7) { | |
263 //modulate by Operator 1 | |
264 phase += context->operators[op-2].output >> 4; | |
265 } | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
266 break; |
362 | 267 case 3://Operator 4 |
268 switch(chan->algorithm) | |
269 { | |
270 case 0: | |
271 case 1: | |
272 case 4: | |
273 //modulate by operator 3 | |
274 phase += context->operators[op-2].output >> 4; | |
275 break; | |
276 case 2: | |
277 //modulate by operator 1+3 | |
278 phase += (context->operators[op-3].output + context->operators[op-2].output) >> 4; | |
279 break; | |
280 case 3: | |
281 //modulate by operator 2+3 | |
282 phase += (context->operators[op-1].output + context->operators[op-2].output) >> 4; | |
283 break; | |
284 case 5: | |
285 //modulate by operator 1 | |
286 phase += context->operators[op-3].output >> 4; | |
287 break; | |
288 } | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
289 break; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
290 } |
362 | 291 //printf("sine_table[%X] + %X = %X, sizeof(pow_table)/sizeof(*pow_table) = %X\n", phase & 0x1FF, operator->envelope, sine_table[phase & 0x1FF] + operator->envelope, sizeof(pow_table)/ sizeof(*pow_table)); |
292 uint16_t output = pow_table[sine_table[phase & 0x1FF] + operator->envelope]; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
293 if (phase & 0x200) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
294 output = -output; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
295 } |
362 | 296 operator->output = output; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
297 //Update the channel output if we've updated all operators |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
298 if (op % 4 == 3) { |
362 | 299 if (chan->algorithm < 4) { |
300 chan->output = operator->output; | |
301 } else if(chan->algorithm == 4) { | |
302 chan->output = operator->output + context->operators[channel * 4 + 1].output; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
303 } else { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
304 output = 0; |
362 | 305 for (uint32_t op = ((chan->algorithm == 7) ? 0 : 1) + channel*4; op < (channel+1)*4; op++) { |
306 output += context->operators[op].output; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
307 } |
362 | 308 chan->output = output; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
309 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
310 } |
362 | 311 //puts("operator update done"); |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
312 } |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
313 context->current_op++; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
314 if (context->current_op == NUM_OPERATORS) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
315 context->current_op = 0; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
316 context->buffer_fraction += context->buffer_inc; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
317 if (context->buffer_fraction > 1.0) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
318 context->buffer_fraction -= 1.0; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
319 context->audio_buffer[context->buffer_pos] = 0; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
320 context->audio_buffer[context->buffer_pos + 1] = 0; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
321 for (int i = 0; i < NUM_CHANNELS; i++) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
322 uint16_t value = context->channels[i].output & 0x3FE0; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
323 if (value & 0x2000) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
324 value |= 0xC000; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
325 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
326 if (context->channels[i].lr & 0x80) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
327 context->audio_buffer[context->buffer_pos] += value / 2; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
328 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
329 if (context->channels[i].lr & 0x40) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
330 context->audio_buffer[context->buffer_pos+1] += value / 2; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
331 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
332 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
333 context->buffer_pos += 2; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
334 if (context->buffer_pos == context->sample_limit) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
335 render_wait_ym(context); |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
336 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
337 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
338 } |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
339 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
340 if (context->current_cycle >= context->write_cycle + BUSY_CYCLES) { |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
341 context->status &= 0x7F; |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
342 } |
362 | 343 //printf("Done running YM2612 at cycle %d\n", context->current_cycle, to_cycle); |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
344 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
345 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
346 void ym_address_write_part1(ym2612_context * context, uint8_t address) |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
347 { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
348 //printf("address_write_part1: %X\n", address); |
362 | 349 context->selected_reg = address; |
350 context->selected_part = 0; | |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
351 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
352 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
353 void ym_address_write_part2(ym2612_context * context, uint8_t address) |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
354 { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
355 //printf("address_write_part2: %X\n", address); |
362 | 356 context->selected_reg = address; |
357 context->selected_part = 1; | |
358 } | |
359 | |
360 uint8_t fnum_to_keycode[] = { | |
361 //F11 = 0 | |
362 0,0,0,0,0,0,0,1, | |
363 //F11 = 1 | |
364 2,3,3,3,3,3,3,3 | |
365 }; | |
366 | |
367 //table courtesy of Nemesis | |
368 uint32_t detune_table[][4] = { | |
369 {0, 0, 1, 2}, //0 (0x00) | |
370 {0, 0, 1, 2}, //1 (0x01) | |
371 {0, 0, 1, 2}, //2 (0x02) | |
372 {0, 0, 1, 2}, //3 (0x03) | |
373 {0, 1, 2, 2}, //4 (0x04) | |
374 {0, 1, 2, 3}, //5 (0x05) | |
375 {0, 1, 2, 3}, //6 (0x06) | |
376 {0, 1, 2, 3}, //7 (0x07) | |
377 {0, 1, 2, 4}, //8 (0x08) | |
378 {0, 1, 3, 4}, //9 (0x09) | |
379 {0, 1, 3, 4}, //10 (0x0A) | |
380 {0, 1, 3, 5}, //11 (0x0B) | |
381 {0, 2, 4, 5}, //12 (0x0C) | |
382 {0, 2, 4, 6}, //13 (0x0D) | |
383 {0, 2, 4, 6}, //14 (0x0E) | |
384 {0, 2, 5, 7}, //15 (0x0F) | |
385 {0, 2, 5, 8}, //16 (0x10) | |
386 {0, 3, 6, 8}, //17 (0x11) | |
387 {0, 3, 6, 9}, //18 (0x12) | |
388 {0, 3, 7,10}, //19 (0x13) | |
389 {0, 4, 8,11}, //20 (0x14) | |
390 {0, 4, 8,12}, //21 (0x15) | |
391 {0, 4, 9,13}, //22 (0x16) | |
392 {0, 5,10,14}, //23 (0x17) | |
393 {0, 5,11,16}, //24 (0x18) | |
394 {0, 6,12,17}, //25 (0x19) | |
395 {0, 6,13,19}, //26 (0x1A) | |
396 {0, 7,14,20}, //27 (0x1B) | |
397 {0, 8,16,22}, //28 (0x1C) | |
398 {0, 8,16,22}, //29 (0x1D) | |
399 {0, 8,16,22}, //30 (0x1E) | |
400 {0, 8,16,22} | |
401 }; //31 (0x1F) | |
402 | |
403 void ym_update_phase_inc(ym2612_context * context, ym_operator * operator, uint32_t op) | |
404 { | |
405 uint32_t chan_num = op / 4; | |
406 //printf("ym_update_phase_inc | channel: %d, op: %d\n", chan_num, op); | |
407 //base frequency | |
408 ym_channel * channel = context->channels + chan_num; | |
409 uint32_t inc = channel->fnum; | |
410 if (!channel->block) { | |
411 inc >> 1; | |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
412 } else { |
362 | 413 inc << (channel->block-1); |
414 } | |
415 //detune | |
416 uint32_t detune = detune_table[channel->keycode][operator->detune & 0x3]; | |
417 if (operator->detune & 0x40) { | |
418 inc -= detune; | |
419 //this can underflow, mask to 17-bit result | |
420 inc &= 0x1FFFF; | |
421 } else { | |
422 inc += detune; | |
423 } | |
424 //multiple | |
425 if (operator->multiple) { | |
426 inc *= operator->multiple; | |
427 } else { | |
428 //0.5 | |
429 inc >>= 1; | |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
430 } |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
431 operator->phase_inc = inc; |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
432 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
433 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
434 void ym_data_write(ym2612_context * context, uint8_t value) |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
435 { |
362 | 436 if (context->selected_reg < 0x21 || context->selected_reg > 0xB6 || (context->selected_reg < 0x30 && context->selected_part)) { |
437 return; | |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
438 } |
362 | 439 //printf("write to reg %X in part %d\n", context->selected_reg, context->selected_part+1); |
440 if (context->selected_reg < 0x30) { | |
441 //Shared regs | |
442 switch (context->selected_reg) | |
443 { | |
444 //TODO: Test reg and LFO | |
445 case REG_TIMERA_HIGH: | |
446 context->timer_a_load &= 0x3; | |
447 context->timer_a_load |= value << 2; | |
448 break; | |
449 case REG_TIMERA_LOW: | |
450 context->timer_a_load &= 0xFFFC; | |
451 context->timer_a_load |= value & 0x3; | |
452 break; | |
453 case REG_TIMERB: | |
454 context->timer_b_load = value; | |
455 break; | |
456 case REG_TIME_CTRL: | |
457 context->timer_control = value; | |
458 break; | |
459 case REG_KEY_ONOFF: { | |
460 uint8_t channel = value & 0x7; | |
461 if (channel < NUM_CHANNELS) { | |
462 for (uint8_t op = channel * 4, bit = 0x10; op < (channel + 1) * 4; op++, bit <<= 1) { | |
463 if (value & bit) { | |
464 //printf("Key On for operator %d in channel %d\n", op, channel); | |
465 context->operators[op].phase_counter = 0; | |
466 context->operators[op].env_phase = PHASE_ATTACK; | |
467 context->operators[op].envelope = MAX_ENVELOPE; | |
468 } else { | |
469 //printf("Key Off for operator %d in channel %d\n", op, channel); | |
470 context->operators[op].env_phase = PHASE_RELEASE; | |
471 } | |
472 } | |
473 } | |
474 break; | |
475 } | |
476 case REG_DAC: | |
477 if (context->dac_enable) { | |
478 context->channels[5].output = (((int16_t)value) - 0x80) << 6; | |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
479 //printf("DAC Write %X(%d)\n", context->channels[5].output, context->channels[5].output); |
362 | 480 } |
481 break; | |
482 case REG_DAC_ENABLE: | |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
483 //printf("DAC Enable: %X\n", value); |
362 | 484 context->dac_enable = value & 0x80; |
485 break; | |
486 } | |
487 } else if (context->selected_reg < 0xA0) { | |
488 //part | |
489 uint8_t op = context->selected_part ? (NUM_OPERATORS/2) : 0; | |
490 //channel in part | |
491 if ((context->selected_reg & 0x3) != 0x3) { | |
492 op += 4 * (context->selected_reg & 0x3); | |
493 //operator in channel | |
494 switch (context->selected_reg & 0xC) | |
495 { | |
496 case 0: | |
497 break; | |
498 case 4: | |
499 op += 2; | |
500 break; | |
501 case 8: | |
502 op += 1; | |
503 break; | |
504 case 0xC: | |
505 op += 3; | |
506 break; | |
507 } | |
508 //printf("write targets operator %d (%d of channel %d)\n", op, op % 4, op / 4); | |
509 ym_operator * operator = context->operators + op; | |
510 switch (context->selected_reg & 0xF0) | |
511 { | |
512 case REG_DETUNE_MULT: | |
513 operator->detune = value >> 4 & 0x7; | |
514 operator->multiple = value & 0xF; | |
515 ym_update_phase_inc(context, operator, op); | |
516 break; | |
517 case REG_TOTAL_LEVEL: | |
518 operator->total_level = (value & 0x7F) << 5; | |
519 break; | |
520 case REG_ATTACK_KS: | |
521 operator->key_scaling = value >> 6; | |
522 operator->rates[PHASE_ATTACK] = value & 0x1F; | |
523 break; | |
524 case REG_DECAY_AM: | |
525 //TODO: AM flag for LFO | |
526 operator->rates[PHASE_DECAY] = value & 0x1F; | |
527 break; | |
528 case REG_SUSTAIN_RATE: | |
529 operator->rates[PHASE_SUSTAIN] = value & 0x1F; | |
530 break; | |
531 case REG_S_LVL_R_RATE: | |
532 operator->rates[PHASE_RELEASE] = (value & 0xF) << 1 | 1; | |
533 operator->sustain_level = value & 0xF0 << 4; | |
534 break; | |
535 } | |
536 } | |
537 } else { | |
538 uint8_t channel = context->selected_reg & 0x3; | |
539 if (channel != 3) { | |
540 if (context->selected_part) { | |
541 channel += 3; | |
542 } | |
543 //printf("write targets channel %d\n", channel); | |
544 switch (context->selected_reg & 0xFC) | |
545 { | |
546 case REG_FNUM_LOW: | |
547 context->channels[channel].block = context->channels[channel].block_fnum_latch >> 3 & 0x7; | |
548 context->channels[channel].fnum = (context->channels[channel].block_fnum_latch & 0x7) << 8 | value; | |
549 context->channels[channel].keycode = context->channels[channel].block << 2 | fnum_to_keycode[context->channels[channel].fnum >> 7]; | |
550 ym_update_phase_inc(context, context->operators + channel*4, channel*4); | |
551 ym_update_phase_inc(context, context->operators + channel*4+1, channel*4+1); | |
552 ym_update_phase_inc(context, context->operators + channel*4+2, channel*4+2); | |
553 ym_update_phase_inc(context, context->operators + channel*4+3, channel*4+3); | |
554 break; | |
555 case REG_BLOCK_FNUM_H:{ | |
556 context->channels[channel].block_fnum_latch = value; | |
557 break; | |
558 } | |
559 //TODO: Channel 3 special/CSM modes | |
560 case REG_ALG_FEEDBACK: | |
561 context->channels[channel].algorithm = value & 0x7; | |
562 context->channels[channel].feedback = value >> 3 & 0x7; | |
563 break; | |
564 case REG_LR_AMS_PMS: | |
565 context->channels[channel].pms = value & 0x7; | |
566 context->channels[channel].ams = value >> 4 & 0x3; | |
567 context->channels[channel].lr = value & 0xC0; | |
568 break; | |
569 } | |
570 } | |
571 } | |
572 | |
573 context->write_cycle = context->current_cycle; | |
574 context->selected_reg = 0;//TODO: Verify this | |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
575 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
576 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
577 uint8_t ym_read_status(ym2612_context * context) |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
578 { |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
579 return context->status; |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
580 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
581 |