OSDN Git Service

444e5e0fd88a65fad65f4e7f80e5a4063a2f4291
[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 "rf5c68.h"
12 #include "ad7820kr.h"
13
14 namespace FMTOWNS {
15 void ADPCM::initialize()
16 {
17         for(int i = 0; i < 8; i++) {
18                 dac_int_mask[i] = true; // true = enable intrrupt.
19                 dac_intr[i] = false;
20         }
21         intr_opx = false;
22 }
23
24 void ADPCM::reset()
25 {
26         // Is clear FIFO?
27 }
28 uint32_t ADPCM::read_io8(uint32_t addr)
29 {
30         /*
31           0x04e7 - 0x04e8 : ADC
32           0x04f0 - 0x04f8 : DAC
33         */
34         uint8_t val = 0xff;
35         switch(addr & 0x1f) {
36         case 0x07: // ADC data register
37                 if(!(adc_fifo->empty())) {
38                         val = (uint8_t)(adc_fifo->read() & 0xff);
39                 } else {
40                         val = 0x00;
41                 }
42                 break;
43         case 0x08: // ADC flags
44                 val = (!(adc_fifo->empty())) ? 0x01 : 0x00;
45                 break;
46         case 0x09: // Int13 reason
47                 {
48                         bool intr_pcm = false;
49                         for(int i = 0; i < 8; i++) {
50                                 if(dac_intr[i]) {
51                                         intr_pcm = true;
52                                         break;
53                                 }
54                         }
55                         val = 0xf6 | ((intr_pcm) ? 0x08 : 0x00) | ((intr_opx) ? 0x01 : 0x00);
56                 }
57                 break;
58         case 0x0a: // PCM Interrupt mask
59                 val = 0x00;
60                 for(int i = 0; i < 8; i++) {
61                         val = val | ((dac_int_mask[i]) ? (0x01 << i) : 0);
62                 }
63                 break;
64         case 0x0b: // PCM Interrupt status
65                 {
66                         bool _s = false;
67                         val = 0x00;
68                         for(int i = 0; i < 8; i++) {
69                                 val = val | ((dac_intr[i]) ? (0x01 << i) : 0);
70                         }
71                         for(int i = 0; i < 8; i++) {
72                                 if(dac_intr[i]) {
73                                         _s = true;
74                                 }
75                                 dac_intr[i] = false;
76                         }
77                         if(_s) {
78                                 d_pic->write_signal(SIG_I8259_IR5 | SIG_I8259_CHIP1, 0x00000000, 0xffffffff);
79                         }
80                 }
81                 break;
82         default:
83                 if((addr & 0x1f) >= 0x10) val = d_rf5c68->read_io8(addr & 0x0f); // AROUND DAC
84                 break;
85         }
86         return val;
87 }
88
89 void ADPCM::write_io8(uint32_t addr, uint32_t data)
90 {
91         uint32_t naddr = addr & 0x1f;
92         if(naddr == 0x08) {
93                 adc_fifo->clear();
94         } else if(naddr == 0x0a) {
95                 uint32_t mask = 0x01;
96                 for(int i = 0; i < 8; i++) {
97                         if((data & mask) != 0) {
98                                 dac_int_mask[i] = true;
99                         } else {
100                                 dac_int_mask[i] = false;
101                         }
102                         mask <<= 1;
103                 }
104         } else if(naddr >= 0x10) {
105                 d_rf5c68->write_io8(naddr & 0x0f, data);
106         }
107 }
108
109 uint32_t ADPCM::read_data8(uint32_t addr)
110 {
111         if((addr >= 0xc2200000) && (addr < 0xc2201000)) {
112                 return d_rf5c68->read_data8(addr & 0x0fff);
113         }
114         return 0xff;
115 }
116
117 void ADPCM::write_data8(uint32_t addr, uint32_t data)
118 {
119         if((addr >= 0xc2200000) && (addr < 0xc2201000)) {
120                 d_rf5c68->write_data8(addr & 0x0fff, data);
121         }
122 }
123
124 void ADPCM::write_signal(int ch, uint32_t data, uint32_t mask)
125 {
126         if(ch == SIG_ADPCM_WRITE_INTERRUPT) {
127                 uint32_t n_ch = data & 0x07;
128                 bool n_onoff = (((data & mask) & 0x00000008) != 0) ? true : false;
129                 bool n_allset =(((data & mask) & 0x80000000) != 0) ? true : false;
130                 if(!(n_allset)) {
131                         n_onoff = n_onoff & dac_int_mask[n_ch];
132                         if(n_onoff != dac_intr[n_ch]) { // SET/RESET INT13                              
133                                 write_signals(&output_intr, (n_onoff) ? 0xffffffff : 0x00000000);
134                         }
135                         dac_intr[n_ch] = n_onoff;
136                 } else {
137                         // ALLSET
138                         bool n_backup;
139                         bool _s = false;
140                         for(int i = 0; i < 8; i++) { // SET/RESET INT13                         
141                                 n_backup = dac_intr[i];
142                                 dac_intr[i] = n_onoff & dac_int_mask[i];
143                                 if(n_backup != dac_intr[i]) _s = true;
144                         }
145                         if(_s) {
146                                 write_signals(&output_intr, (n_onoff) ? 0xffffffff : 0x00000000);
147                         }
148                 }
149         } else if(ch == SIG_ADPCM_OPX_INTR) { // SET/RESET INT13
150                 intr_opx = ((data & mask) != 0); 
151                 write_signals(&output_intr, (intr_opx) ? 0xffffffff : 0x00000000);
152         } else if(ch == SIG_ADPCM_PUSH_FIFO) { // Push data to FIFO from ADC.
153                 if(adc_fifo->full()) {
154                         adc_fifo->read(); // Dummy read
155                 }
156                 adc_fifo->write((int)(data & 0xff));
157         }
158 }
159
160 #define STATE_VERSION   1
161
162 bool ADPCM::process_state(FILEIO* state_fio, bool loading)
163 {
164         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
165                 return false;
166         }
167         if(!state_fio->StateCheckInt32(this_device_id)) {
168                 return false;
169         }
170         if(!(adc_fifo->process_state((void *)state_fio, loading))) {
171                 return false;
172         }
173         state_fio->StateValue(intr_opx);
174         state_fio->StateArray(dac_intr,     sizeof(dac_intr), 1);
175         state_fio->StateArray(dac_int_mask, sizeof(dac_int_mask), 1);
176         return true;
177 }
178         
179 }