Mercurial > repos > blastem
annotate ym2612.c @ 367:f20562f2a570
Fix P condition in Z80 core
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 31 May 2013 20:46:56 -0700 |
parents | 3ba3b6656fff |
children | fc820ab1394b |
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 | |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
77 uint16_t rate_table[64*8]; |
362 | 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; | |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
124 } else if (rate >= 60) { |
362 | 125 value = 8; |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
126 } else if (rate < 8) { |
362 | 127 value = rate_table_base[((rate & 6) == 6 ? 16 : 8) + cycle]; |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
128 } else if (rate < 48) { |
362 | 129 value = rate_table_base[(rate & 0x3) * 8 + cycle]; |
130 } else { | |
131 value = rate_table_base[32 + (rate & 0x3) * 8 + cycle] << (rate >> 2); | |
132 } | |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
133 rate_table[rate * 8 + cycle] = value; |
362 | 134 } |
135 } | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
136 } |
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
|
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 |
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 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
|
140 { |
362 | 141 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); |
142 //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
|
143 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
|
144 //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
|
145 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
|
146 if (context->timer_a) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
147 context->timer_a--; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
148 } else { |
362 | 149 if (context->timer_control & BIT_TIMERA_OVEREN) { |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
150 context->status |= BIT_STATUS_TIMERA; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
151 } |
362 | 152 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
|
153 } |
362 | 154 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
|
155 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
|
156 if (!b_cyc) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
157 if (context->timer_b) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
158 context->timer_b--; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
159 } else { |
362 | 160 if (context->timer_control & BIT_TIMERB_OVEREN) { |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
161 context->status |= BIT_STATUS_TIMERB; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
162 } |
362 | 163 context->timer_b = context->timer_b_load; |
359
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 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
166 } |
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
|
167 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
168 //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
|
169 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
|
170 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
|
171 uint32_t op = context->current_env_op; |
362 | 172 ym_operator * operator = context->operators + op; |
173 ym_channel * channel = context->channels + op/4; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
174 uint8_t rate; |
362 | 175 for(;;) { |
176 rate = operator->rates[operator->env_phase]; | |
177 if (rate) { | |
178 uint8_t ks = channel->keycode >> operator->key_scaling;; | |
179 rate = rate*2 + ks; | |
180 if (rate > 63) { | |
181 rate = 63; | |
182 } | |
183 } | |
184 //Deal with "infinite" rates | |
185 //It's possible this should be handled in key-on as well | |
186 if (rate == 63 && operator->env_phase < PHASE_SUSTAIN) { | |
187 if (operator->env_phase == PHASE_ATTACK) { | |
188 operator->env_phase = PHASE_DECAY; | |
189 operator->envelope = operator->total_level; | |
190 } else { | |
191 operator->env_phase = PHASE_SUSTAIN; | |
192 operator->envelope = operator->sustain_level; | |
193 } | |
194 } else { | |
195 break; | |
196 } | |
197 } | |
198 uint32_t cycle_shift = rate < 0x30 ? ((0x2F - rate) >> 2) : 0; | |
199 if (!(env_cyc & ((1 << cycle_shift) - 1))) { | |
200 uint32_t update_cycle = env_cyc >> cycle_shift & 0x7; | |
201 //envelope value is 10-bits, but it will be used as a 4.8 value | |
202 uint16_t envelope_inc = rate_table[rate * 8 + update_cycle] << 2; | |
203 if (operator->env_phase == PHASE_ATTACK) { | |
204 //this can probably be optimized to a single shift rather than a multiply + shift | |
205 operator->envelope += (~operator->envelope * envelope_inc) >> 4; | |
206 operator->envelope &= MAX_ENVELOPE; | |
207 if (operator->envelope <= operator->total_level) { | |
208 operator->envelope = operator->total_level; | |
209 operator->env_phase = PHASE_DECAY; | |
210 } | |
211 } else { | |
212 operator->envelope += envelope_inc; | |
213 //clamp to max attenuation value | |
214 if (operator->envelope > MAX_ENVELOPE) { | |
215 operator->envelope = MAX_ENVELOPE; | |
216 } | |
217 if (operator->env_phase == PHASE_DECAY && operator->envelope >= operator->sustain_level) { | |
218 operator->envelope = operator->sustain_level; | |
219 operator->env_phase = PHASE_SUSTAIN; | |
220 } | |
221 } | |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
222 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
223 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
|
224 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
|
225 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
|
226 context->env_counter++; |
362 | 227 } |
228 } | |
229 | |
230 //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
|
231 uint32_t channel = context->current_op / 4; |
362 | 232 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
|
233 uint32_t op = context->current_op; |
362 | 234 //printf("updating operator %d of channel %d\n", op, channel); |
235 ym_operator * operator = context->operators + op; | |
236 ym_channel * chan = context->channels + channel; | |
237 //TODO: Modulate phase by LFO if necessary | |
238 operator->phase_counter += operator->phase_inc; | |
239 uint16_t phase = operator->phase_counter >> 10 & 0x3FF; | |
240 switch (op % 4) | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
241 { |
362 | 242 case 0://Operator 1 |
243 //TODO: Feedback | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
244 break; |
362 | 245 case 1://Operator 3 |
246 switch(chan->algorithm) | |
247 { | |
248 case 0: | |
249 case 2: | |
250 //modulate by operator 2 | |
251 phase += context->operators[op+1].output >> 4; | |
252 break; | |
253 case 1: | |
254 //modulate by operator 1+2 | |
255 phase += (context->operators[op-1].output + context->operators[op+1].output) >> 4; | |
256 break; | |
257 case 5: | |
258 //modulate by operator 1 | |
259 phase += context->operators[op-1].output >> 4; | |
260 } | |
261 break; | |
262 case 2://Operator 2 | |
263 if (chan->algorithm != 1 && chan->algorithm != 2 || chan->algorithm != 7) { | |
264 //modulate by Operator 1 | |
265 phase += context->operators[op-2].output >> 4; | |
266 } | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
267 break; |
362 | 268 case 3://Operator 4 |
269 switch(chan->algorithm) | |
270 { | |
271 case 0: | |
272 case 1: | |
273 case 4: | |
274 //modulate by operator 3 | |
275 phase += context->operators[op-2].output >> 4; | |
276 break; | |
277 case 2: | |
278 //modulate by operator 1+3 | |
279 phase += (context->operators[op-3].output + context->operators[op-2].output) >> 4; | |
280 break; | |
281 case 3: | |
282 //modulate by operator 2+3 | |
283 phase += (context->operators[op-1].output + context->operators[op-2].output) >> 4; | |
284 break; | |
285 case 5: | |
286 //modulate by operator 1 | |
287 phase += context->operators[op-3].output >> 4; | |
288 break; | |
289 } | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
290 break; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
291 } |
362 | 292 //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)); |
293 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
|
294 if (phase & 0x200) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
295 output = -output; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
296 } |
362 | 297 operator->output = output; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
298 //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
|
299 if (op % 4 == 3) { |
362 | 300 if (chan->algorithm < 4) { |
301 chan->output = operator->output; | |
302 } else if(chan->algorithm == 4) { | |
303 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
|
304 } else { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
305 output = 0; |
362 | 306 for (uint32_t op = ((chan->algorithm == 7) ? 0 : 1) + channel*4; op < (channel+1)*4; op++) { |
307 output += context->operators[op].output; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
308 } |
362 | 309 chan->output = output; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
310 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
311 } |
362 | 312 //puts("operator update done"); |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
313 } |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
314 context->current_op++; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
315 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
|
316 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
|
317 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
|
318 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
|
319 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
|
320 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
|
321 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
|
322 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
|
323 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
|
324 if (value & 0x2000) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
325 value |= 0xC000; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
326 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
327 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
|
328 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
|
329 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
330 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
|
331 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
|
332 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
333 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
334 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
|
335 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
|
336 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
|
337 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
338 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
339 } |
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
|
340 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
341 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
|
342 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
|
343 } |
362 | 344 //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
|
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 |
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 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
|
348 { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
349 //printf("address_write_part1: %X\n", address); |
362 | 350 context->selected_reg = address; |
351 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
|
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 |
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 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
|
355 { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
356 //printf("address_write_part2: %X\n", address); |
362 | 357 context->selected_reg = address; |
358 context->selected_part = 1; | |
359 } | |
360 | |
361 uint8_t fnum_to_keycode[] = { | |
362 //F11 = 0 | |
363 0,0,0,0,0,0,0,1, | |
364 //F11 = 1 | |
365 2,3,3,3,3,3,3,3 | |
366 }; | |
367 | |
368 //table courtesy of Nemesis | |
369 uint32_t detune_table[][4] = { | |
370 {0, 0, 1, 2}, //0 (0x00) | |
371 {0, 0, 1, 2}, //1 (0x01) | |
372 {0, 0, 1, 2}, //2 (0x02) | |
373 {0, 0, 1, 2}, //3 (0x03) | |
374 {0, 1, 2, 2}, //4 (0x04) | |
375 {0, 1, 2, 3}, //5 (0x05) | |
376 {0, 1, 2, 3}, //6 (0x06) | |
377 {0, 1, 2, 3}, //7 (0x07) | |
378 {0, 1, 2, 4}, //8 (0x08) | |
379 {0, 1, 3, 4}, //9 (0x09) | |
380 {0, 1, 3, 4}, //10 (0x0A) | |
381 {0, 1, 3, 5}, //11 (0x0B) | |
382 {0, 2, 4, 5}, //12 (0x0C) | |
383 {0, 2, 4, 6}, //13 (0x0D) | |
384 {0, 2, 4, 6}, //14 (0x0E) | |
385 {0, 2, 5, 7}, //15 (0x0F) | |
386 {0, 2, 5, 8}, //16 (0x10) | |
387 {0, 3, 6, 8}, //17 (0x11) | |
388 {0, 3, 6, 9}, //18 (0x12) | |
389 {0, 3, 7,10}, //19 (0x13) | |
390 {0, 4, 8,11}, //20 (0x14) | |
391 {0, 4, 8,12}, //21 (0x15) | |
392 {0, 4, 9,13}, //22 (0x16) | |
393 {0, 5,10,14}, //23 (0x17) | |
394 {0, 5,11,16}, //24 (0x18) | |
395 {0, 6,12,17}, //25 (0x19) | |
396 {0, 6,13,19}, //26 (0x1A) | |
397 {0, 7,14,20}, //27 (0x1B) | |
398 {0, 8,16,22}, //28 (0x1C) | |
399 {0, 8,16,22}, //29 (0x1D) | |
400 {0, 8,16,22}, //30 (0x1E) | |
401 {0, 8,16,22} | |
402 }; //31 (0x1F) | |
403 | |
404 void ym_update_phase_inc(ym2612_context * context, ym_operator * operator, uint32_t op) | |
405 { | |
406 uint32_t chan_num = op / 4; | |
407 //printf("ym_update_phase_inc | channel: %d, op: %d\n", chan_num, op); | |
408 //base frequency | |
409 ym_channel * channel = context->channels + chan_num; | |
410 uint32_t inc = channel->fnum; | |
411 if (!channel->block) { | |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
412 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
|
413 } else { |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
414 inc <<= (channel->block-1); |
362 | 415 } |
416 //detune | |
417 uint32_t detune = detune_table[channel->keycode][operator->detune & 0x3]; | |
418 if (operator->detune & 0x40) { | |
419 inc -= detune; | |
420 //this can underflow, mask to 17-bit result | |
421 inc &= 0x1FFFF; | |
422 } else { | |
423 inc += detune; | |
424 } | |
425 //multiple | |
426 if (operator->multiple) { | |
427 inc *= operator->multiple; | |
428 } else { | |
429 //0.5 | |
430 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
|
431 } |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
432 //printf("phase_inc for operator %d: %d, block: %d, fnum: %d, detune: %d, multiple: %d\n", op, inc, channel->block, channel->fnum, detune, operator->multiple); |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
433 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
|
434 } |
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 |
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
|
436 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
|
437 { |
362 | 438 if (context->selected_reg < 0x21 || context->selected_reg > 0xB6 || (context->selected_reg < 0x30 && context->selected_part)) { |
439 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
|
440 } |
362 | 441 //printf("write to reg %X in part %d\n", context->selected_reg, context->selected_part+1); |
442 if (context->selected_reg < 0x30) { | |
443 //Shared regs | |
444 switch (context->selected_reg) | |
445 { | |
446 //TODO: Test reg and LFO | |
447 case REG_TIMERA_HIGH: | |
448 context->timer_a_load &= 0x3; | |
449 context->timer_a_load |= value << 2; | |
450 break; | |
451 case REG_TIMERA_LOW: | |
452 context->timer_a_load &= 0xFFFC; | |
453 context->timer_a_load |= value & 0x3; | |
454 break; | |
455 case REG_TIMERB: | |
456 context->timer_b_load = value; | |
457 break; | |
458 case REG_TIME_CTRL: | |
459 context->timer_control = value; | |
460 break; | |
461 case REG_KEY_ONOFF: { | |
462 uint8_t channel = value & 0x7; | |
463 if (channel < NUM_CHANNELS) { | |
464 for (uint8_t op = channel * 4, bit = 0x10; op < (channel + 1) * 4; op++, bit <<= 1) { | |
465 if (value & bit) { | |
466 //printf("Key On for operator %d in channel %d\n", op, channel); | |
467 context->operators[op].phase_counter = 0; | |
468 context->operators[op].env_phase = PHASE_ATTACK; | |
469 context->operators[op].envelope = MAX_ENVELOPE; | |
470 } else { | |
471 //printf("Key Off for operator %d in channel %d\n", op, channel); | |
472 context->operators[op].env_phase = PHASE_RELEASE; | |
473 } | |
474 } | |
475 } | |
476 break; | |
477 } | |
478 case REG_DAC: | |
479 if (context->dac_enable) { | |
480 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
|
481 //printf("DAC Write %X(%d)\n", context->channels[5].output, context->channels[5].output); |
362 | 482 } |
483 break; | |
484 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
|
485 //printf("DAC Enable: %X\n", value); |
362 | 486 context->dac_enable = value & 0x80; |
487 break; | |
488 } | |
489 } else if (context->selected_reg < 0xA0) { | |
490 //part | |
491 uint8_t op = context->selected_part ? (NUM_OPERATORS/2) : 0; | |
492 //channel in part | |
493 if ((context->selected_reg & 0x3) != 0x3) { | |
494 op += 4 * (context->selected_reg & 0x3); | |
495 //operator in channel | |
496 switch (context->selected_reg & 0xC) | |
497 { | |
498 case 0: | |
499 break; | |
500 case 4: | |
501 op += 2; | |
502 break; | |
503 case 8: | |
504 op += 1; | |
505 break; | |
506 case 0xC: | |
507 op += 3; | |
508 break; | |
509 } | |
510 //printf("write targets operator %d (%d of channel %d)\n", op, op % 4, op / 4); | |
511 ym_operator * operator = context->operators + op; | |
512 switch (context->selected_reg & 0xF0) | |
513 { | |
514 case REG_DETUNE_MULT: | |
515 operator->detune = value >> 4 & 0x7; | |
516 operator->multiple = value & 0xF; | |
517 ym_update_phase_inc(context, operator, op); | |
518 break; | |
519 case REG_TOTAL_LEVEL: | |
520 operator->total_level = (value & 0x7F) << 5; | |
521 break; | |
522 case REG_ATTACK_KS: | |
523 operator->key_scaling = value >> 6; | |
524 operator->rates[PHASE_ATTACK] = value & 0x1F; | |
525 break; | |
526 case REG_DECAY_AM: | |
527 //TODO: AM flag for LFO | |
528 operator->rates[PHASE_DECAY] = value & 0x1F; | |
529 break; | |
530 case REG_SUSTAIN_RATE: | |
531 operator->rates[PHASE_SUSTAIN] = value & 0x1F; | |
532 break; | |
533 case REG_S_LVL_R_RATE: | |
534 operator->rates[PHASE_RELEASE] = (value & 0xF) << 1 | 1; | |
535 operator->sustain_level = value & 0xF0 << 4; | |
536 break; | |
537 } | |
538 } | |
539 } else { | |
540 uint8_t channel = context->selected_reg & 0x3; | |
541 if (channel != 3) { | |
542 if (context->selected_part) { | |
543 channel += 3; | |
544 } | |
545 //printf("write targets channel %d\n", channel); | |
546 switch (context->selected_reg & 0xFC) | |
547 { | |
548 case REG_FNUM_LOW: | |
549 context->channels[channel].block = context->channels[channel].block_fnum_latch >> 3 & 0x7; | |
550 context->channels[channel].fnum = (context->channels[channel].block_fnum_latch & 0x7) << 8 | value; | |
551 context->channels[channel].keycode = context->channels[channel].block << 2 | fnum_to_keycode[context->channels[channel].fnum >> 7]; | |
552 ym_update_phase_inc(context, context->operators + channel*4, channel*4); | |
553 ym_update_phase_inc(context, context->operators + channel*4+1, channel*4+1); | |
554 ym_update_phase_inc(context, context->operators + channel*4+2, channel*4+2); | |
555 ym_update_phase_inc(context, context->operators + channel*4+3, channel*4+3); | |
556 break; | |
557 case REG_BLOCK_FNUM_H:{ | |
558 context->channels[channel].block_fnum_latch = value; | |
559 break; | |
560 } | |
561 //TODO: Channel 3 special/CSM modes | |
562 case REG_ALG_FEEDBACK: | |
563 context->channels[channel].algorithm = value & 0x7; | |
564 context->channels[channel].feedback = value >> 3 & 0x7; | |
565 break; | |
566 case REG_LR_AMS_PMS: | |
567 context->channels[channel].pms = value & 0x7; | |
568 context->channels[channel].ams = value >> 4 & 0x3; | |
569 context->channels[channel].lr = value & 0xC0; | |
570 break; | |
571 } | |
572 } | |
573 } | |
574 | |
575 context->write_cycle = context->current_cycle; | |
576 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
|
577 } |
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 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
|
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 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
|
582 } |
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
|
583 |