OSDN Git Service

fd25f7daa77ced06d2110405e33633856b537545
[csp-qt/common_source_project-fm7.git] / source / src / vm / i8255.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.06.01-
6
7         [ i8255 ]
8 */
9
10 #include "i8255.h"
11
12 // mode1 input
13 #define BIT_IBF_A       0x20    // PC5
14 #define BIT_STB_A       0x10    // PC4
15 #define BIT_STB_B       0x04    // PC2
16 #define BIT_IBF_B       0x02    // PC1
17
18 #define BIT_OBF_A       0x80    // PC7
19 #define BIT_ACK_A       0x40    // PC6
20 #define BIT_ACK_B       0x04    // PC2
21 #define BIT_OBF_B       0x02    // PC1
22
23 #define BIT_INTR_A      0x08    // PC3
24 #define BIT_INTR_B      0x01    // PC0
25
26 void I8255::initialize()
27 {
28         DEVICE::initialize();
29         __I8255_AUTO_HAND_SHAKE = osd->check_feature(_T("I8255_AUTO_HAND_SHAKE"));
30 }
31
32 void I8255::reset()
33 {
34         for(int i = 0; i < 3; i++) {
35                 port[i].rmask = 0xff;
36                 port[i].first = true;
37                 port[i].mode = 0;
38         }
39 }
40
41 void I8255::write_io8(uint32_t addr, uint32_t data)
42 {
43         int ch = addr & 3;
44         
45         switch(ch) {
46         case 0:
47         case 1:
48         case 2:
49                 if(port[ch].wreg != data || port[ch].first) {
50                         write_signals(&port[ch].outputs, port[ch].wreg = data);
51                         port[ch].first = false;
52                 }
53 //#ifndef I8255_AUTO_HAND_SHAKE
54                 if(__I8255_AUTO_HAND_SHAKE) break;
55                 if(ch == 0) {
56                         if(port[0].mode == 1 || port[0].mode == 2) {
57                                 uint32_t val = port[2].wreg & ~BIT_OBF_A;
58                                 if(port[2].wreg & BIT_ACK_A) {
59                                         val &= ~BIT_INTR_A;
60                                 }
61                                 write_io8(2, val);
62                         }
63                 } else if(ch == 1) {
64                         if(port[1].mode == 1) {
65                                 uint32_t val = port[2].wreg & ~BIT_OBF_B;
66                                 if(port[2].wreg & BIT_ACK_B) {
67                                         val &= ~BIT_INTR_B;
68                                 }
69                                 write_io8(2, val);
70                         }
71                 }
72 //#endif
73                 break;
74         case 3:
75                 if(data & 0x80) {
76                         port[0].mode = (data & 0x40) ? 2 : ((data >> 5) & 1);
77                         port[0].rmask = (port[0].mode == 2) ? 0xff : (data & 0x10) ? 0xff : 0;
78                         port[1].mode = (data >> 2) & 1;
79                         port[1].rmask = (data & 2) ? 0xff : 0;
80                         port[2].rmask = ((data & 8) ? 0xf0 : 0) | ((data & 1) ? 0xf : 0);
81                         // clear ports
82                         if(clear_ports_by_cmdreg) {
83                                 write_io8(0, 0);
84                                 write_io8(1, 0);
85                                 write_io8(2, 0);
86                         }
87                         // setup control signals
88                         if(port[0].mode != 0 || port[1].mode != 0) {
89                                 uint32_t val = port[2].wreg;
90                                 if(port[0].mode == 1 || port[0].mode == 2) {
91                                         val &= ~BIT_IBF_A;
92                                         val |= BIT_OBF_A;
93                                         val &= ~BIT_INTR_A;
94                                 }
95                                 if(port[1].mode == 1) {
96                                         if(port[1].mode == 0xff) {
97                                                 val &= ~BIT_IBF_B;
98                                         } else {
99                                                 val |= BIT_OBF_B;
100                                         }
101                                         val &= ~BIT_INTR_B;
102                                 }
103                                 write_io8(2, val);
104                         }
105                 } else {
106                         uint32_t val = port[2].wreg;
107                         int bit = (data >> 1) & 7;
108                         if(data & 1) {
109                                 val |= 1 << bit;
110                         } else {
111                                 val &= ~(1 << bit);
112                         }
113                         write_io8(2, val);
114                 }
115                 break;
116         }
117 }
118
119 uint32_t I8255::read_io8(uint32_t addr)
120 {
121         int ch = addr & 3;
122         
123         switch(ch) {
124         case 0:
125         case 1:
126         case 2:
127                 if(ch == 0) {
128                         if(port[0].mode == 1 || port[0].mode == 2) {
129                                 uint32_t val = port[2].wreg & ~BIT_IBF_A;
130                                 if(port[2].wreg & BIT_STB_A) {
131                                         val &= ~BIT_INTR_A;
132                                 }
133                                 write_io8(2, val);
134                         }
135                 } else if(ch == 1) {
136                         if(port[1].mode == 1) {
137                                 uint32_t val = port[2].wreg & ~BIT_IBF_B;
138                                 if(port[2].wreg & BIT_STB_B) {
139                                         val &= ~BIT_INTR_B;
140                                 }
141                                 write_io8(2, val);
142                         }
143                 }
144                 return (port[ch].rreg & port[ch].rmask) | (port[ch].wreg & ~port[ch].rmask);
145         }
146         return 0xff;
147 }
148
149 void I8255::write_signal(int id, uint32_t data, uint32_t mask)
150 {
151         switch(id) {
152         case SIG_I8255_PORT_A:
153                 port[0].rreg = (port[0].rreg & ~mask) | (data & mask);
154 //#ifdef I8255_AUTO_HAND_SHAKE
155                 if(!__I8255_AUTO_HAND_SHAKE) break;
156                 if(port[0].mode == 1 || port[0].mode == 2) {
157                         uint32_t val = port[2].wreg | BIT_IBF_A;
158                         if(port[2].wreg & BIT_STB_A) {
159                                 val |= BIT_INTR_A;
160                         }
161                         write_io8(2, val);
162                 }
163 //#endif
164                 break;
165         case SIG_I8255_PORT_B:
166                 port[1].rreg = (port[1].rreg & ~mask) | (data & mask);
167 //#ifdef I8255_AUTO_HAND_SHAKE
168                 if(!__I8255_AUTO_HAND_SHAKE) break;
169                 if(port[1].mode == 1) {
170                         uint32_t val = port[2].wreg | BIT_IBF_B;
171                         if(port[2].wreg & BIT_STB_B) {
172                                 val |= BIT_INTR_B;
173                         }
174                         write_io8(2, val);
175                 }
176 //#endif
177                 break;
178         case SIG_I8255_PORT_C:
179 //#ifndef I8255_AUTO_HAND_SHAKE
180                 if(!__I8255_AUTO_HAND_SHAKE) {
181                         if(port[0].mode == 1 || port[0].mode == 2) {
182                                 if(mask & BIT_STB_A) {
183                                         if((port[2].rreg & BIT_STB_A) && !(data & BIT_STB_A)) {
184                                                 write_io8(2, port[2].wreg | BIT_IBF_A);
185                                         } else if(!(port[2].rreg & BIT_STB_A) && (data & BIT_STB_A)) {
186                                                 if(port[2].wreg & BIT_STB_A) {
187                                                         write_io8(2, port[2].wreg | BIT_INTR_A);
188                                                 }
189                                         }
190                                 }
191                                 if(mask & BIT_ACK_A) {
192                                         if((port[2].rreg & BIT_ACK_A) && !(data & BIT_ACK_A)) {
193                                                 write_io8(2, port[2].wreg | BIT_OBF_A);
194                                         } else if(!(port[2].rreg & BIT_ACK_A) && (data & BIT_ACK_A)) {
195                                                 if(port[2].wreg & BIT_ACK_A) {
196                                                         write_io8(2, port[2].wreg | BIT_INTR_A);
197                                                 }
198                                         }
199                                 }
200                         }
201                         if(port[1].mode == 1) {
202                                 if(port[0].rmask == 0xff) {
203                                         if(mask & BIT_STB_B) {
204                                                 if((port[2].rreg & BIT_STB_B) && !(data & BIT_STB_B)) {
205                                                         write_io8(2, port[2].wreg | BIT_IBF_B);
206                                                 } else if(!(port[2].rreg & BIT_STB_B) && (data & BIT_STB_B)) {
207                                                         if(port[2].wreg & BIT_STB_B) {
208                                                                 write_io8(2, port[2].wreg | BIT_INTR_B);
209                                                         }
210                                                 }
211                                         }
212                                 } else {
213                                         if(mask & BIT_ACK_B) {
214                                                 if((port[2].rreg & BIT_ACK_B) && !(data & BIT_ACK_B)) {
215                                                         write_io8(2, port[2].wreg | BIT_OBF_B);
216                                                 } else if(!(port[2].rreg & BIT_ACK_B) && (data & BIT_ACK_B)) {
217                                                         if(port[2].wreg & BIT_ACK_B) {
218                                                                 write_io8(2, port[2].wreg | BIT_INTR_B);
219                                                         }
220                                                 }
221                                         }
222                                 }
223                         }
224                 }
225 //#endif
226                 port[2].rreg = (port[2].rreg & ~mask) | (data & mask);
227                 break;
228         }
229 }
230
231 uint32_t I8255::read_signal(int id)
232 {
233         switch(id) {
234         case SIG_I8255_PORT_A:
235                 return port[0].wreg;
236         case SIG_I8255_PORT_B:
237                 return port[1].wreg;
238         case SIG_I8255_PORT_C:
239                 return port[2].wreg;
240         }
241         return 0;
242 }
243
244 #define STATE_VERSION   1
245
246 void I8255::save_state(FILEIO* state_fio)
247 {
248         state_fio->FputUint32(STATE_VERSION);
249         state_fio->FputInt32(this_device_id);
250         
251         for(int i = 0; i < 3; i++) {
252                 state_fio->FputUint8(port[i].wreg);
253                 state_fio->FputUint8(port[i].rreg);
254                 state_fio->FputUint8(port[i].rmask);
255                 state_fio->FputUint8(port[i].mode);
256                 state_fio->FputBool(port[i].first);
257         }
258 }
259
260 bool I8255::load_state(FILEIO* state_fio)
261 {
262         if(state_fio->FgetUint32() != STATE_VERSION) {
263                 return false;
264         }
265         if(state_fio->FgetInt32() != this_device_id) {
266                 return false;
267         }
268         for(int i = 0; i < 3; i++) {
269                 port[i].wreg = state_fio->FgetUint8();
270                 port[i].rreg = state_fio->FgetUint8();
271                 port[i].rmask = state_fio->FgetUint8();
272                 port[i].mode = state_fio->FgetUint8();
273                 port[i].first = state_fio->FgetBool();
274         }
275         return true;
276 }
277