OSDN Git Service

[VM][General][WIP] Start to merge upstream 2018-10-14.Open branch upstream_20181014 .
[csp-qt/common_source_project-fm7.git] / source / src / vm / i8259.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2005.06.10-
6
7         [ i8259 ]
8 */
9
10 #include "i8259.h"
11
12 //#define CHIP_MASK     (I8259_MAX_CHIPS - 1)
13
14 void I8259::initialize()
15 {
16         DEVICE::initialize();
17         __I8259_MAX_CHIPS = osd->get_feature_uint32_value(_T("I8259_MAX_CHIPS"));
18         if(__I8259_MAX_CHIPS >= 2) __I8259_MAX_CHIPS = 2;
19         __CHIP_MASK = __I8259_MAX_CHIPS - 1;
20         for(uint32_t c = 0; c < __I8259_MAX_CHIPS; c++) {
21                 pic[c].imr = 0xff;
22                 pic[c].irr = pic[c].isr = pic[c].prio = 0;
23                 pic[c].icw1 = pic[c].icw2 = pic[c].icw3 = pic[c].icw4 = 0;
24                 pic[c].ocw3 = 2;
25                 pic[c].icw2_r = pic[c].icw3_r = pic[c].icw4_r = 0;
26         }
27 }
28
29 void I8259::reset()
30 {
31         for(uint32_t c = 0; c < __I8259_MAX_CHIPS; c++) {
32                 pic[c].irr_tmp = 0;
33                 pic[c].irr_tmp_id = -1;
34         }
35 }
36
37 void I8259::write_io8(uint32_t addr, uint32_t data)
38 {
39         int c = (addr >> 1) & __CHIP_MASK;
40         
41         if(addr & 1) {
42                 if(pic[c].icw2_r) {
43                         // icw2
44                         pic[c].icw2 = data;
45                         pic[c].icw2_r = 0;
46                 } else if(pic[c].icw3_r) {
47                         // icw3
48                         pic[c].icw3 = data;
49                         pic[c].icw3_r = 0;
50                 } else if(pic[c].icw4_r) {
51                         // icw4
52                         pic[c].icw4 = data;
53                         pic[c].icw4_r = 0;
54                 } else {
55                         // ocw1
56                         uint8_t irr = pic[c].irr;
57                         for(int i = 0; i < 8; i++) {
58                                 uint8_t bit = 1 << i;
59                                 if((pic[c].irr & bit) && (pic[c].imr & bit) && !(data & bit)) {
60                                         pic[c].irr &= ~bit;
61                                         pic[c].irr_tmp |= bit;
62                                 }
63                         }
64                         if(irr != pic[c].irr) {
65                                 if(pic[c].irr_tmp_id != -1) {
66                                         cancel_event(this, pic[c].irr_tmp_id);
67                                 }
68                                 register_event(this, c, 10, false, &pic[c].irr_tmp_id);
69                         }
70                         pic[c].imr = data;
71                 }
72         } else {
73                 if(data & 0x10) {
74                         // icw1
75                         pic[c].icw1 = data;
76                         pic[c].icw2_r = 1;
77                         pic[c].icw3_r = (data & 2) ? 0 : 1;
78                         pic[c].icw4_r = data & 1;
79                         
80                         pic[c].irr = 0;
81                         pic[c].irr_tmp = 0;
82                         pic[c].isr = 0;
83                         pic[c].imr = 0;
84                         pic[c].prio = 0;
85                         if(!(pic[c].icw1 & 1)) {
86                                 pic[c].icw4 = 0;
87                         }
88                         pic[c].ocw3 = 0;
89                 } else if((data & 0x98) == 0x08) {
90                         // ocw3
91                         pic[c].ocw3 = data;
92                 } else if((data & 0x18) == 0x00) {
93                         // ocw2
94                         int n = data & 7;
95                         uint8_t mask = 1 << n;
96                         
97                         switch(data & 0xe0) {
98                         case 0x00:
99                                 pic[c].prio = 0;
100                                 break;
101                         case 0x20:
102                                 for(n = 0, mask = (1 << pic[c].prio); n < 8; n++, mask = (mask << 1) | (mask >> 7)) {
103                                         if(pic[c].isr & mask) {
104                                                 pic[c].isr &= ~mask;
105                                                 break;
106                                         }
107                                 }
108                                 break;
109                         case 0x40:
110                                 break;
111                         case 0x60:
112                                 if(pic[c].isr & mask) {
113                                         pic[c].isr &= ~mask;
114                                 }
115                                 break;
116                         case 0x80:
117                                 pic[c].prio = (pic[c].prio + 1) & 7;
118                                 break;
119                         case 0xa0:
120                                 for(n = 0, mask = (1 << pic[c].prio); n < 8; n++, mask = (mask << 1) | (mask >> 7)) {
121                                         if(pic[c].isr & mask) {
122                                                 pic[c].isr &= ~mask;
123                                                 pic[c].prio = (pic[c].prio + 1) & 7;
124                                                 break;
125                                         }
126                                 }
127                                 break;
128                         case 0xc0:
129                                 pic[c].prio = n & 7;
130                                 break;
131                         case 0xe0:
132                                 if(pic[c].isr & mask) {
133                                         pic[c].isr &= ~mask;
134                                         pic[c].irr &= ~mask;
135                                         pic[c].irr_tmp &= ~mask;
136                                         pic[c].prio = (pic[c].prio + 1) & 7;
137                                 }
138                                 break;
139                         }
140                 }
141         }
142         update_intr();
143 }
144
145 uint32_t I8259::read_io8(uint32_t addr)
146 {
147         int c = (addr >> 1) & __CHIP_MASK;
148         
149         if(addr & 1) {
150                 return pic[c].imr;
151         } else {
152                 if(pic[c].ocw3 & 4) {
153                         // poling command
154                         if(pic[c].isr & ~pic[c].imr) {
155                                 get_intr_ack();
156                         }
157                         for(int i = 0; i < 8; i++) {
158                                 if((1 << i) & pic[c].irr & ~pic[c].imr) {
159                                         return 0x80 | i;
160                                 }
161                         }
162                 } else if((pic[c].ocw3 & 3) == 2) {
163                         return pic[c].irr;
164                 } else if((pic[c].ocw3 & 3) == 3) {
165                         return pic[c].isr & ~pic[c].imr;
166                 }
167                 return 0;
168         }
169 }
170
171 void I8259::write_signal(int id, uint32_t data, uint32_t mask)
172 {
173         if(data & mask) {
174                 pic[id >> 3].irr |= 1 << (id & 7);
175                 update_intr();
176         } else {
177                 pic[id >> 3].irr &= ~(1 << (id & 7));
178                 update_intr();
179         }
180 }
181
182 void I8259::event_callback(int event_id, int err)
183 {
184         int c = event_id & __CHIP_MASK;
185         uint8_t irr = pic[c].irr;
186         
187         pic[c].irr |= pic[c].irr_tmp;
188         pic[c].irr_tmp = 0;
189         pic[c].irr_tmp_id = -1;
190         
191         if(irr != pic[c].irr) {
192                 update_intr();
193         }
194 }
195
196 uint32_t I8259::read_signal(int id)
197 {
198         return (pic[id >> 3].irr & (1 << (id & 7))) ? 1 : 0;
199 }
200
201 void I8259::update_intr()
202 {
203         bool intr = false;
204         
205         for(uint32_t c = 0; c < __I8259_MAX_CHIPS; c++) {
206                 uint8_t irr = pic[c].irr;
207                 if((c + 1) < __I8259_MAX_CHIPS) {
208                         // this is master
209                         if(pic[c + 1].irr & (~pic[c + 1].imr)) {
210                                 // request from slave
211                                 irr |= 1 << (pic[c + 1].icw3 & 7);
212                         }
213                 }
214                 irr &= (~pic[c].imr);
215                 if(!irr) {
216                         break;
217                 }
218                 if(!(pic[c].ocw3 & 0x20)) {
219                         irr |= pic[c].isr;
220                 }
221                 int level = pic[c].prio;
222                 uint8_t bit = 1 << level;
223                 while(!(irr & bit)) {
224                         level = (level + 1) & 7;
225                         bit = 1 << level;
226                 }
227                 if(((c + 1) < __I8259_MAX_CHIPS) && (pic[c].icw3 & bit)) {
228                         // check slave
229                         continue;
230                 }
231                 if(pic[c].isr & bit) {
232                         break;
233                 }
234                 
235                 // interrupt request
236                 req_chip = c;
237                 req_level = level;
238                 req_bit = bit;
239                 intr = true;
240                 break;
241         }
242         if(d_cpu) {
243                 d_cpu->set_intr_line(intr, true, 0);
244         }
245 }
246
247 uint32_t I8259::get_intr_ack()
248 {
249         // ack (INTA=L)
250         uint32_t vector;
251         
252         pic[req_chip].isr |= req_bit;
253         pic[req_chip].irr &= ~req_bit;
254         if(req_chip > 0) {
255                 // update isr and irr of master
256                 uint8_t slave = 1 << (pic[req_chip].icw3 & 7);
257                 pic[req_chip - 1].isr |= slave;
258                 pic[req_chip - 1].irr &= ~slave;
259         }
260         if(pic[req_chip].icw4 & 1) {
261                 // 8086 mode
262                 vector = (pic[req_chip].icw2 & 0xf8) | req_level;
263         } else {
264                 // 8080 mode
265                 uint16_t addr = (uint16_t)pic[req_chip].icw2 << 8;
266                 if(pic[req_chip].icw1 & 4) {
267                         addr |= (pic[req_chip].icw1 & 0xe0) | (req_level << 2);
268                 } else {
269                         addr |= (pic[req_chip].icw1 & 0xc0) | (req_level << 3);
270                 }
271                 vector = 0xcd | (addr << 8);
272         }
273         if(pic[req_chip].icw4 & 2) {
274                 // auto eoi
275                 pic[req_chip].isr &= ~req_bit;
276         }
277         return vector;
278 }
279
280 #define STATE_VERSION   2
281
282 bool I8259::process_state(FILEIO* state_fio, bool loading)
283 {
284         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
285                 return false;
286         }
287         if(!state_fio->StateCheckInt32(this_device_id)) {
288                 return false;
289         }
290         state_fio->StateBuffer(pic, sizeof(pic), 1); // ToDo:
291         state_fio->StateInt32(req_chip);
292         state_fio->StateInt32(req_level);
293         state_fio->StateUint8(req_bit);
294         return true;
295 }
296