OSDN Git Service

[DOC] For release 2017-01-24.
[csp-qt/common_source_project-fm7.git] / source / src / vm / i8237.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : MESS
5         Author : Takeda.Toshiya
6         Date   : 2006.12.06 -
7
8         [ i8237 ]
9 */
10
11 #include "i8237.h"
12
13 void I8237::reset()
14 {
15         low_high = false;
16         cmd = req = tc = 0;
17         mask = 0xff;
18 }
19
20 void I8237::write_io8(uint32_t addr, uint32_t data)
21 {
22         int ch = (addr >> 1) & 3;
23         uint8_t bit = 1 << (data & 3);
24         
25         switch(addr & 0x0f) {
26         case 0x00: case 0x02: case 0x04: case 0x06:
27                 if(low_high) {
28                         dma[ch].bareg = (dma[ch].bareg & 0xff) | (data << 8);
29                 } else {
30                         dma[ch].bareg = (dma[ch].bareg & 0xff00) | data;
31                 }
32                 dma[ch].areg = dma[ch].bareg;
33                 low_high = !low_high;
34                 break;
35         case 0x01: case 0x03: case 0x05: case 0x07:
36                 if(low_high) {
37                         dma[ch].bcreg = (dma[ch].bcreg & 0xff) | (data << 8);
38                 } else {
39                         dma[ch].bcreg = (dma[ch].bcreg & 0xff00) | data;
40                 }
41                 dma[ch].creg = dma[ch].bcreg;
42                 low_high = !low_high;
43                 break;
44         case 0x08:
45                 // command register
46                 cmd = data;
47                 break;
48         case 0x09:
49                 // request register
50                 if(data & 4) {
51                         if(!(req & bit)) {
52                                 req |= bit;
53 #ifndef SINGLE_MODE_DMA
54                                 do_dma();
55 #endif
56                         }
57                 } else {
58                         req &= ~bit;
59                 }
60                 break;
61         case 0x0a:
62                 // single mask register
63                 if(data & 4) {
64                         mask |= bit;
65                 } else {
66                         mask &= ~bit;
67                 }
68                 break;
69         case 0x0b:
70                 // mode register
71                 dma[data & 3].mode = data;
72                 break;
73         case 0x0c:
74                 low_high = false;
75                 break;
76         case 0x0d:
77                 // clear master
78                 reset();
79                 break;
80         case 0x0e:
81                 // clear mask register
82                 mask = 0;
83                 break;
84         case 0x0f:
85                 // all mask register
86                 mask = data & 0x0f;
87                 break;
88         }
89 }
90
91 uint32_t I8237::read_io8(uint32_t addr)
92 {
93         int ch = (addr >> 1) & 3;
94         uint32_t val = 0xff;
95         
96         switch(addr & 0x0f) {
97         case 0x00: case 0x02: case 0x04: case 0x06:
98                 if(low_high) {
99                         val = dma[ch].areg >> 8;
100                 } else {
101                         val = dma[ch].areg & 0xff;
102                 }
103                 low_high = !low_high;
104                 return val;
105         case 0x01: case 0x03: case 0x05: case 0x07:
106                 if(low_high) {
107                         val = dma[ch].creg >> 8;
108                 } else {
109                         val = dma[ch].creg & 0xff;
110                 }
111                 low_high = !low_high;
112                 return val;
113         case 0x08:
114                 // status register
115                 val = (req << 4) | tc;
116                 tc = 0;
117                 return val;
118         case 0x0d:
119                 // temporary register
120                 return tmp & 0xff;
121         }
122         return 0xff;
123 }
124
125 void I8237::write_signal(int id, uint32_t data, uint32_t mask)
126 {
127         if(SIG_I8237_CH0 <= id && id <= SIG_I8237_CH3) {
128                 uint8_t bit = 1 << (id & 3);
129                 if(data & mask) {
130                         if(!(req & bit)) {
131                                 write_signals(&dma[id & 3].outputs_tc, 0);
132                                 req |= bit;
133 #ifndef SINGLE_MODE_DMA
134                                 do_dma();
135 #endif
136                         }
137                 } else {
138                         req &= ~bit;
139                 }
140         } else if(SIG_I8237_BANK0 <= id && id <= SIG_I8237_BANK3) {
141                 // external bank registers
142                 dma[id & 3].bankreg = data & mask;
143         } else if(SIG_I8237_MASK0 <= id && id <= SIG_I8237_MASK3) {
144                 // external bank registers
145                 dma[id & 3].incmask = data & mask;
146         }
147 }
148
149 // note: if SINGLE_MODE_DMA is defined, do_dma() is called in every machine cycle
150
151 void I8237::do_dma()
152 {
153         for(int ch = 0; ch < 4; ch++) {
154                 uint8_t bit = 1 << ch;
155                 if((req & bit) && !(mask & bit)) {
156                         // execute dma
157                         while(req & bit) {
158                                 if((dma[ch].mode & 0x0c) == 0) {
159                                         // verify
160                                 } else if((dma[ch].mode & 0x0c) == 4) {
161                                         // io -> memory
162                                         tmp = read_io(ch);
163                                         write_mem(dma[ch].areg | (dma[ch].bankreg << 16), tmp);
164                                 } else if((dma[ch].mode & 0x0c) == 8) {
165                                         // memory -> io
166                                         tmp = read_mem(dma[ch].areg | (dma[ch].bankreg << 16));
167                                         write_io(ch, tmp);
168                                 }
169                                 if(dma[ch].mode & 0x20) {
170                                         dma[ch].areg--;
171                                         if(dma[ch].areg == 0xffff) {
172                                                 dma[ch].bankreg = (dma[ch].bankreg & ~dma[ch].incmask) | ((dma[ch].bankreg - 1) & dma[ch].incmask);
173                                         }
174                                 } else {
175                                         dma[ch].areg++;
176                                         if(dma[ch].areg == 0) {
177                                                 dma[ch].bankreg = (dma[ch].bankreg & ~dma[ch].incmask) | ((dma[ch].bankreg + 1) & dma[ch].incmask);
178                                         }
179                                 }
180                                 
181                                 // check dma condition
182                                 if(dma[ch].creg-- == 0) {
183                                         // TC
184                                         if(dma[ch].mode & 0x10) {
185                                                 // self initialize
186                                                 dma[ch].areg = dma[ch].bareg;
187                                                 dma[ch].creg = dma[ch].bcreg;
188                                         } else {
189                                                 mask |= bit;
190                                         }
191                                         req &= ~bit;
192                                         tc |= bit;
193                                         write_signals(&dma[ch].outputs_tc, 0xffffffff);
194 #ifdef SINGLE_MODE_DMA
195                                 } else if((dma[ch].mode & 0xc0) == 0x40) {
196                                         // single mode
197                                         break;
198 #endif
199                                 }
200                         }
201                 }
202         }
203 #ifdef SINGLE_MODE_DMA
204         if(d_dma) {
205                 d_dma->do_dma();
206         }
207 #endif
208 }
209
210 void I8237::write_mem(uint32_t addr, uint32_t data)
211 {
212         if(mode_word) {
213                 d_mem->write_dma_data16(addr << 1, data);
214         } else {
215                 d_mem->write_dma_data8(addr, data);
216         }
217 }
218
219 uint32_t I8237::read_mem(uint32_t addr)
220 {
221         if(mode_word) {
222                 return d_mem->read_dma_data16(addr << 1);
223         } else {
224                 return d_mem->read_dma_data8(addr);
225         }
226 }
227
228 void I8237::write_io(int ch, uint32_t data)
229 {
230         if(mode_word) {
231                 dma[ch].dev->write_dma_io16(0, data);
232         } else {
233                 dma[ch].dev->write_dma_io8(0, data);
234         }
235 }
236
237 uint32_t I8237::read_io(int ch)
238 {
239         if(mode_word) {
240                 return dma[ch].dev->read_dma_io16(0);
241         } else {
242                 return dma[ch].dev->read_dma_io8(0);
243         }
244 }
245
246 #define STATE_VERSION   1
247
248 void I8237::save_state(FILEIO* state_fio)
249 {
250         state_fio->FputUint32(STATE_VERSION);
251         state_fio->FputInt32(this_device_id);
252         
253         for(int i = 0; i < 4; i++) {
254                 state_fio->FputUint16(dma[i].areg);
255                 state_fio->FputUint16(dma[i].creg);
256                 state_fio->FputUint16(dma[i].bareg);
257                 state_fio->FputUint16(dma[i].bcreg);
258                 state_fio->FputUint8(dma[i].mode);
259                 state_fio->FputUint16(dma[i].bankreg);
260                 state_fio->FputUint16(dma[i].incmask);
261         }
262         state_fio->FputBool(low_high);
263         state_fio->FputUint8(cmd);
264         state_fio->FputUint8(req);
265         state_fio->FputUint8(mask);
266         state_fio->FputUint8(tc);
267         state_fio->FputUint32(tmp);
268         state_fio->FputBool(mode_word);
269 }
270
271 bool I8237::load_state(FILEIO* state_fio)
272 {
273         if(state_fio->FgetUint32() != STATE_VERSION) {
274                 return false;
275         }
276         if(state_fio->FgetInt32() != this_device_id) {
277                 return false;
278         }
279         for(int i = 0; i < 4; i++) {
280                 dma[i].areg = state_fio->FgetUint16();
281                 dma[i].creg = state_fio->FgetUint16();
282                 dma[i].bareg = state_fio->FgetUint16();
283                 dma[i].bcreg = state_fio->FgetUint16();
284                 dma[i].mode = state_fio->FgetUint8();
285                 dma[i].bankreg = state_fio->FgetUint16();
286                 dma[i].incmask = state_fio->FgetUint16();
287         }
288         low_high = state_fio->FgetBool();
289         cmd = state_fio->FgetUint8();
290         req = state_fio->FgetUint8();
291         mask = state_fio->FgetUint8();
292         tc = state_fio->FgetUint8();
293         tmp = state_fio->FgetUint32();
294         mode_word = state_fio->FgetBool();
295         return true;
296 }
297