OSDN Git Service

[VM][COMMON_VM] Include IO:: class to common_vm.
[csp-qt/common_source_project-fm7.git] / source / src / vm / mc6840.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : MAME 0.168 Motorola 6840 (PTM)
5         Author : Takeda.Toshiya
6         Date   : 2016.02.24-
7
8         [ MC6840 ]
9 */
10
11 // license:BSD-3-Clause
12 // copyright-holders:James Wallace
13 /***************************************************************************
14
15     Motorola 6840 (PTM)
16
17     Programmable Timer Module
18
19     Written By J.Wallace based on previous work by Aaron Giles,
20    'Re-Animator' and Mathis Rosenhauer.
21
22     Todo:
23          Confirm handling for 'Single Shot' operation.
24          (Datasheet suggests that output starts high, going low
25          on timeout, opposite of continuous case)
26          Establish whether ptm6840_set_c? routines can replace
27          hard coding of external clock frequencies.
28
29
30     Operation:
31     The interface is arranged as follows:
32
33     Internal Clock frequency,
34     Clock 1 frequency, Clock 2 frequency, Clock 3 frequency,
35     Clock 1 output, Clock 2 output, Clock 3 output,
36     IRQ function
37
38     If the external clock frequencies are not fixed, they should be
39     entered as '0', and the ptm6840_set_c?(which, state) functions
40     should be used instead if necessary (This should allow the VBLANK
41     clock on the MCR units to operate).
42
43
44     2009-06 Converted to be a device
45
46 ***************************************************************************/
47
48 #include "mc6840.h"
49
50 #define from_hz(v)      (1000000.0 / (double)(v))
51 typedef double attotime;
52
53 #define m_out0_cb(o,v)  write_signals(&outputs_ch0, (v) ? 0xffffffff : 0)
54 #define m_out1_cb(o,v)  write_signals(&outputs_ch1, (v) ? 0xffffffff : 0)
55 #define m_out2_cb(o,v)  write_signals(&outputs_ch2, (v) ? 0xffffffff : 0)
56 #define m_irq_cb(v)     write_signals(&outputs_irq, (v) ? 0xffffffff : 0)
57
58 //#define PTMVERBOSE 0
59 //#define PLOG(x) do { if (PTMVERBOSE) logerror x; } while (0)
60
61 /***************************************************************************
62     IMPLEMENTATION
63 ***************************************************************************/
64
65 //-------------------------------------------------
66 //  device_start - device-specific startup
67 //-------------------------------------------------
68
69 void MC6840::initialize()
70 {
71         DEVICE::initialize();
72         for (int i = 0; i < 3; i++)
73         {
74 //              if ( m_external_clock[i] == 0 )
75 //              {
76 //                      m_external_clock[i] = 1;
77 //              }
78                 m_gate[i] = m_clk[i] = 0;
79         }
80 }
81
82 //-------------------------------------------------
83 //  device_reset - device-specific reset
84 //-------------------------------------------------
85
86 void MC6840::reset()
87 {
88         m_control_reg[2]         = 0;
89         m_control_reg[1]         = 0;
90         m_control_reg[0]         = 1;
91         m_status_reg             = 0;
92         m_t3_divisor             = 1;
93         m_status_read_since_int = 0;
94         m_IRQ                   = 0;
95         m_t3_scaler             = 0;
96         for (int i = 0; i < 3; i++)
97         {
98                 m_counter[i] = 0xffff;
99                 m_latch[i]   = 0xffff;
100                 m_output[i]  = 0;
101                 m_fired[i]   = 0;
102                 m_enabled[i] = 0;
103                 m_mode[i] = 0;
104                 m_timer[i] = -1;
105         }
106 }
107
108 //-------------------------------------------------
109 //  subtract_from_counter - Subtract from Counter
110 //-------------------------------------------------
111
112 void MC6840::subtract_from_counter(int counter, int count)
113 {
114         double clock;
115
116         // Determine the clock frequency for this timer
117         if (m_control_reg[counter] & 0x02)
118         {
119                 clock = m_internal_clock;
120         }
121         else
122         {
123                 clock = m_external_clock[counter];
124         }
125
126         // Dual-byte mode
127         if (m_control_reg[counter] & 0x04)
128         {
129                 int lsb = m_counter[counter] & 0xff;
130                 int msb = m_counter[counter] >> 8;
131
132                 // Count the clocks
133                 lsb -= count;
134
135                 // Loop while we're less than zero
136                 while (lsb < 0)
137                 {
138                         // Borrow from the MSB
139                         lsb += (m_latch[counter] & 0xff) + 1;
140                         msb--;
141
142                         // If MSB goes less than zero, we've expired
143                         if (msb < 0)
144                         {
145                                 timeout(counter);
146                                 msb = (m_latch[counter] >> 8) + 1;
147                         }
148                 }
149
150                 // Store the result
151                 m_counter[counter] = (msb << 8) | lsb;
152         }
153
154         // Word mode
155         else
156         {
157                 int word = m_counter[counter];
158
159                 // Count the clocks
160                 word -= count;
161
162                 // loop while we're less than zero
163                 while (word < 0)
164                 {
165                         // Borrow from the MSB
166                         word += m_latch[counter] + 1;
167
168                         // We've expired
169                         timeout(counter);
170                 }
171
172                 // Store the result
173                 m_counter[counter] = word;
174         }
175
176         if (clock && m_enabled[counter])
177         {
178                 attotime duration = from_hz(clock) * m_counter[counter];
179
180                 if (counter == 2)
181                 {
182                         duration *= m_t3_divisor;
183                 }
184
185                 if (m_timer[counter] != -1)
186                 {
187                         cancel_event(this, m_timer[counter]);
188                 }
189                 register_event(this, counter, duration, false, &m_timer[counter]);
190         }
191 }
192
193 //-------------------------------------------------
194 //  tick
195 //-------------------------------------------------
196
197 void MC6840::tick(int counter, int count)
198 {
199         if (counter == 2)
200         {
201                 m_t3_scaler += count;
202
203                 if ( m_t3_scaler > m_t3_divisor - 1)
204                 {
205                         subtract_from_counter(counter, 1);
206                         m_t3_scaler = 0;
207                 }
208         }
209         else
210         {
211                 subtract_from_counter(counter, count);
212         }
213 }
214
215 //-------------------------------------------------
216 //  update_interrupts - Update Internal Interrupts
217 //-------------------------------------------------
218
219 void MC6840::update_interrupts()
220 {
221         int new_state = ((m_status_reg & 0x01) && (m_control_reg[0] & 0x40)) ||
222                                         ((m_status_reg & 0x02) && (m_control_reg[1] & 0x40)) ||
223                                         ((m_status_reg & 0x04) && (m_control_reg[2] & 0x40));
224
225 //      if (new_state != m_IRQ)
226         {
227                 m_IRQ = new_state;
228
229                 if (m_IRQ)
230                 {
231                         m_status_reg |= 0x80;
232                 }
233                 else
234                 {
235                         m_status_reg &= ~0x80;
236                 }
237
238                 m_irq_cb(m_IRQ);
239         }
240 }
241
242 //-------------------------------------------------
243 //  compute_counter - Compute Counter
244 //-------------------------------------------------
245
246 UINT16 MC6840::compute_counter( int counter )
247 {
248         double clock;
249
250         // determine the clock frequency for this timer
251         if (m_control_reg[counter] & 0x02)
252         {
253                 clock = m_internal_clock;
254 //              PLOG(("MC6840 #%s: %d internal clock freq %f \n", tag(), counter, clock));
255         }
256         else
257         {
258                 clock = m_external_clock[counter];
259 //              PLOG(("MC6840 #%s: %d external clock freq %f \n", tag(), counter, clock));
260         }
261
262         // If there's no timer, return the count
263         if (!(clock && m_enabled[counter]))
264         {
265 //              PLOG(("MC6840 #%s: read counter(%d): %d\n", tag(), counter, m_counter[counter]));
266                 return m_counter[counter];
267         }
268
269         // See how many are left
270         int remaining = (int)(get_event_remaining_usec(m_timer[counter]) / 1000000.0 * clock);
271
272         // Adjust the count for dual byte mode
273         if (m_control_reg[counter] & 0x04)
274         {
275                 int divisor = (m_counter[counter] & 0xff) + 1;
276                 int msb = remaining / divisor;
277                 int lsb = remaining % divisor;
278                 remaining = (msb << 8) | lsb;
279         }
280 //      PLOG(("MC6840 #%s: read counter(%d): %d\n", tag(), counter, remaining));
281         return remaining;
282 }
283
284 //-------------------------------------------------
285 //  reload_count - Reload Counter
286 //-------------------------------------------------
287
288 void MC6840::reload_count(int idx)
289 {
290         double clock;
291
292         // Copy the latched value in
293         m_counter[idx] = m_latch[idx];
294
295         // Determine the clock frequency for this timer
296         if (m_control_reg[idx] & 0x02)
297         {
298                 clock = m_internal_clock;
299 //              PLOG(("MC6840 #%s: %d internal clock freq %f \n", tag(), idx, clock));
300         }
301         else
302         {
303                 clock = m_external_clock[idx];
304 //              PLOG(("MC6840 #%s: %d external clock freq %f \n", tag(), idx, clock));
305         }
306
307         // Determine the number of clock periods before we expire
308         int count = m_counter[idx];
309         if (m_control_reg[idx] & 0x04)
310         {
311                 count = ((count >> 8) + 1) * ((count & 0xff) + 1);
312         }
313         else
314         {
315                 count = count + 1;
316         }
317
318         m_fired[idx] = 0;
319
320         if ((m_mode[idx] == 4) || (m_mode[idx] == 6))
321         {
322                 m_output[idx] = 1;
323                 switch (idx)
324                 {
325                         case 0:
326                                 m_out0_cb((offs_t)0, m_output[0]);
327                                 break;
328                         case 1:
329                                 m_out1_cb((offs_t)0, m_output[1]);
330                                 break;
331                         case 2:
332                                 m_out2_cb((offs_t)0, m_output[2]);
333                                 break;
334                 }
335         }
336
337         if(clock) {
338                 // Set the timer
339 //              PLOG(("MC6840 #%s: reload_count(%d): clock = %f  count = %d\n", tag(), idx, clock, count));
340
341                 attotime duration = from_hz(clock) * count;
342                 if (idx == 2)
343                 {
344                         duration *= m_t3_divisor;
345                 }
346
347 //              PLOG(("MC6840 #%s: reload_count(%d): output = %f\n", tag(), idx, duration.as_double()));
348
349                 if (m_timer[idx] != -1)
350                 {
351                         cancel_event(this, m_timer[idx]);
352                 }
353                 register_event(this, idx, duration, false, &m_timer[idx]);
354         }
355
356         m_enabled[idx] = 1;
357 }
358
359 //-------------------------------------------------
360 //  read - Read Timer
361 //-------------------------------------------------
362
363 uint32_t MC6840::read_io8(uint32_t offset)
364 {
365         int val;
366
367         offset &= 7;
368
369         switch ( offset )
370         {
371                 case PTM_6840_CTRL1:
372                 {
373                         val = 0;
374                         break;
375                 }
376
377                 case PTM_6840_STATUS:
378                 {
379 //                      PLOG(("%s: MC6840 #%s: Status read = %04X\n", machine().describe_context(), tag(), m_status_reg));
380                         m_status_read_since_int |= m_status_reg & 0x07;
381                         val = m_status_reg;
382                         break;
383                 }
384
385                 case PTM_6840_MSBBUF1:
386                 case PTM_6840_MSBBUF2:
387                 case PTM_6840_MSBBUF3:
388                 {
389                         int idx = (offset - 2) / 2;
390                         int result = compute_counter(idx);
391
392                         // Clear the interrupt if the status has been read
393                         if (m_status_read_since_int & (1 << idx))
394                         {
395                                 m_status_reg &= ~(1 << idx);
396                                 update_interrupts();
397                         }
398
399                         m_lsb_buffer = result & 0xff;
400
401 //                      PLOG(("%s: MC6840 #%s: Counter %d read = %04X\n", machine().describe_context(), tag(), idx, result >> 8));
402                         val = result >> 8;
403                         break;
404                 }
405
406                 case PTM_6840_LSB1:
407                 case PTM_6840_LSB2:
408                 case PTM_6840_LSB3:
409                 {
410                         val = m_lsb_buffer;
411                         break;
412                 }
413
414                 default:
415                 {
416                         val = 0;
417                         break;
418                 }
419
420         }
421         return val;
422 }
423
424 //-------------------------------------------------
425 //  write - Write Timer
426 //-------------------------------------------------
427
428 void MC6840::write_io8(uint32_t offset, uint32_t data)
429 {
430         offset &= 7;
431
432         switch ( offset )
433         {
434                 case PTM_6840_CTRL1:
435                 case PTM_6840_CTRL2:
436                 {
437                         int idx = (offset == 1) ? 1 : (m_control_reg[1] & 0x01) ? 0 : 2;
438                         UINT8 diffs = data ^ m_control_reg[idx];
439                         m_t3_divisor = (m_control_reg[2] & 0x01) ? 8 : 1;
440                         m_mode[idx] = (data >> 3) & 0x07;
441                         m_control_reg[idx] = data;
442
443 //                      PLOG(("MC6840 #%s : Control register %d selected\n", tag(), idx));
444 //                      PLOG(("operation mode   = %s\n", opmode[ m_mode[idx] ]));
445 //                      PLOG(("value            = %04X\n", m_control_reg[idx]));
446 //                      PLOG(("t3divisor        = %d\n", m_t3_divisor));
447
448                         if (!(m_control_reg[idx] & 0x80 ))
449                         {
450                                 // Output cleared
451                                 switch (idx)
452                                 {
453                                         case 0:
454                                                 m_out0_cb((offs_t)0, 0);
455                                                 break;
456                                         case 1:
457                                                 m_out1_cb((offs_t)0, 0);
458                                                 break;
459                                         case 2:
460                                                 m_out2_cb((offs_t)0, 0);
461                                                 break;
462                                 }
463                         }
464                         // Reset?
465                         if (idx == 0 && (diffs & 0x01))
466                         {
467                                 // Holding reset down
468                                 if (data & 0x01)
469                                 {
470 //                                      PLOG(("MC6840 #%s : Timer reset\n", tag()));
471                                         for (int i = 0; i < 3; i++)
472                                         {
473                                                 if (m_timer[i] != -1)
474                                                 {
475                                                         cancel_event(this, m_timer[i]);
476                                                         m_timer[i] = -1;
477                                                 }
478                                                 m_enabled[i] = 0;
479                                         }
480                                 }
481                                 // Releasing reset
482                                 else
483                                 {
484                                         for (int i = 0; i < 3; i++)
485                                         {
486                                                 reload_count(i);
487                                         }
488                                 }
489
490                                 m_status_reg = 0;
491                                 update_interrupts();
492
493                                 // Changing the clock source? (e.g. Zwackery)
494                                 if (diffs & 0x02)
495                                 {
496                                         reload_count(idx);
497                                 }
498                         }
499                         break;
500                 }
501
502                 case PTM_6840_MSBBUF1:
503                 case PTM_6840_MSBBUF2:
504                 case PTM_6840_MSBBUF3:
505                 {
506 //                      PLOG(("MC6840 #%s msbbuf%d = %02X\n", tag(), offset / 2, data));
507                         m_msb_buffer = data;
508                         break;
509                 }
510
511                 case PTM_6840_LSB1:
512                 case PTM_6840_LSB2:
513                 case PTM_6840_LSB3:
514                 {
515                         int idx = (offset - 3) / 2;
516                         m_latch[idx] = (m_msb_buffer << 8) | (data & 0xff);
517
518                         // Clear the interrupt
519                         m_status_reg &= ~(1 << idx);
520                         update_interrupts();
521
522                         // Reload the count if in an appropriate mode
523                         if (!(m_control_reg[idx] & 0x10))
524                         {
525                                 reload_count(idx);
526                         }
527
528 //                      PLOG(("%s:MC6840 #%s: Counter %d latch = %04X\n", machine().describe_context(), tag(), idx, m_latch[idx]));
529                         break;
530                 }
531         }
532 }
533
534 //-------------------------------------------------
535 //  timeout - Called if timer is mature
536 //-------------------------------------------------
537
538 void MC6840::timeout(int idx)
539 {
540 //      PLOG(("**ptm6840 %s t%d timeout**\n", tag(), idx));
541
542         // Set the interrupt flag
543         m_status_reg |= (1 << idx);
544         m_status_read_since_int &= ~(1 << idx);
545         update_interrupts();
546
547         if ( m_control_reg[idx] & 0x80 )
548         {
549                 if ((m_mode[idx] == 0)||(m_mode[idx] == 2))
550                 {
551                         m_output[idx] = m_output[idx] ? 0 : 1;
552 //                      PLOG(("**ptm6840 %s t%d output %d **\n", tag(), idx, m_output[idx]));
553
554                         switch (idx)
555                         {
556                                 case 0:
557                                         m_out0_cb((offs_t)0, m_output[0]);
558                                         break;
559                                 case 1:
560                                         m_out1_cb((offs_t)0, m_output[1]);
561                                         break;
562                                 case 2:
563                                         m_out2_cb((offs_t)0, m_output[2]);
564                                         break;
565                         }
566                 }
567                 if ((m_mode[idx] == 4)||(m_mode[idx] == 6))
568                 {
569                         if (!m_fired[idx])
570                         {
571                                 m_output[idx] = 1;
572 //                              PLOG(("**ptm6840 %s t%d output %d **\n", tag(), idx, m_output[idx]));
573
574                                 switch (idx)
575                                 {
576                                         case 0:
577                                                 m_out0_cb((offs_t)0, m_output[0]);
578                                                 break;
579                                         case 1:
580                                                 m_out1_cb((offs_t)0, m_output[1]);
581                                                 break;
582                                         case 2:
583                                                 m_out2_cb((offs_t)0, m_output[2]);
584                                                 break;
585                                 }
586
587                                 // No changes in output until reinit
588                                 m_fired[idx] = 1;
589
590                                 m_status_reg |= (1 << idx);
591                                 m_status_read_since_int &= ~(1 << idx);
592                                 update_interrupts();
593                         }
594                 }
595         }
596         m_enabled[idx]= 0;
597         reload_count(idx);
598 }
599
600 //-------------------------------------------------
601 //  set_gate - set gate status (0 or 1)
602 //-------------------------------------------------
603
604 void MC6840::set_gate(int idx, int state)
605 {
606         if ((m_mode[idx] & 1) == 0)
607         {
608                 if (state == 0 && m_gate[idx])
609                 {
610                         reload_count(idx);
611                 }
612         }
613         m_gate[idx] = state;
614 }
615
616 //-------------------------------------------------
617 //  set_clock - set clock status (0 or 1)
618 //-------------------------------------------------
619
620 void MC6840::set_clock(int idx, int state)
621 {
622
623         if (!(m_control_reg[idx] & 0x02))
624         {
625                 if (state && m_clk[idx] == 0)
626                 {
627                         tick(idx, 1);
628                 }
629         }
630         m_clk[idx] = state;
631 }
632
633 void MC6840::event_callback(int id, int err)
634 {
635         m_timer[id] = -1;
636         timeout(id);
637 }
638
639 void MC6840::write_signal(int id, uint32_t data, uint32_t mask)
640 {
641         switch (id)
642         {
643                 case SIG_MC6840_CLOCK_0:
644                         set_clock(0, (data & mask) ? 1 : 0);
645                         break;
646                 case SIG_MC6840_CLOCK_1:
647                         set_clock(1, (data & mask) ? 1 : 0);
648                         break;
649                 case SIG_MC6840_CLOCK_2:
650                         set_clock(2, (data & mask) ? 1 : 0);
651                         break;
652                 case SIG_MC6840_GATE_0:
653                         set_gate(0, (data & mask) ? 1 : 0);
654                         break;
655                 case SIG_MC6840_GATE_1:
656                         set_gate(1, (data & mask) ? 1 : 0);
657                         break;
658                 case SIG_MC6840_GATE_2:
659                         set_gate(2, (data & mask) ? 1 : 0);
660                         break;
661         }
662 }
663
664 #define STATE_VERSION   2
665
666 bool MC6840::process_state(FILEIO* state_fio, bool loading)
667 {
668         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
669                 return false;
670         }
671         if(!state_fio->StateCheckInt32(this_device_id)) {
672                 return false;
673         }
674         state_fio->StateArray(m_control_reg, sizeof(m_control_reg), 1);
675         state_fio->StateArray(m_output, sizeof(m_output), 1);
676         state_fio->StateArray(m_gate, sizeof(m_gate), 1);
677         state_fio->StateArray(m_clk, sizeof(m_clk), 1);
678         state_fio->StateArray(m_enabled, sizeof(m_enabled), 1);
679         state_fio->StateArray(m_mode, sizeof(m_mode), 1);
680         state_fio->StateArray(m_fired, sizeof(m_fired), 1);
681         state_fio->StateValue(m_t3_divisor);
682         state_fio->StateValue(m_t3_scaler);
683         state_fio->StateValue(m_IRQ);
684         state_fio->StateValue(m_status_reg);
685         state_fio->StateValue(m_status_read_since_int);
686         state_fio->StateValue(m_lsb_buffer);
687         state_fio->StateValue(m_msb_buffer);
688         state_fio->StateArray(m_timer, sizeof(m_timer), 1);
689         state_fio->StateArray(m_latch, sizeof(m_latch), 1);
690         state_fio->StateArray(m_counter, sizeof(m_counter), 1);
691         return true;
692 }
693