2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
10 #include "sn76489an.h"
14 #define NOISE_FB 0x4000
15 #define NOISE_DST_TAP 1
16 #define NOISE_SRC_TAP 2
19 #define NOISE_FB 0x10000
20 #define NOISE_DST_TAP 4
21 #define NOISE_SRC_TAP 8
23 #define NOISE_MODE ((regs[6] & 4) ? 1 : 0)
25 void SN76489AN::initialize()
31 void SN76489AN::reset()
33 for(int i = 0; i < 4; i++) {
39 for(int i = 0; i < 8; i += 2) {
41 regs[i + 1] = 0x0f; // volume = 0
47 void SN76489AN::write_io8(uint32 addr, uint32 data)
50 index = (data >> 4) & 7;
54 case 0: case 2: case 4:
56 regs[index] = (regs[index] & 0x3f0) | (data & 0x0f);
57 ch[c].period = regs[index] ? regs[index] : 0x400;
60 case 1: case 3: case 5: case 7:
61 // tone / noise : volume
62 regs[index] = data & 0x0f;
63 ch[c].volume = volume_table[data & 0x0f];
66 // noise : frequency, mode
69 ch[3].period = (data == 3) ? (ch[2].period << 1) : (1 << (data + 5));
78 switch(index & 0x07) {
79 case 0: case 2: case 4:
81 regs[index] = (regs[index] & 0x0f) | (((uint16)data << 4) & 0x3f0);
82 ch[c].period = regs[index] ? regs[index] : 0x400;
84 // update noise shift frequency
85 if(index == 4 && (regs[6] & 3) == 3) {
86 ch[3].period = ch[2].period << 1;
93 void SN76489AN::write_signal(int id, uint32 data, uint32 mask)
95 if(id == SIG_SN76489AN_MUTE) {
96 mute = ((data & mask) != 0);
97 } else if(id == SIG_SN76489AN_DATA) {
99 } else if(id == SIG_SN76489AN_CS) {
100 bool next = ((data & mask) != 0);
102 if(!(cs = next) && !we) {
106 } else if(id == SIG_SN76489AN_CS) {
107 bool next = ((data & mask) != 0);
114 } else if(id == SIG_SN76489AN_WE) {
115 bool next = ((data & mask) != 0);
125 void SN76489AN::mix(int32* buffer, int cnt)
130 for(int i = 0; i < cnt; i++) {
131 int32 vol_l = 0, vol_r = 0;
132 for(int j = 0; j < 4; j++) {
136 bool prev_signal = ch[j].signal;
137 int prev_count = ch[j].count;
139 if(ch[j].count < 0) {
140 ch[j].count += ch[j].period << 8;
142 if(((noise_gen & NOISE_DST_TAP) ? 1 : 0) ^ (((noise_gen & NOISE_SRC_TAP) ? 1 : 0) * NOISE_MODE)) {
144 noise_gen |= NOISE_FB;
148 ch[3].signal = ((noise_gen & 1) != 0);
150 ch[j].signal = !ch[j].signal;
153 int32 sample = (prev_signal != ch[j].signal && prev_count < diff) ? (ch[j].volume * (2 * prev_count - diff)) / diff : ch[j].volume;
154 int32 vol_tmp_l = apply_volume(sample, volume_l);
155 int32 vol_tmp_r = apply_volume(sample, volume_r);
157 vol_l += prev_signal ? vol_tmp_l : -vol_tmp_l;
158 vol_r += prev_signal ? vol_tmp_r : -vol_tmp_r;
160 *buffer++ += vol_l; // L
161 *buffer++ += vol_r; // R
165 void SN76489AN::set_volume(int ch, int decibel_l, int decibel_r)
167 volume_l = decibel_to_volume(decibel_l);
168 volume_r = decibel_to_volume(decibel_r);
171 void SN76489AN::init(int rate, int clock, int volume)
175 for(int i = 0; i < 15; i++) {
176 volume_table[i] = (int)vol;
179 volume_table[15] = 0;
180 diff = (int)(16.0 * (double)clock / (double)rate + 0.5);
183 #define STATE_VERSION 1
185 void SN76489AN::save_state(FILEIO* state_fio)
187 state_fio->FputUint32(STATE_VERSION);
188 state_fio->FputInt32(this_device_id);
190 state_fio->Fwrite(regs, sizeof(regs), 1);
191 state_fio->FputInt32(index);
192 state_fio->Fwrite(ch, sizeof(ch), 1);
193 state_fio->FputUint32(noise_gen);
194 state_fio->FputBool(mute);
195 state_fio->FputBool(cs);
196 state_fio->FputBool(we);
197 state_fio->FputUint8(val);
200 bool SN76489AN::load_state(FILEIO* state_fio)
202 if(state_fio->FgetUint32() != STATE_VERSION) {
205 if(state_fio->FgetInt32() != this_device_id) {
208 state_fio->Fread(regs, sizeof(regs), 1);
209 index = state_fio->FgetInt32();
210 state_fio->Fwrite(ch, sizeof(ch), 1);
211 noise_gen = state_fio->FgetUint32();
212 mute = state_fio->FgetBool();
213 cs = state_fio->FgetBool();
214 we = state_fio->FgetBool();
215 val = state_fio->FgetUint8();