OSDN Git Service

[VM][WIP][STATE] Updating state framework to upstream 2018-10-05.Still may cause...
[csp-qt/common_source_project-fm7.git] / source / src / vm / i8253.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.06.01-
6
7         [ i8253/i8254 ]
8 */
9
10 #include "i8253.h"
11
12 void I8253::initialize()
13 {
14         DEVICE::initialize();
15         __HAS_I8254 = osd->check_feature(_T("HAS_I8254"));
16         for(int ch = 0; ch < 3; ch++) {
17                 counter[ch].prev_out = true;
18                 counter[ch].prev_in = false;
19                 counter[ch].gate = true;
20                 counter[ch].count = 0x10000;
21                 counter[ch].count_reg = 0;
22                 counter[ch].ctrl_reg = 0x34;
23                 counter[ch].mode = 3;
24                 counter[ch].count_latched = false;
25                 counter[ch].low_read = counter[ch].high_read = false;
26                 counter[ch].low_write = counter[ch].high_write = false;
27                 counter[ch].delay = false;
28                 counter[ch].start = false;
29 //#ifdef HAS_I8254
30                 if(__HAS_I8254) {
31                         // 8254 read-back command
32                         counter[ch].null_count = true;
33                         counter[ch].status_latched = false;
34                 }
35 //#endif
36         }
37 }
38
39 void I8253::reset()
40 {
41         for(int ch = 0; ch < 3; ch++) {
42                 counter[ch].register_id = -1;
43         }
44 }
45
46 #define COUNT_VALUE(n) ((counter[n].count_reg == 0) ? 0x10000 : (counter[n].mode == 3 && counter[n].count_reg == 1) ? 0x10001 : counter[n].count_reg)
47
48 void I8253::write_io8(uint32_t addr, uint32_t data)
49 {
50         int ch = addr & 3;
51         
52         switch(addr & 3) {
53         case 0:
54         case 1:
55         case 2:
56                 // write count register
57                 if(!counter[ch].low_write && !counter[ch].high_write) {
58                         if(counter[ch].ctrl_reg & 0x10) {
59                                 counter[ch].low_write = true;
60                         }
61                         if(counter[ch].ctrl_reg & 0x20) {
62                                 counter[ch].high_write = true;
63                         }
64                 }
65                 if(counter[ch].low_write) {
66                         counter[ch].count_reg = data;
67                         counter[ch].low_write = false;
68                 } else if(counter[ch].high_write) {
69                         if((counter[ch].ctrl_reg & 0x30) == 0x20) {
70                                 counter[ch].count_reg = data << 8;
71                         } else {
72                                 counter[ch].count_reg |= data << 8;
73                         }
74                         counter[ch].high_write = false;
75                 }
76 //#ifdef HAS_I8254
77                 if(__HAS_I8254) counter[ch].null_count = true;
78 //#endif
79                 // set signal
80                 if(counter[ch].mode == 0) {
81                         set_signal(ch, false);
82                 } else {
83                         set_signal(ch, true);
84                 }
85                 // start count
86                 if(counter[ch].mode == 0 || counter[ch].mode == 4) {
87                         // restart with new count
88                         stop_count(ch);
89                         counter[ch].delay = true;
90                         start_count(ch);
91                 } else if(counter[ch].mode == 2 || counter[ch].mode == 3) {
92                         // start with new counter after the current count is finished
93                         if(!counter[ch].start) {
94                                 counter[ch].delay = true;
95                                 start_count(ch);
96                         }
97                 }
98                 break;
99                 
100         case 3: // ctrl reg
101                 if((data & 0xc0) == 0xc0) {
102 //#ifdef HAS_I8254
103                         if(__HAS_I8254) {
104                                 // i8254 read-back command
105                                 for(ch = 0; ch < 3; ch++) {
106                                         uint8_t bit = 2 << ch;
107                                         if(!(data & 0x10) && !counter[ch].status_latched) {
108                                                 counter[ch].status = counter[ch].ctrl_reg & 0x3f;
109                                                 if(counter[ch].prev_out) {
110                                                         counter[ch].status |= 0x80;
111                                                 }
112                                                 if(counter[ch].null_count) {
113                                                         counter[ch].status |= 0x40;
114                                                 }
115                                                 counter[ch].status_latched = true;
116                                         }
117                                         if(!(data & 0x20) && !counter[ch].count_latched) {
118                                                 latch_count(ch);
119                                         }
120                                 }
121                         }
122 //#endif
123                         break;
124                 }
125                 ch = (data >> 6) & 3;
126                 
127                 if(data & 0x30) {
128                         static const int modes[8] = {0, 1, 2, 3, 4, 5, 2, 3};
129 //                      int prev = counter[ch].mode;
130                         counter[ch].mode = modes[(data >> 1) & 7];
131                         counter[ch].count_latched = false;
132                         counter[ch].low_read = counter[ch].high_read = false;
133                         counter[ch].low_write = counter[ch].high_write = false;
134                         counter[ch].ctrl_reg = data;
135                         // set signal
136                         if(counter[ch].mode == 0) {
137                                 set_signal(ch, false);
138                         } else {
139                                 set_signal(ch, true);
140                         }
141                         // stop count
142 //                      if(counter[ch].mode != prev || counter[ch].mode == 0 || counter[ch].mode == 4) {
143                                 stop_count(ch);
144                                 counter[ch].count_reg = 0;
145 //                      }
146 //#ifdef HAS_I8254
147                                 if(__HAS_I8254) counter[ch].null_count = true;
148 //#endif
149                 } else if(!counter[ch].count_latched) {
150                         latch_count(ch);
151                 }
152                 break;
153         }
154 }
155
156 uint32_t I8253::read_io8(uint32_t addr)
157 {
158         int ch = addr & 3;
159         
160         switch(ch) {
161         case 0:
162         case 1:
163         case 2:
164 //#ifdef HAS_I8254
165                 if(__HAS_I8254) {
166                         if(counter[ch].status_latched) {
167                                 counter[ch].status_latched = false;
168                                 return counter[ch].status;
169                         }
170                 }
171 //#endif
172                 // if not latched, through current count
173                 if(!counter[ch].count_latched) {
174                         if(!counter[ch].low_read && !counter[ch].high_read) {
175                                 latch_count(ch);
176                         }
177                 }
178                 // return latched count
179                 if(counter[ch].low_read) {
180                         counter[ch].low_read = false;
181                         if(!counter[ch].high_read) {
182                                 counter[ch].count_latched = false;
183                         }
184                         return counter[ch].latch & 0xff;
185                 } else if(counter[ch].high_read) {
186                         counter[ch].high_read = false;
187                         counter[ch].count_latched = false;
188                         return (counter[ch].latch >> 8) & 0xff;
189                 }
190         }
191         return 0xff;
192 }
193
194 void I8253::event_callback(int event_id, int err)
195 {
196         int ch = event_id;
197         counter[ch].register_id = -1;
198         input_clock(ch, counter[ch].input_clk);
199         
200         // register next event
201         if(counter[ch].freq && counter[ch].start) {
202                 counter[ch].input_clk = counter[ch].delay ? 1 : get_next_count(ch);
203                 counter[ch].period = (int)(cpu_clocks * counter[ch].input_clk / counter[ch].freq + err);
204                 counter[ch].prev_clk = get_current_clock() + err;
205                 register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
206         }
207 }
208
209 void I8253::write_signal(int id, uint32_t data, uint32_t mask)
210 {
211         bool next = ((data & mask) != 0);
212         
213         switch(id) {
214         case SIG_I8253_CLOCK_0:
215                 if(counter[0].prev_in && !next) {
216                         input_clock(0, 1);
217                 }
218                 counter[0].prev_in = next;
219                 break;
220         case SIG_I8253_CLOCK_1:
221                 if(counter[1].prev_in && !next) {
222                         input_clock(1, 1);
223                 }
224                 counter[1].prev_in = next;
225                 break;
226         case SIG_I8253_CLOCK_2:
227                 if(counter[2].prev_in && !next) {
228                         input_clock(2, 1);
229                 }
230                 counter[2].prev_in = next;
231                 break;
232         case SIG_I8253_GATE_0:
233                 input_gate(0, next);
234                 break;
235         case SIG_I8253_GATE_1:
236                 input_gate(1, next);
237                 break;
238         case SIG_I8253_GATE_2:
239                 input_gate(2, next);
240                 break;
241         }
242 }
243
244 void I8253::input_clock(int ch, int clock)
245 {
246         if(!(counter[ch].start && clock)) {
247                 return;
248         }
249         if(counter[ch].delay) {
250                 clock -= 1;
251                 counter[ch].delay = false;
252                 counter[ch].count = COUNT_VALUE(ch);
253 //#ifdef HAS_I8254
254                 if(__HAS_I8254) counter[ch].null_count = false;
255 //#endif
256         }
257         
258         // update counter
259         counter[ch].count -= clock;
260         int32_t tmp = COUNT_VALUE(ch);
261 loop:
262         if(counter[ch].mode == 3) {
263                 int32_t half = tmp >> 1;
264                 set_signal(ch, counter[ch].count > half);
265         } else {
266                 if(counter[ch].count <= 1) {
267                         if(counter[ch].mode == 2 || counter[ch].mode == 4 || counter[ch].mode == 5) {
268                                 set_signal(ch, false);
269                         }
270                 }
271                 if(counter[ch].count <= 0) {
272                         set_signal(ch, true);
273                 }
274         }
275         if(counter[ch].count <= 0) {
276                 if(counter[ch].mode == 0 || counter[ch].mode == 2 || counter[ch].mode == 3) {
277                         counter[ch].count += tmp;
278 //#ifdef HAS_I8254
279                         if(__HAS_I8254) counter[ch].null_count = false;
280 //#endif
281                         goto loop;
282                 } else {
283                         counter[ch].start = false;
284                         counter[ch].count = 0x10000;
285                 }
286         }
287 }
288
289 void I8253::input_gate(int ch, bool signal)
290 {
291         bool prev = counter[ch].gate;
292         counter[ch].gate = signal;
293         
294         if(prev && !signal) {
295                 // stop count
296                 if(!(counter[ch].mode == 1 || counter[ch].mode == 5)) {
297                         stop_count(ch);
298                 }
299                 // set output signal
300                 if(counter[ch].mode == 2 || counter[ch].mode == 3) {
301                         set_signal(ch, true);
302                 }
303         } else if(!prev && signal) {
304                 // restart count
305                 stop_count(ch);
306                 if(!(counter[ch].mode == 0 || counter[ch].mode == 4)) {
307                         counter[ch].delay = true;
308                 }
309                 start_count(ch);
310                 // set output signal
311                 if(counter[ch].mode == 1) {
312                         set_signal(ch, false);
313                 }
314         }
315 }
316
317 void I8253::start_count(int ch)
318 {
319         if(counter[ch].low_write || counter[ch].high_write) {
320                 return;
321         }
322         if(!counter[ch].gate) {
323                 return;
324         }
325         counter[ch].start = true;
326         
327         // register event
328         if(counter[ch].freq) {
329                 counter[ch].input_clk = counter[ch].delay ? 1 : get_next_count(ch);
330                 counter[ch].period = (int)(cpu_clocks * counter[ch].input_clk / counter[ch].freq);
331                 counter[ch].prev_clk = get_current_clock();
332                 register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
333         }
334 }
335
336 void I8253::stop_count(int ch)
337 {
338         counter[ch].start = false;
339         
340         // cancel event
341         if(counter[ch].register_id != -1) {
342                 cancel_event(this, counter[ch].register_id);
343         }
344         counter[ch].register_id = -1;
345 }
346
347 void I8253::latch_count(int ch)
348 {
349         if(counter[ch].register_id != -1) {
350                 // update counter
351                 int passed = get_passed_clock(counter[ch].prev_clk);
352                 uint32_t input = (uint32_t)(counter[ch].freq * passed / cpu_clocks);
353                 if(input > 0) {
354                         bool expired = (counter[ch].input_clk <= input);
355                         input_clock(ch, input);
356                         // cancel and re-register event
357                         if(expired) {
358                                 cancel_event(this, counter[ch].register_id);
359                                 if(counter[ch].freq && counter[ch].start) {
360                                         counter[ch].input_clk = counter[ch].delay ? 1 : get_next_count(ch);
361                                         counter[ch].period = (int)(cpu_clocks * counter[ch].input_clk / counter[ch].freq);
362                                         counter[ch].prev_clk = get_current_clock();
363                                         register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
364                                 }
365                         } else {
366                                 cancel_event(this, counter[ch].register_id);
367                                 counter[ch].input_clk -= input;
368                                 counter[ch].period -= passed;
369                                 counter[ch].prev_clk = get_current_clock();
370                                 register_event_by_clock(this, ch, counter[ch].period, false, &counter[ch].register_id);
371                         }
372                 }
373         }
374         // latch counter
375         counter[ch].latch = (uint16_t)counter[ch].count;
376         counter[ch].count_latched = true;
377         if((counter[ch].ctrl_reg & 0x30) == 0x10) {
378                 // lower byte
379                 counter[ch].low_read = true;
380                 counter[ch].high_read = false;
381         } else if((counter[ch].ctrl_reg & 0x30) == 0x20) {
382                 // upper byte
383                 counter[ch].low_read = false;
384                 counter[ch].high_read = true;
385         } else {
386                 // lower -> upper
387                 counter[ch].low_read = counter[ch].high_read = true;
388         }
389 }
390
391 void I8253::set_signal(int ch, bool signal)
392 {
393         bool prev = counter[ch].prev_out;
394         counter[ch].prev_out = signal;
395         
396         if(prev && !signal) {
397                 // H->L
398                 write_signals(&counter[ch].outputs, 0);
399         } else if(!prev && signal) {
400                 // L->H
401                 write_signals(&counter[ch].outputs, 0xffffffff);
402         }
403 }
404
405 int I8253::get_next_count(int ch)
406 {
407         if(counter[ch].mode == 2 || counter[ch].mode == 4 || counter[ch].mode == 5) {
408                 return (counter[ch].count > 1) ? counter[ch].count - 1 : 1;
409         }
410         if(counter[ch].mode == 3) {
411                 int32_t half = COUNT_VALUE(ch) >> 1;
412                 return (counter[ch].count > half) ? counter[ch].count - half : counter[ch].count;
413         }
414         return counter[ch].count;
415 }
416
417 #define STATE_VERSION   1
418
419 bool I8253::process_state(FILEIO* state_fio, bool loading)
420 {
421         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
422                 return false;
423         }
424         if(!state_fio->StateCheckInt32(this_device_id)) {
425                 return false;
426         }
427         for(int i = 0; i < 3; i++) {
428                 state_fio->StateBool(counter[i].prev_out);
429                 state_fio->StateBool(counter[i].prev_in);
430                 state_fio->StateBool(counter[i].gate);
431                 state_fio->StateInt32(counter[i].count);
432                 state_fio->StateUint16(counter[i].latch);
433                 state_fio->StateUint16(counter[i].count_reg);
434                 state_fio->StateUint8(counter[i].ctrl_reg);
435                 state_fio->StateBool(counter[i].count_latched);
436                 state_fio->StateBool(counter[i].low_read);
437                 state_fio->StateBool(counter[i].high_read);
438                 state_fio->StateBool(counter[i].low_write);
439                 state_fio->StateBool(counter[i].high_write);
440                 state_fio->StateInt32(counter[i].mode);
441                 state_fio->StateBool(counter[i].delay);
442                 state_fio->StateBool(counter[i].start);
443                 if(__HAS_I8254) {
444                         state_fio->StateBool(counter[i].null_count);
445                         state_fio->StateBool(counter[i].status_latched);
446                         state_fio->StateUint8(counter[i].status);
447                 }
448                 state_fio->StateUint64(counter[i].freq);
449                 state_fio->StateInt32(counter[i].register_id);
450                 state_fio->StateUint32(counter[i].input_clk);
451                 state_fio->StateInt32(counter[i].period);
452                 state_fio->StateUint32(counter[i].prev_clk);
453         }
454         state_fio->StateUint64(cpu_clocks);
455         return true;
456 }