OSDN Git Service

[VM][FMTOWNS][MEMORY] Fix setup around memory banks by I/O 0404h and 0480h.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fmtowns / adpcm.cpp
1 /*
2         FUJITSU FM Towns Emulator 'eFMTowns'
3
4         Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
5         Date   : 2019.01.29-
6
7         [I/O around ADPCM]
8 */
9
10 #include "./adpcm.h"
11 #include "ad7820kr.h"
12 #include "rf5c68.h"
13 #include "ym2612.h"
14 #include "../i8259.h"
15
16 namespace FMTOWNS {
17
18 #define EVENT_ADC_CLOCK   1
19
20 void ADPCM::initialize()
21 {
22         adc_fifo = new FIFO(64); // OK?
23         event_adc_clock = -1;
24 }
25
26 void ADPCM::release()
27 {
28         adc_fifo->release();
29         delete adc_fifo;
30 }
31
32 void ADPCM::reset()
33 {
34         // Is clear FIFO?
35         adc_fifo->clear();
36         dac_intr_mask = 0x0000; // Disable
37         dac_intr = 0x0000;      // OFF
38         latest_dac_intr = false;
39
40         opx_intr = false;
41         adpcm_mute = false;
42         opn2_mute = false;
43
44         write_signals(&outputs_intr, 0x00000000);
45         write_signals(&outputs_led_control, 0x00000000);
46         write_signals(&outputs_allmute, 0xffffffff); // OK?
47
48         initialize_adc_clock(-1);
49 }
50
51 void ADPCM::initialize_adc_clock(int freq)
52 {
53         if(freq <= 0) {
54                 freq = (int)d_adc->read_signal(SIG_AD7820_SAMPLE_RATE);
55         }
56         if(event_adc_clock >= 0) {
57                 cancel_event(this, event_adc_clock);
58         }
59         d_adc->write_signal(SIG_AD7820_DATA_REG, 0x00, 0x00);
60         d_adc->write_signal(SIG_AD7820_CS, 0xffffffff, 0xffffffff);
61         d_adc->write_signal(SIG_AD7820_WR_CONVERSION_MODE, 0, 0xffffffff); // READ MODE..
62         register_event(this, EVENT_ADC_CLOCK, 1.0e6 / (double)freq, true, &event_adc_clock);
63 }
64
65 void ADPCM::event_callback(int id, int err)
66 {
67         switch(id) {
68         case EVENT_ADC_CLOCK:
69                 if(!(adc_fifo->full())) {
70                         d_adc->write_signal(SIG_AD7820_WR_CONVERSION_MODE, 0, 0xffffffff); // READ MODE
71                         d_adc->write_signal(SIG_AD7820_CS, 0xffffffff, 0xffffffff);
72                         d_adc->read_data8(SIG_AD7820_DATA_REG); // Dummy read, start to  sample.
73                 }
74                 break;
75         }
76 }
77
78 uint32_t ADPCM::read_io8(uint32_t addr)
79 {
80         /*
81           0x04d5 : OPN2/ADPCM MUTE
82           0x04e7 - 0x04e8 : ADC
83           0x04e9 - 0x04ec : DAC CONTROL
84         */
85         uint8_t val = 0x00;
86         switch(addr) {
87         case 0x04d5: // Mute reg
88                 val |= ((opn2_mute) ? 0 : 0x02);
89                 val |= ((adpcm_mute) ? 0 : 0x01);
90                 break;
91         case 0x04e7: // ADC data register
92                 if(!(adc_fifo->empty())) {
93                         val = (uint8_t)(adc_fifo->read() & 0xff);
94                 } else {
95                         val = 0x00;
96                 }
97                 break;
98         case 0x04e8: // ADC flags
99                 val = (!(adc_fifo->empty())) ? 0x01 : 0x00;
100                 break;
101         case 0x04e9: // Int13 reason
102                 val = 0x00 | ((dac_intr != 0) ? 0x08 : 0x00) | ((opx_intr) ? 0x01 : 0x00);
103 //              write_signals(&outputs_intr, 0); // Clear Interrupt
104 //              dac_intr = 0;
105 //              opx_intr = false;
106                 break;
107         case 0x04ea: // PCM Interrupt mask
108                 val = dac_intr_mask;
109                 break;
110         case 0x04eb: // PCM Interrupt status
111                 {
112                         val = dac_intr;
113                         dac_intr = 0x00;
114                         if(latest_dac_intr) {
115                                 latest_dac_intr = false;
116                         }
117                         if(!(opx_intr)) write_signals(&outputs_intr, 0); // Clear Interrupt
118                 }
119                 break;
120         default:
121                 break;
122         }
123         return val;
124 }
125
126 void ADPCM::write_io8(uint32_t addr, uint32_t data)
127 {
128         /*
129           0x04d5 : OPN2/ADPCM MUTE
130           0x04e7 - 0x04e8 : ADC
131           0x04e9 - 0x04ec : DAC CONTROL
132         */
133         switch(addr) {
134         case 0x04d5:
135                 opn2_mute = ((data & 0x02) == 0) ? true : false;
136                 adpcm_mute =  ((data & 0x01) == 0) ? true : false;
137                 d_opn2->write_signal(SIG_YM2612_MUTE, (opn2_mute) ? 0xffffffff : 0x00000000, 0xffffffff);
138                 d_rf5c68->write_signal(SIG_RF5C68_MUTE, (adpcm_mute) ? 0xffffffff : 0x00000000, 0xffffffff);
139                 break;
140         case 0x04e8:
141                 adc_fifo->clear();
142                 break;
143         case 0x04ea:
144                 dac_intr_mask = data;
145                 break;
146         case 0x04ec:
147                 write_signals(&outputs_led_control, ((data & 0x80) == 0) ? 0xffffffff : 0x00000000);
148                 write_signals(&outputs_allmute, ((data & 0x40) == 0) ? 0xffffffff : 0x00000000);
149                 break;
150         default:
151                 break;
152         }
153 }
154
155 void ADPCM::write_signal(int ch, uint32_t data, uint32_t mask)
156 {
157         if(ch == SIG_ADPCM_WRITE_INTERRUPT) {
158 //              out_debug_log(_T("SIG_ADPCM_WRITE_INTERRUPT val=%08X mask=%08X"), data ,mask);
159                 uint32_t n_ch = data & 0x07;
160                 bool n_onoff = (((data & mask) & 0x00000008) != 0) ? true : false;
161                 bool n_allset =(((data & mask) & 0x80000000) != 0) ? true : false;
162                 bool _d = false;
163                 if(!(n_allset)) {
164                         _d = ((dac_intr_mask & (1 << n_ch)) != 0) ? true : false;
165                         if(n_onoff) {
166                                 dac_intr = dac_intr | (1 << n_ch);
167                         } else {
168                                 dac_intr = dac_intr & ~(1 << n_ch);
169                         }
170                 } else {
171                         // ALLSET
172                         uint16_t intr_backup = dac_intr;
173                         dac_intr = (n_onoff) ? 0xffff : 0x0000;
174                         _d = true;
175 //                      _d = (dac_intr != intr_backup) ? true : false;
176                 }
177                 if((n_onoff) && (_d)) { // ON
178                         write_signals(&outputs_intr, 0xffffffff);
179                         latest_dac_intr = true;
180                 } else if(!(n_onoff) || !(_d)) {
181                         if(!(opx_intr)) {
182                                 write_signals(&outputs_intr, 0x00000000);
183                         }
184                         latest_dac_intr = false;
185                 }
186         } else if(ch == SIG_ADPCM_OPX_INTR) { // SET/RESET INT13
187 //              out_debug_log(_T("SIG_ADPCM_OPX_INTR val=%08X mask=%08X"), data ,mask);
188                 opx_intr = ((data & mask) != 0);
189                 if(opx_intr) {
190                         write_signals(&outputs_intr, 0xffffffff);
191                 } else {
192                         if(!(latest_dac_intr)) {
193                                 write_signals(&outputs_intr, 0x00000000);
194                         }
195                 }
196         } else if(ch == SIG_ADPCM_ADC_INTR) { // Push data to FIFO from ADC.
197                 if((data & mask) != 0) {
198                         uint32_t n_data = d_adc->read_signal(SIG_AD7820_DATA_REG);
199                         d_adc->write_signal(SIG_AD7820_CS, 0, 0xffffffff);
200                         if(!(adc_fifo->full())) {
201                                 adc_fifo->write((int)(n_data & 0xff));
202                         }
203                 }
204         }
205 }
206
207 uint32_t ADPCM::read_signal(int ch)
208 {
209         return 0;
210 }
211
212 #define STATE_VERSION   2
213
214 bool ADPCM::process_state(FILEIO* state_fio, bool loading)
215 {
216         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
217                 return false;
218         }
219         if(!state_fio->StateCheckInt32(this_device_id)) {
220                 return false;
221         }
222         if(!(adc_fifo->process_state((void *)state_fio, loading))) {
223                 return false;
224         }
225         state_fio->StateValue(opn2_mute);
226         state_fio->StateValue(adpcm_mute);
227
228         state_fio->StateValue(opx_intr);
229         state_fio->StateValue(dac_intr);
230         state_fio->StateValue(dac_intr_mask);
231         state_fio->StateValue(latest_dac_intr);
232
233         state_fio->StateValue(event_adc_clock);
234         return true;
235 }
236
237 }