OSDN Git Service

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