2 Skelton for retropc emulator
4 Origin : MAME 0.168 Motorola 6840 (PTM)
5 Author : Takeda.Toshiya
11 // license:BSD-3-Clause
12 // copyright-holders:James Wallace
13 /***************************************************************************
17 Programmable Timer Module
19 Written By J.Wallace based on previous work by Aaron Giles,
20 'Re-Animator' and Mathis Rosenhauer.
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.
31 The interface is arranged as follows:
33 Internal Clock frequency,
34 Clock 1 frequency, Clock 2 frequency, Clock 3 frequency,
35 Clock 1 output, Clock 2 output, Clock 3 output,
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).
44 2009-06 Converted to be a device
46 ***************************************************************************/
50 #define from_hz(v) (1000000.0 / (double)(v))
51 typedef double attotime;
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)
58 //#define PTMVERBOSE 0
59 //#define PLOG(x) do { if (PTMVERBOSE) logerror x; } while (0)
61 /***************************************************************************
63 ***************************************************************************/
65 //-------------------------------------------------
66 // device_start - device-specific startup
67 //-------------------------------------------------
69 void MC6840::initialize()
72 for (int i = 0; i < 3; i++)
74 // if ( m_external_clock[i] == 0 )
76 // m_external_clock[i] = 1;
78 m_gate[i] = m_clk[i] = 0;
82 //-------------------------------------------------
83 // device_reset - device-specific reset
84 //-------------------------------------------------
93 m_status_read_since_int = 0;
96 for (int i = 0; i < 3; i++)
98 m_counter[i] = 0xffff;
108 //-------------------------------------------------
109 // subtract_from_counter - Subtract from Counter
110 //-------------------------------------------------
112 void MC6840::subtract_from_counter(int counter, int count)
116 // Determine the clock frequency for this timer
117 if (m_control_reg[counter] & 0x02)
119 clock = m_internal_clock;
123 clock = m_external_clock[counter];
127 if (m_control_reg[counter] & 0x04)
129 int lsb = m_counter[counter] & 0xff;
130 int msb = m_counter[counter] >> 8;
135 // Loop while we're less than zero
138 // Borrow from the MSB
139 lsb += (m_latch[counter] & 0xff) + 1;
142 // If MSB goes less than zero, we've expired
146 msb = (m_latch[counter] >> 8) + 1;
151 m_counter[counter] = (msb << 8) | lsb;
157 int word = m_counter[counter];
162 // loop while we're less than zero
165 // Borrow from the MSB
166 word += m_latch[counter] + 1;
173 m_counter[counter] = word;
176 if (clock && m_enabled[counter])
178 attotime duration = from_hz(clock) * m_counter[counter];
182 duration *= m_t3_divisor;
185 if (m_timer[counter] != -1)
187 cancel_event(this, m_timer[counter]);
189 register_event(this, counter, duration, false, &m_timer[counter]);
193 //-------------------------------------------------
195 //-------------------------------------------------
197 void MC6840::tick(int counter, int count)
201 m_t3_scaler += count;
203 if ( m_t3_scaler > m_t3_divisor - 1)
205 subtract_from_counter(counter, 1);
211 subtract_from_counter(counter, count);
215 //-------------------------------------------------
216 // update_interrupts - Update Internal Interrupts
217 //-------------------------------------------------
219 void MC6840::update_interrupts()
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));
225 // if (new_state != m_IRQ)
231 m_status_reg |= 0x80;
235 m_status_reg &= ~0x80;
242 //-------------------------------------------------
243 // compute_counter - Compute Counter
244 //-------------------------------------------------
246 UINT16 MC6840::compute_counter( int counter )
250 // determine the clock frequency for this timer
251 if (m_control_reg[counter] & 0x02)
253 clock = m_internal_clock;
254 // PLOG(("MC6840 #%s: %d internal clock freq %f \n", tag(), counter, clock));
258 clock = m_external_clock[counter];
259 // PLOG(("MC6840 #%s: %d external clock freq %f \n", tag(), counter, clock));
262 // If there's no timer, return the count
263 if (!(clock && m_enabled[counter]))
265 // PLOG(("MC6840 #%s: read counter(%d): %d\n", tag(), counter, m_counter[counter]));
266 return m_counter[counter];
269 // See how many are left
270 int remaining = (int)(get_event_remaining_usec(m_timer[counter]) / 1000000.0 * clock);
272 // Adjust the count for dual byte mode
273 if (m_control_reg[counter] & 0x04)
275 int divisor = (m_counter[counter] & 0xff) + 1;
276 int msb = remaining / divisor;
277 int lsb = remaining % divisor;
278 remaining = (msb << 8) | lsb;
280 // PLOG(("MC6840 #%s: read counter(%d): %d\n", tag(), counter, remaining));
284 //-------------------------------------------------
285 // reload_count - Reload Counter
286 //-------------------------------------------------
288 void MC6840::reload_count(int idx)
292 // Copy the latched value in
293 m_counter[idx] = m_latch[idx];
295 // Determine the clock frequency for this timer
296 if (m_control_reg[idx] & 0x02)
298 clock = m_internal_clock;
299 // PLOG(("MC6840 #%s: %d internal clock freq %f \n", tag(), idx, clock));
303 clock = m_external_clock[idx];
304 // PLOG(("MC6840 #%s: %d external clock freq %f \n", tag(), idx, clock));
307 // Determine the number of clock periods before we expire
308 int count = m_counter[idx];
309 if (m_control_reg[idx] & 0x04)
311 count = ((count >> 8) + 1) * ((count & 0xff) + 1);
320 if ((m_mode[idx] == 4) || (m_mode[idx] == 6))
326 m_out0_cb((offs_t)0, m_output[0]);
329 m_out1_cb((offs_t)0, m_output[1]);
332 m_out2_cb((offs_t)0, m_output[2]);
339 // PLOG(("MC6840 #%s: reload_count(%d): clock = %f count = %d\n", tag(), idx, clock, count));
341 attotime duration = from_hz(clock) * count;
344 duration *= m_t3_divisor;
347 // PLOG(("MC6840 #%s: reload_count(%d): output = %f\n", tag(), idx, duration.as_double()));
349 if (m_timer[idx] != -1)
351 cancel_event(this, m_timer[idx]);
353 register_event(this, idx, duration, false, &m_timer[idx]);
359 //-------------------------------------------------
361 //-------------------------------------------------
363 uint32_t MC6840::read_io8(uint32_t offset)
377 case PTM_6840_STATUS:
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;
385 case PTM_6840_MSBBUF1:
386 case PTM_6840_MSBBUF2:
387 case PTM_6840_MSBBUF3:
389 int idx = (offset - 2) / 2;
390 int result = compute_counter(idx);
392 // Clear the interrupt if the status has been read
393 if (m_status_read_since_int & (1 << idx))
395 m_status_reg &= ~(1 << idx);
399 m_lsb_buffer = result & 0xff;
401 // PLOG(("%s: MC6840 #%s: Counter %d read = %04X\n", machine().describe_context(), tag(), idx, result >> 8));
424 //-------------------------------------------------
425 // write - Write Timer
426 //-------------------------------------------------
428 void MC6840::write_io8(uint32_t offset, uint32_t data)
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;
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));
448 if (!(m_control_reg[idx] & 0x80 ))
454 m_out0_cb((offs_t)0, 0);
457 m_out1_cb((offs_t)0, 0);
460 m_out2_cb((offs_t)0, 0);
465 if (idx == 0 && (diffs & 0x01))
467 // Holding reset down
470 // PLOG(("MC6840 #%s : Timer reset\n", tag()));
471 for (int i = 0; i < 3; i++)
473 if (m_timer[i] != -1)
475 cancel_event(this, m_timer[i]);
484 for (int i = 0; i < 3; i++)
493 // Changing the clock source? (e.g. Zwackery)
502 case PTM_6840_MSBBUF1:
503 case PTM_6840_MSBBUF2:
504 case PTM_6840_MSBBUF3:
506 // PLOG(("MC6840 #%s msbbuf%d = %02X\n", tag(), offset / 2, data));
515 int idx = (offset - 3) / 2;
516 m_latch[idx] = (m_msb_buffer << 8) | (data & 0xff);
518 // Clear the interrupt
519 m_status_reg &= ~(1 << idx);
522 // Reload the count if in an appropriate mode
523 if (!(m_control_reg[idx] & 0x10))
528 // PLOG(("%s:MC6840 #%s: Counter %d latch = %04X\n", machine().describe_context(), tag(), idx, m_latch[idx]));
534 //-------------------------------------------------
535 // timeout - Called if timer is mature
536 //-------------------------------------------------
538 void MC6840::timeout(int idx)
540 // PLOG(("**ptm6840 %s t%d timeout**\n", tag(), idx));
542 // Set the interrupt flag
543 m_status_reg |= (1 << idx);
544 m_status_read_since_int &= ~(1 << idx);
547 if ( m_control_reg[idx] & 0x80 )
549 if ((m_mode[idx] == 0)||(m_mode[idx] == 2))
551 m_output[idx] = m_output[idx] ? 0 : 1;
552 // PLOG(("**ptm6840 %s t%d output %d **\n", tag(), idx, m_output[idx]));
557 m_out0_cb((offs_t)0, m_output[0]);
560 m_out1_cb((offs_t)0, m_output[1]);
563 m_out2_cb((offs_t)0, m_output[2]);
567 if ((m_mode[idx] == 4)||(m_mode[idx] == 6))
572 // PLOG(("**ptm6840 %s t%d output %d **\n", tag(), idx, m_output[idx]));
577 m_out0_cb((offs_t)0, m_output[0]);
580 m_out1_cb((offs_t)0, m_output[1]);
583 m_out2_cb((offs_t)0, m_output[2]);
587 // No changes in output until reinit
590 m_status_reg |= (1 << idx);
591 m_status_read_since_int &= ~(1 << idx);
600 //-------------------------------------------------
601 // set_gate - set gate status (0 or 1)
602 //-------------------------------------------------
604 void MC6840::set_gate(int idx, int state)
606 if ((m_mode[idx] & 1) == 0)
608 if (state == 0 && m_gate[idx])
616 //-------------------------------------------------
617 // set_clock - set clock status (0 or 1)
618 //-------------------------------------------------
620 void MC6840::set_clock(int idx, int state)
623 if (!(m_control_reg[idx] & 0x02))
625 if (state && m_clk[idx] == 0)
633 void MC6840::event_callback(int id, int err)
639 void MC6840::write_signal(int id, uint32_t data, uint32_t mask)
643 case SIG_MC6840_CLOCK_0:
644 set_clock(0, (data & mask) ? 1 : 0);
646 case SIG_MC6840_CLOCK_1:
647 set_clock(1, (data & mask) ? 1 : 0);
649 case SIG_MC6840_CLOCK_2:
650 set_clock(2, (data & mask) ? 1 : 0);
652 case SIG_MC6840_GATE_0:
653 set_gate(0, (data & mask) ? 1 : 0);
655 case SIG_MC6840_GATE_1:
656 set_gate(1, (data & mask) ? 1 : 0);
658 case SIG_MC6840_GATE_2:
659 set_gate(2, (data & mask) ? 1 : 0);
664 #define STATE_VERSION 2
666 bool MC6840::process_state(FILEIO* state_fio, bool loading)
668 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
671 if(!state_fio->StateCheckInt32(this_device_id)) {
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);