2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
7 [ AY-3-8910 / 8912 / 8913 ]
9 2017-02-02: Fork from YM2203.
12 #include "ay_3_891x.h"
15 #define EVENT_PSG_TIMER 0
18 void AY_3_891X::initialize()
20 psg = new PSG_AY_3_891X;
22 register_vline_event(this);
24 clock_prev = clock_accum = clock_busy = 0;
26 left_volume = right_volume = 256;
27 v_left_volume = v_right_volume = 256;
30 void AY_3_891X::release()
35 void AY_3_891X::reset()
42 #ifdef SUPPORT_AY_3_891X_PORT
43 port[0].first = port[1].first = true;
44 port[0].wreg = port[1].wreg = 0;//0xff;
45 #ifdef AY_3_891X_PORT_MODE
46 mode = AY_3_891X_PORT_MODE;
51 irq_prev = busy = false;
56 void AY_3_891X::write_io8(uint32_t addr, uint32_t data)
58 switch(addr & amask) {
63 #ifdef SUPPORT_AY_3_891X_PORT
65 #ifdef AY_3_891X_PORT_MODE
66 mode = (data & 0x3f) | AY_3_891X_PORT_MODE;
71 #ifdef SUPPORT_AY_3_891X_PORT_A
72 if(port[0].wreg != data || port[0].first) {
73 write_signals(&port[0].outputs, data);
75 port[0].first = false;
79 #ifdef SUPPORT_AY_3_891X_PORT_B
80 if(port[1].wreg != data || port[1].first) {
81 write_signals(&port[1].outputs, data);
83 port[1].first = false;
91 this->set_reg(ch, data);
97 uint32_t AY_3_891X::read_io8(uint32_t addr)
99 switch(addr & amask) {
101 #ifdef SUPPORT_AY_3_891X_PORT
103 #ifdef SUPPORT_AY_3_891X_PORT_A
104 return (mode & 0x40) ? port[0].wreg : port[0].rreg;
106 } else if(ch == 15) {
107 #ifdef SUPPORT_AY_3_891X_PORT_B
108 return (mode & 0x80) ? port[1].wreg : port[1].rreg;
112 return psg->GetReg(ch);
117 void AY_3_891X::write_signal(int id, uint32_t data, uint32_t mask)
119 if(id == SIG_AY_3_891X_MUTE) {
120 mute = ((data & mask) != 0);
121 #ifdef SUPPORT_AY_3_891X_PORT_A
122 } else if(id == SIG_AY_3_891X_PORT_A) {
123 port[0].rreg = (port[0].rreg & ~mask) | (data & mask);
125 #ifdef SUPPORT_AY_3_891X_PORT_B
126 } else if(id == SIG_AY_3_891X_PORT_B) {
127 port[1].rreg = (port[1].rreg & ~mask) | (data & mask);
132 void AY_3_891X::event_vline(int v, int clock)
137 void AY_3_891X::event_callback(int event_id, int error)
140 //timer_event_id = -1;
144 void AY_3_891X::update_count()
146 clock_accum += clock_const * get_passed_clock(clock_prev);
147 uint32_t count = clock_accum >> 20;
150 clock_accum -= count << 20;
152 clock_prev = get_current_clock();
155 void AY_3_891X::update_event()
157 //if(timer_event_id != -1) {
158 // cancel_event(this, timer_event_id);
159 // timer_event_id = -1;
163 //count = psg->GetNextEvent();
166 // register_event(this, EVENT_PSG_TIMER, 1000000.0 / (double)chip_clock * (double)count, false, &timer_event_id);
171 inline int32_t VCALC(int32_t x, int32_t y)
178 inline int32_t SATURATION_ADD(int32_t x, int32_t y)
181 if(x < -0x8000) x = -0x8000;
182 if(x > 0x7fff) x = 0x7fff;
187 void AY_3_891X::mix(int32_t* buffer, int cnt)
189 if(cnt > 0 && !mute) {
190 int32_t *dbuffer = (int32_t *)malloc((cnt * 2 + 2) * sizeof(int32_t));
191 memset((void *)dbuffer, 0x00, (cnt * 2 + 2) * sizeof(int32_t));
193 psg->Mix(dbuffer, cnt);
194 int32_t *p = dbuffer;
197 int32_t tvol[8] = {v_left_volume, v_right_volume,
198 v_left_volume, v_right_volume,
199 v_left_volume, v_right_volume,
200 v_left_volume, v_right_volume};
202 // More EXCEPTS to optimize to SIMD features.
203 for(i = 0; i < cnt / 4; i++) {
204 tmp[0] = VCALC(p[0], tvol[0]);
205 tmp[1] = VCALC(p[1], tvol[1]);
206 tmp[2] = VCALC(p[2], tvol[2]);
207 tmp[3] = VCALC(p[3], tvol[3]);
208 tmp[4] = VCALC(p[4], tvol[4]);
209 tmp[5] = VCALC(p[5], tvol[5]);
210 tmp[6] = VCALC(p[6], tvol[6]);
211 tmp[7] = VCALC(p[7], tvol[7]);
213 q[0] = SATURATION_ADD(q[0], tmp[0]);
214 q[1] = SATURATION_ADD(q[1], tmp[1]);
215 q[2] = SATURATION_ADD(q[2], tmp[2]);
216 q[3] = SATURATION_ADD(q[3], tmp[3]);
218 q[4] = SATURATION_ADD(q[4], tmp[4]);
219 q[5] = SATURATION_ADD(q[5], tmp[5]);
220 q[6] = SATURATION_ADD(q[6], tmp[6]);
221 q[7] = SATURATION_ADD(q[7], tmp[7]);
226 for(i = 0; i < (cnt & 3); i++) {
227 tmp[0] = VCALC(p[0], tvol[0]);
228 tmp[1] = VCALC(p[1], tvol[1]);
230 q[0] = SATURATION_ADD(q[0], tmp[0]);
231 q[1] = SATURATION_ADD(q[1], tmp[1]);
240 void AY_3_891X::set_volume(int ch, int decibel_l, int decibel_r)
242 v_right_volume = (int)(pow(10.0, (double)decibel_vol / 10.0) * (double)right_volume);
243 v_left_volume = (int)(pow(10.0, (double)decibel_vol / 10.0) * (double)left_volume);
245 psg->SetVolume(base_decibel_psg + decibel_l, base_decibel_psg + decibel_r);
249 void AY_3_891X::initialize_sound(int rate, int clock, int samples, int decibel_fm, int decibel_psg)
251 //psg->Init(clock, rate, false, NULL);
252 psg->Init(clock, rate);
253 psg->SetVolume(decibel_psg, decibel_psg);
254 base_decibel_psg = decibel_psg;
258 void AY_3_891X::set_reg(uint32_t addr, uint32_t data)
261 if((addr >= 0x2d) && (addr <= 0x2f)) {
262 psg->SetPrescaler(addr - 0x2d);
265 psg->SetReg(addr, data);
268 void AY_3_891X::update_timing(int new_clocks, double new_frames_per_sec, int new_lines_per_frame)
270 clock_const = (uint32_t)((double)chip_clock * 1024.0 * 1024.0 / (double)new_clocks + 0.5);
273 #define STATE_VERSION 1
275 void AY_3_891X::save_state(FILEIO* state_fio)
277 state_fio->FputUint32(STATE_VERSION);
278 state_fio->FputInt32(this_device_id);
279 psg->SaveState((void *)state_fio);
280 state_fio->FputUint8(ch);
281 state_fio->FputUint8(fnum2);
282 #ifdef SUPPORT_AY_3_891X_PORT
283 for(int i = 0; i < 2; i++) {
284 state_fio->FputUint8(port[i].wreg);
285 state_fio->FputUint8(port[i].rreg);
286 state_fio->FputBool(port[i].first);
288 state_fio->FputUint8(mode);
290 state_fio->FputInt32(chip_clock);
291 state_fio->FputBool(irq_prev);
292 state_fio->FputBool(mute);
293 state_fio->FputUint32(clock_prev);
294 state_fio->FputUint32(clock_accum);
295 state_fio->FputUint32(clock_const);
296 state_fio->FputUint32(clock_busy);
297 //state_fio->FputInt32(timer_event_id);
298 state_fio->FputBool(busy);
299 state_fio->FputInt32(decibel_vol);
300 state_fio->FputInt32(left_volume);
301 state_fio->FputInt32(right_volume);
302 state_fio->FputInt32(v_left_volume);
303 state_fio->FputInt32(v_right_volume);
306 bool AY_3_891X::load_state(FILEIO* state_fio)
308 if(state_fio->FgetUint32() != STATE_VERSION) {
311 if(state_fio->FgetInt32() != this_device_id) {
314 if(!psg->LoadState((void *)state_fio)) {
317 ch = state_fio->FgetUint8();
318 fnum2 = state_fio->FgetUint8();
319 #ifdef SUPPORT_AY_3_891X_PORT
320 for(int i = 0; i < 2; i++) {
321 port[i].wreg = state_fio->FgetUint8();
322 port[i].rreg = state_fio->FgetUint8();
323 port[i].first = state_fio->FgetBool();
325 mode = state_fio->FgetUint8();
327 chip_clock = state_fio->FgetInt32();
328 irq_prev = state_fio->FgetBool();
329 mute = state_fio->FgetBool();
330 clock_prev = state_fio->FgetUint32();
331 clock_accum = state_fio->FgetUint32();
332 clock_const = state_fio->FgetUint32();
333 clock_busy = state_fio->FgetUint32();
334 //timer_event_id = state_fio->FgetInt32();
335 busy = state_fio->FgetBool();
337 decibel_vol = state_fio->FgetInt32();
338 left_volume = state_fio->FgetInt32();
339 right_volume = state_fio->FgetInt32();
340 v_left_volume = state_fio->FgetInt32();
341 v_right_volume = state_fio->FgetInt32();