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()
71 for (int i = 0; i < 3; i++)
73 // if ( m_external_clock[i] == 0 )
75 // m_external_clock[i] = 1;
77 m_gate[i] = m_clk[i] = 0;
81 //-------------------------------------------------
82 // device_reset - device-specific reset
83 //-------------------------------------------------
92 m_status_read_since_int = 0;
95 for (int i = 0; i < 3; i++)
97 m_counter[i] = 0xffff;
107 //-------------------------------------------------
108 // subtract_from_counter - Subtract from Counter
109 //-------------------------------------------------
111 void MC6840::subtract_from_counter(int counter, int count)
115 // Determine the clock frequency for this timer
116 if (m_control_reg[counter] & 0x02)
118 clock = m_internal_clock;
122 clock = m_external_clock[counter];
126 if (m_control_reg[counter] & 0x04)
128 int lsb = m_counter[counter] & 0xff;
129 int msb = m_counter[counter] >> 8;
134 // Loop while we're less than zero
137 // Borrow from the MSB
138 lsb += (m_latch[counter] & 0xff) + 1;
141 // If MSB goes less than zero, we've expired
145 msb = (m_latch[counter] >> 8) + 1;
150 m_counter[counter] = (msb << 8) | lsb;
156 int word = m_counter[counter];
161 // loop while we're less than zero
164 // Borrow from the MSB
165 word += m_latch[counter] + 1;
172 m_counter[counter] = word;
175 if (clock && m_enabled[counter])
177 attotime duration = from_hz(clock) * m_counter[counter];
181 duration *= m_t3_divisor;
184 if (m_timer[counter] != -1)
186 cancel_event(this, m_timer[counter]);
188 register_event(this, counter, duration, false, &m_timer[counter]);
192 //-------------------------------------------------
194 //-------------------------------------------------
196 void MC6840::tick(int counter, int count)
200 m_t3_scaler += count;
202 if ( m_t3_scaler > m_t3_divisor - 1)
204 subtract_from_counter(counter, 1);
210 subtract_from_counter(counter, count);
214 //-------------------------------------------------
215 // update_interrupts - Update Internal Interrupts
216 //-------------------------------------------------
218 void MC6840::update_interrupts()
220 int new_state = ((m_status_reg & 0x01) && (m_control_reg[0] & 0x40)) ||
221 ((m_status_reg & 0x02) && (m_control_reg[1] & 0x40)) ||
222 ((m_status_reg & 0x04) && (m_control_reg[2] & 0x40));
224 if (new_state != m_IRQ)
230 m_status_reg |= 0x80;
234 m_status_reg &= ~0x80;
241 //-------------------------------------------------
242 // compute_counter - Compute Counter
243 //-------------------------------------------------
245 UINT16 MC6840::compute_counter( int counter )
249 // determine the clock frequency for this timer
250 if (m_control_reg[counter] & 0x02)
252 clock = m_internal_clock;
253 // PLOG(("MC6840 #%s: %d internal clock freq %f \n", tag(), counter, clock));
257 clock = m_external_clock[counter];
258 // PLOG(("MC6840 #%s: %d external clock freq %f \n", tag(), counter, clock));
261 // If there's no timer, return the count
262 if (!(clock && m_enabled[counter]))
264 // PLOG(("MC6840 #%s: read counter(%d): %d\n", tag(), counter, m_counter[counter]));
265 return m_counter[counter];
268 // See how many are left
269 int remaining = (int)(get_event_remaining_usec(m_timer[counter]) / 1000000.0 * clock);
271 // Adjust the count for dual byte mode
272 if (m_control_reg[counter] & 0x04)
274 int divisor = (m_counter[counter] & 0xff) + 1;
275 int msb = remaining / divisor;
276 int lsb = remaining % divisor;
277 remaining = (msb << 8) | lsb;
279 // PLOG(("MC6840 #%s: read counter(%d): %d\n", tag(), counter, remaining));
283 //-------------------------------------------------
284 // reload_count - Reload Counter
285 //-------------------------------------------------
287 void MC6840::reload_count(int idx)
291 // Copy the latched value in
292 m_counter[idx] = m_latch[idx];
294 // Determine the clock frequency for this timer
295 if (m_control_reg[idx] & 0x02)
297 clock = m_internal_clock;
298 // PLOG(("MC6840 #%s: %d internal clock freq %f \n", tag(), idx, clock));
302 clock = m_external_clock[idx];
303 // PLOG(("MC6840 #%s: %d external clock freq %f \n", tag(), idx, clock));
306 // Determine the number of clock periods before we expire
307 int count = m_counter[idx];
308 if (m_control_reg[idx] & 0x04)
310 count = ((count >> 8) + 1) * ((count & 0xff) + 1);
319 if ((m_mode[idx] == 4) || (m_mode[idx] == 6))
325 m_out0_cb((offs_t)0, m_output[0]);
328 m_out1_cb((offs_t)0, m_output[1]);
331 m_out2_cb((offs_t)0, m_output[2]);
338 // PLOG(("MC6840 #%s: reload_count(%d): clock = %f count = %d\n", tag(), idx, clock, count));
340 attotime duration = from_hz(clock) * count;
343 duration *= m_t3_divisor;
346 // PLOG(("MC6840 #%s: reload_count(%d): output = %f\n", tag(), idx, duration.as_double()));
348 if (m_timer[idx] != -1)
350 cancel_event(this, m_timer[idx]);
352 register_event(this, idx, duration, false, &m_timer[idx]);
358 //-------------------------------------------------
360 //-------------------------------------------------
362 uint32_t MC6840::read_io8(uint32_t offset)
366 switch ( offset & 7 )
374 case PTM_6840_STATUS:
376 // PLOG(("%s: MC6840 #%s: Status read = %04X\n", machine().describe_context(), tag(), m_status_reg));
377 m_status_read_since_int |= m_status_reg & 0x07;
382 case PTM_6840_MSBBUF1:
383 case PTM_6840_MSBBUF2:
384 case PTM_6840_MSBBUF3:
386 int idx = (offset - 2) / 2;
387 int result = compute_counter(idx);
389 // Clear the interrupt if the status has been read
390 if (m_status_read_since_int & (1 << idx))
392 m_status_reg &= ~(1 << idx);
396 m_lsb_buffer = result & 0xff;
398 // PLOG(("%s: MC6840 #%s: Counter %d read = %04X\n", machine().describe_context(), tag(), idx, result >> 8));
421 //-------------------------------------------------
422 // write - Write Timer
423 //-------------------------------------------------
425 void MC6840::write_io8(uint32_t offset, uint32_t data)
427 switch ( offset & 7 )
432 int idx = (offset == 1) ? 1 : (m_control_reg[1] & 0x01) ? 0 : 2;
433 UINT8 diffs = data ^ m_control_reg[idx];
434 m_t3_divisor = (m_control_reg[2] & 0x01) ? 8 : 1;
435 m_mode[idx] = (data >> 3) & 0x07;
436 m_control_reg[idx] = data;
438 // PLOG(("MC6840 #%s : Control register %d selected\n", tag(), idx));
439 // PLOG(("operation mode = %s\n", opmode[ m_mode[idx] ]));
440 // PLOG(("value = %04X\n", m_control_reg[idx]));
441 // PLOG(("t3divisor = %d\n", m_t3_divisor));
443 if (!(m_control_reg[idx] & 0x80 ))
449 m_out0_cb((offs_t)0, 0);
452 m_out1_cb((offs_t)0, 0);
455 m_out2_cb((offs_t)0, 0);
460 if (idx == 0 && (diffs & 0x01))
462 // Holding reset down
465 // PLOG(("MC6840 #%s : Timer reset\n", tag()));
466 for (int i = 0; i < 3; i++)
468 if (m_timer[i] != -1)
470 cancel_event(this, m_timer[i]);
479 for (int i = 0; i < 3; i++)
488 // Changing the clock source? (e.g. Zwackery)
497 case PTM_6840_MSBBUF1:
498 case PTM_6840_MSBBUF2:
499 case PTM_6840_MSBBUF3:
501 // PLOG(("MC6840 #%s msbbuf%d = %02X\n", tag(), offset / 2, data));
510 int idx = (offset - 3) / 2;
511 m_latch[idx] = (m_msb_buffer << 8) | (data & 0xff);
513 // Clear the interrupt
514 m_status_reg &= ~(1 << idx);
517 // Reload the count if in an appropriate mode
518 if (!(m_control_reg[idx] & 0x10))
523 // PLOG(("%s:MC6840 #%s: Counter %d latch = %04X\n", machine().describe_context(), tag(), idx, m_latch[idx]));
529 //-------------------------------------------------
530 // timeout - Called if timer is mature
531 //-------------------------------------------------
533 void MC6840::timeout(int idx)
535 // PLOG(("**ptm6840 %s t%d timeout**\n", tag(), idx));
537 // Set the interrupt flag
538 m_status_reg |= (1 << idx);
539 m_status_read_since_int &= ~(1 << idx);
542 if ( m_control_reg[idx] & 0x80 )
544 if ((m_mode[idx] == 0)||(m_mode[idx] == 2))
546 m_output[idx] = m_output[idx] ? 0 : 1;
547 // PLOG(("**ptm6840 %s t%d output %d **\n", tag(), idx, m_output[idx]));
552 m_out0_cb((offs_t)0, m_output[0]);
555 m_out1_cb((offs_t)0, m_output[1]);
558 m_out2_cb((offs_t)0, m_output[2]);
562 if ((m_mode[idx] == 4)||(m_mode[idx] == 6))
567 // PLOG(("**ptm6840 %s t%d output %d **\n", tag(), idx, m_output[idx]));
572 m_out0_cb((offs_t)0, m_output[0]);
575 m_out1_cb((offs_t)0, m_output[1]);
578 m_out2_cb((offs_t)0, m_output[2]);
582 // No changes in output until reinit
585 m_status_reg |= (1 << idx);
586 m_status_read_since_int &= ~(1 << idx);
595 //-------------------------------------------------
596 // set_gate - set gate status (0 or 1)
597 //-------------------------------------------------
599 void MC6840::set_gate(int idx, int state)
601 if ((m_mode[idx] & 1) == 0)
603 if (state == 0 && m_gate[idx])
611 //-------------------------------------------------
612 // set_clock - set clock status (0 or 1)
613 //-------------------------------------------------
615 void MC6840::set_clock(int idx, int state)
618 if (!(m_control_reg[idx] & 0x02))
620 if (state && m_clk[idx] == 0)
628 void MC6840::event_callback(int id, int err)
634 void MC6840::write_signal(int id, uint32_t data, uint32_t mask)
638 case SIG_MC6840_CLOCK_0:
639 set_clock(0, (data & mask) ? 1 : 0);
641 case SIG_MC6840_CLOCK_1:
642 set_clock(1, (data & mask) ? 1 : 0);
644 case SIG_MC6840_CLOCK_2:
645 set_clock(2, (data & mask) ? 1 : 0);
647 case SIG_MC6840_GATE_0:
648 set_gate(0, (data & mask) ? 1 : 0);
650 case SIG_MC6840_GATE_1:
651 set_gate(1, (data & mask) ? 1 : 0);
653 case SIG_MC6840_GATE_2:
654 set_gate(2, (data & mask) ? 1 : 0);
659 #define STATE_VERSION 1
661 void MC6840::save_state(FILEIO* state_fio)
663 state_fio->FputUint32(STATE_VERSION);
664 state_fio->FputInt32(this_device_id);
666 state_fio->Fwrite(m_control_reg, sizeof(m_control_reg), 1);
667 state_fio->Fwrite(m_output, sizeof(m_output), 1);
668 state_fio->Fwrite(m_gate, sizeof(m_gate), 1);
669 state_fio->Fwrite(m_clk, sizeof(m_clk), 1);
670 state_fio->Fwrite(m_enabled, sizeof(m_enabled), 1);
671 state_fio->Fwrite(m_mode, sizeof(m_mode), 1);
672 state_fio->Fwrite(m_fired, sizeof(m_fired), 1);
673 state_fio->FputUint8(m_t3_divisor);
674 state_fio->FputUint8(m_t3_scaler);
675 state_fio->FputUint8(m_IRQ);
676 state_fio->FputUint8(m_status_reg);
677 state_fio->FputUint8(m_status_read_since_int);
678 state_fio->FputUint8(m_lsb_buffer);
679 state_fio->FputUint8(m_msb_buffer);
680 state_fio->Fwrite(m_timer, sizeof(m_timer), 1);
681 state_fio->Fwrite(m_latch, sizeof(m_latch), 1);
682 state_fio->Fwrite(m_counter, sizeof(m_counter), 1);
685 bool MC6840::load_state(FILEIO* state_fio)
687 if(state_fio->FgetUint32() != STATE_VERSION) {
690 if(state_fio->FgetInt32() != this_device_id) {
693 state_fio->Fread(m_control_reg, sizeof(m_control_reg), 1);
694 state_fio->Fread(m_output, sizeof(m_output), 1);
695 state_fio->Fread(m_gate, sizeof(m_gate), 1);
696 state_fio->Fread(m_clk, sizeof(m_clk), 1);
697 state_fio->Fread(m_enabled, sizeof(m_enabled), 1);
698 state_fio->Fread(m_mode, sizeof(m_mode), 1);
699 state_fio->Fread(m_fired, sizeof(m_fired), 1);
700 m_t3_divisor = state_fio->FgetUint8();
701 m_t3_scaler = state_fio->FgetUint8();
702 m_IRQ = state_fio->FgetUint8();
703 m_status_reg = state_fio->FgetUint8();
704 m_status_read_since_int = state_fio->FgetUint8();
705 m_lsb_buffer = state_fio->FgetUint8();
706 m_msb_buffer = state_fio->FgetUint8();
707 state_fio->Fread(m_timer, sizeof(m_timer), 1);
708 state_fio->Fread(m_latch, sizeof(m_latch), 1);
709 state_fio->Fread(m_counter, sizeof(m_counter), 1);