OSDN Git Service

[VM][DEVICE][WIP] Updating State functions.Still cause FTBFS.
[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 "vm.h"
12 #include "../emu.h"
13 #include "i8237.h"
14
15
16 I8237::I8237(VM_TEMPLATE* parent_vm, EMU* parent_emu) : I8237_BASE(parent_vm, parent_emu)
17 {
18         for(int i = 0; i < 4; i++) {
19                 dma[i].dev = vm->dummy;
20         }
21 #ifdef SINGLE_MODE_DMA
22                 d_dma = NULL;
23 #endif
24 }
25
26 I8237::~I8237()
27 {
28 }
29
30 void I8237::write_io8(uint32_t addr, uint32_t data)
31 {
32         int ch = (addr >> 1) & 3;
33         uint8_t bit = 1 << (data & 3);
34         
35         switch(addr & 0x0f) {
36         case 0x00: case 0x02: case 0x04: case 0x06:
37                 if(low_high) {
38                         dma[ch].bareg = (dma[ch].bareg & 0xff) | (data << 8);
39                 } else {
40                         dma[ch].bareg = (dma[ch].bareg & 0xff00) | data;
41                 }
42                 dma[ch].areg = dma[ch].bareg;
43                 low_high = !low_high;
44                 break;
45         case 0x01: case 0x03: case 0x05: case 0x07:
46                 if(low_high) {
47                         dma[ch].bcreg = (dma[ch].bcreg & 0xff) | (data << 8);
48                 } else {
49                         dma[ch].bcreg = (dma[ch].bcreg & 0xff00) | data;
50                 }
51                 dma[ch].creg = dma[ch].bcreg;
52                 low_high = !low_high;
53                 break;
54         case 0x08:
55                 // command register
56                 cmd = data;
57                 break;
58         case 0x09:
59                 // request register
60                 if(data & 4) {
61                         if(!(req & bit)) {
62                                 req |= bit;
63 #ifndef SINGLE_MODE_DMA
64                                 do_dma();
65 #endif
66                         }
67                 } else {
68                         req &= ~bit;
69                 }
70                 break;
71         case 0x0a:
72                 // single mask register
73                 if(data & 4) {
74                         mask |= bit;
75                 } else {
76                         mask &= ~bit;
77                 }
78                 break;
79         case 0x0b:
80                 // mode register
81                 dma[data & 3].mode = data;
82                 break;
83         case 0x0c:
84                 low_high = false;
85                 break;
86         case 0x0d:
87                 // clear master
88                 reset();
89                 break;
90         case 0x0e:
91                 // clear mask register
92                 mask = 0;
93                 break;
94         case 0x0f:
95                 // all mask register
96                 mask = data & 0x0f;
97                 break;
98         }
99 }
100
101 void I8237::write_signal(int id, uint32_t data, uint32_t mask)
102 {
103         if(SIG_I8237_CH0 <= id && id <= SIG_I8237_CH3) {
104                 int ch = id - SIG_I8237_CH0;
105                 uint8_t bit = 1 << ch;
106                 if(data & mask) {
107                         if(!(req & bit)) {
108                                 write_signals(&dma[ch].outputs_tc, 0);
109                                 req |= bit;
110 #ifndef SINGLE_MODE_DMA
111                                 do_dma();
112 #endif
113                         }
114                 } else {
115                         req &= ~bit;
116                 }
117         } else if(SIG_I8237_BANK0 <= id && id <= SIG_I8237_BANK3) {
118                 // external bank registers
119                 int ch = id - SIG_I8237_BANK0;
120                 dma[ch].bankreg &= ~mask;
121                 dma[ch].bankreg |= data & mask;
122         } else if(SIG_I8237_MASK0 <= id && id <= SIG_I8237_MASK3) {
123                 // external bank registers
124                 int ch = id - SIG_I8237_MASK0;
125                 dma[ch].incmask &= ~mask;
126                 dma[ch].incmask |= data & mask;
127         }
128 }
129
130 uint32_t I8237::read_signal(int id)
131 {
132         if(SIG_I8237_BANK0 <= id && id <= SIG_I8237_BANK3) {
133                 // external bank registers
134                 int ch = id - SIG_I8237_BANK0;
135                 return dma[ch].bankreg;
136         } else if(SIG_I8237_MASK0 <= id && id <= SIG_I8237_MASK3) {
137                 // external bank registers
138                 int ch = id - SIG_I8237_MASK0;
139                 return dma[ch].incmask;
140         }
141         return 0;
142 }
143
144 // note: if SINGLE_MODE_DMA is defined, do_dma() is called in every machine cycle
145
146 void I8237::do_dma()
147 {
148         for(int ch = 0; ch < 4; ch++) {
149                 uint8_t bit = 1 << ch;
150                 if((req & bit) && !(mask & bit)) {
151                         // execute dma
152                         while(req & bit) {
153                                 switch(dma[ch].mode & 0x0c) {
154                                 case 0x00:
155                                         // verify
156                                         tmp = read_io(ch);
157                                         break;
158                                 case 0x04:
159                                         // io -> memory
160                                         tmp = read_io(ch);
161                                         write_mem(dma[ch].areg | (dma[ch].bankreg << 16), tmp);
162                                         break;
163                                 case 0x08:
164                                         // memory -> io
165                                         tmp = read_mem(dma[ch].areg | (dma[ch].bankreg << 16));
166                                         write_io(ch, tmp);
167                                         break;
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 #define STATE_VERSION   2
211
212 bool I8237::process_state(FILEIO* state_fio, bool loading)
213 {
214         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
215                 return false;
216         }
217         if(!state_fio->StateCheckInt32(this_device_id)) {
218                 return false;
219         }
220         for(int i = 0; i < 4; i++) {
221                 state_fio->StateValue(dma[i].areg);
222                 state_fio->StateValue(dma[i].creg);
223                 state_fio->StateValue(dma[i].bareg);
224                 state_fio->StateValue(dma[i].bcreg);
225                 state_fio->StateValue(dma[i].mode);
226                 state_fio->StateValue(dma[i].bankreg);
227                 state_fio->StateValue(dma[i].incmask);
228         }
229         state_fio->StateValue(low_high);
230         state_fio->StateValue(cmd);
231         state_fio->StateValue(req);
232         state_fio->StateValue(mask);
233         state_fio->StateValue(tc);
234         state_fio->StateValue(tmp);
235         state_fio->StateValue(mode_word);
236         state_fio->StateValue(addr_mask);
237         return true;
238 }