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