comparison rf5c164.c @ 2082:485834c0fea7

Forgot to add PCM source files
author Michael Pavone <pavone@retrodev.com>
date Thu, 03 Feb 2022 23:41:40 -0800
parents
children b0dcf5c9f353
comparison
equal deleted inserted replaced
2081:cfd53c94fffb 2082:485834c0fea7
1 #include <stdio.h>
2 #include "rf5c164.h"
3
4 enum {
5 ENV,
6 PAN,
7 FDL,
8 FDH,
9 LSL,
10 LSH,
11 ST,
12 CTRL,
13 CHAN_ENABLE
14 };
15
16 enum {
17 START,
18 NORMAL,
19 LOOP
20 };
21
22 #define FLAG_SOUNDING 0x80
23 #define FLAG_PENDING 0x01
24
25 void rf5c164_init(rf5c164* pcm, uint32_t mclks, uint32_t divider)
26 {
27 pcm->audio = render_audio_source("rf5c164", mclks, divider * 384, 2);
28 pcm->clock_step = divider * 4;
29 }
30
31 //48 cycles per channel
32 //1 external write per 16 cycles
33 //3 external writes per channel/sample
34 // TCE pulse width is 200ns @ 10Mhz aka 2 cycles
35 // total cycle is longer than TCE pulse, guessing 4 cycles
36 // 12 memory access slots per channel sample
37 // 3 for external memory writes
38 // 1 for internal register writes?
39 // 1 for refresh?
40 // 6 for register reads?
41 // or maybe 7 for register reads and writes happen when register is read?
42
43 #define CHECK pcm->cycle += pcm->clock_step; pcm->step++; if (pcm->cycle >= cycle) break
44 #define CHECK_LOOP pcm->cycle += pcm->clock_step; pcm->step = 0; if (pcm->cycle >= cycle) break
45
46 static void write_if_not_sounding(rf5c164* pcm)
47 {
48 if (!(pcm->flags & FLAG_SOUNDING) && (pcm->flags & FLAG_PENDING)
49 && pcm->pending_address >= 0x1000) {
50 pcm->ram[(pcm->pending_address & 0xFFF) | pcm->ram_bank] = pcm->pending_byte;
51 pcm->flags &= ~FLAG_PENDING;
52 }
53 }
54
55 static void write_always(rf5c164* pcm)
56 {
57 if ((pcm->flags & FLAG_PENDING) && pcm->pending_address >= 0x1000) {
58 pcm->ram[(pcm->pending_address & 0xFFF) | pcm->ram_bank] = pcm->pending_byte;
59 pcm->flags &= ~FLAG_PENDING;
60 }
61 }
62
63 void rf5c164_run(rf5c164* pcm, uint32_t cycle)
64 {
65 //TODO: Timing of this is all educated guesses based on documentation, do some real measurements
66 while (pcm->cycle < cycle)
67 {
68 switch (pcm->step)
69 {
70 case 0:
71 //handle internal memory write
72 // RF5C164 datasheet seems to suggest only 1 "internal memory" write every 48 cycles when the chip is not sounding (globally)
73 // and 1 write every 384 cycles when the chip is sounding (globally). However, games seem to expect to be able to write faster than that
74 // RF5C68 datasheet suggests internal memory writes are unrestricted regardless of sounding status
75 /*if ((pcm->cur_channel == pcm->selected_channel || !(pcm->flags & FLAG_SOUNDING)) && (pcm->flags & FLAG_PENDING)
76 && pcm->pending_address <= ST
77 ) {
78 printf("pcm_write commit chan %d, %X - %X @ %u\n", pcm->selected_channel, pcm->pending_address, pcm->pending_byte, pcm->cycle);
79 pcm->channels[pcm->selected_channel].regs[pcm->pending_address] = pcm->pending_byte;
80 pcm->flags &= ~FLAG_PENDING;
81 }*/
82 write_if_not_sounding(pcm);
83 CHECK;
84 case 1:
85 if ((pcm->flags & FLAG_SOUNDING) && !(pcm->channel_enable & (1 << pcm->cur_channel))) {
86 if (pcm->channels[pcm->cur_channel].state == START) {
87 pcm->channels[pcm->cur_channel].cur_ptr = pcm->channels[pcm->cur_channel].regs[ST] << 19;
88 //printf("chan %d START %X (%X raw)\n", pcm->cur_channel, pcm->channels[pcm->cur_channel].cur_ptr >> 11, pcm->channels[pcm->cur_channel].cur_ptr);
89 pcm->channels[pcm->cur_channel].state = NORMAL;
90 } else if (pcm->channels[pcm->cur_channel].state == LOOP) {
91 pcm->channels[pcm->cur_channel].cur_ptr = (pcm->channels[pcm->cur_channel].regs[LSH] << 19) | (pcm->channels[pcm->cur_channel].regs[LSL] << 11);
92 //printf("chan %d LOOP %X (%X raw)\n", pcm->cur_channel, pcm->channels[pcm->cur_channel].cur_ptr >> 11, pcm->channels[pcm->cur_channel].cur_ptr);
93 pcm->channels[pcm->cur_channel].state = NORMAL;
94 }
95 }
96 write_if_not_sounding(pcm);
97 CHECK;
98 case 2: {
99 if ((pcm->flags & FLAG_SOUNDING) && !(pcm->channel_enable & (1 << pcm->cur_channel))) {
100 uint8_t byte = pcm->ram[pcm->channels[pcm->cur_channel].cur_ptr >> 11];
101 if (byte == 0xFF) {
102 pcm->channels[pcm->cur_channel].state = LOOP;
103 } else {
104 pcm->channels[pcm->cur_channel].sample = byte;
105 }
106 }
107 write_if_not_sounding(pcm);
108 CHECK;
109 }
110 case 3:
111 write_always(pcm);
112 CHECK;
113 case 4:
114 if ((pcm->flags & FLAG_SOUNDING) && !(pcm->channel_enable & (1 << pcm->cur_channel))) {
115 pcm->channels[pcm->cur_channel].cur_ptr += (pcm->channels[pcm->cur_channel].regs[FDH] << 8) | pcm->channels[pcm->cur_channel].regs[FDL];
116 pcm->channels[pcm->cur_channel].cur_ptr &= 0x7FFFFFF;
117 }
118 write_if_not_sounding(pcm);
119 CHECK;
120 case 5:
121 write_if_not_sounding(pcm);
122 CHECK;
123 case 6:
124 write_if_not_sounding(pcm);
125 CHECK;
126 case 7:
127 write_always(pcm);
128 CHECK;
129 case 8:
130 write_if_not_sounding(pcm);
131 CHECK;
132 case 9:
133 if ((pcm->flags & FLAG_SOUNDING) && !(pcm->channel_enable & (1 << pcm->cur_channel))) {
134 int16_t sample = pcm->channels[pcm->cur_channel].sample & 0x7F;
135 if (!(pcm->channels[pcm->cur_channel].sample & 0x80)) {
136 sample = -sample;
137 }
138 sample *= pcm->channels[pcm->cur_channel].regs[ENV];
139 int16_t left = (sample * (pcm->channels[pcm->cur_channel].regs[PAN] >> 4)) >> 5;
140 int16_t right = (sample * (pcm->channels[pcm->cur_channel].regs[PAN] & 0xF)) >> 5;
141 //printf("chan %d, raw %X, sample %d, left %d, right %d, ptr %X (raw %X)\n", pcm->cur_channel, pcm->channels[pcm->cur_channel].sample, sample, left, right, pcm->channels[pcm->cur_channel].cur_ptr >> 11, pcm->channels[pcm->cur_channel].cur_ptr);
142 //TODO: saturating add
143 pcm->left += left;
144 pcm->right += right;
145 }
146 write_if_not_sounding(pcm);
147 CHECK;
148 case 10:
149 //refresh?
150 CHECK;
151 case 11:
152 write_always(pcm);
153 pcm->cur_channel++;
154 pcm->cur_channel &= 7;
155 if (!pcm->cur_channel) {
156 render_put_stereo_sample(pcm->audio, pcm->left, pcm->right);
157 pcm->left = pcm->right = 0;
158 }
159 CHECK_LOOP;
160 }
161 }
162 }
163
164 void rf5c164_write(rf5c164* pcm, uint16_t address, uint8_t value)
165 {
166 //printf("pcm_write %X - %X @ %u\n", address, value, pcm->cycle);
167 if (address == CTRL) {
168 pcm->flags &= ~FLAG_SOUNDING;
169 pcm->flags |= value & FLAG_SOUNDING;
170 if (value & 0x40) {
171 pcm->selected_channel = value & 0x7;
172 //printf("selected channel %d\n", pcm->selected_channel);
173 } else {
174 pcm->ram_bank = value << 12 & 0xF000;
175 //printf("selected RAM bank %X\n", pcm->ram_bank);
176 }
177 if (!(pcm->flags & FLAG_SOUNDING)) {
178 pcm->left = pcm->right = 0;
179 }
180 } else if (address == CHAN_ENABLE) {
181 uint8_t changed = pcm->channel_enable ^ value;
182 pcm->channel_enable = value;
183 for (int i = 0; i < 8; i++)
184 {
185 int mask = 1 << i;
186 if (changed & mask & value) {
187 pcm->channels[i].state = START;
188 }
189 }
190 } else if (address <= ST) {
191 //See note in first step of rf5c164_run
192 pcm->channels[pcm->selected_channel].regs[address] = value;
193 } else {
194 pcm->pending_address = address;
195 pcm->pending_byte = value;
196 pcm->flags |= FLAG_PENDING;
197 }
198 }
199
200 uint8_t rf5c164_read(rf5c164* pcm, uint16_t address)
201 {
202 if (address >= 0x10 && address < 0x20) {
203 uint16_t chan = address >> 1 & 0x7;
204 if (address & 1) {
205 return pcm->channels[chan].cur_ptr >> 19;
206 } else {
207 return pcm->channels[chan].cur_ptr >> 11;
208 }
209 } else if (address >= 0x1000 && !(pcm->flags & FLAG_SOUNDING)) {
210 return pcm->ram[pcm->ram_bank | (address & 0xFFF)];
211 } else {
212 return 0xFF;
213 }
214 }