void i8155_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { if (m_count_extra) { m_count_extra = false; return; } // count down by twos m_counter -= 2; if (m_counter == 1) { LOGMASKED(LOG_TIMER, "Timer count half finished\n"); // reload the even half of the count m_counter = m_count_loaded & 0x3ffe; // square wave modes produce a low output in the second half of the counting period if ((get_timer_mode() & TIMER_MODE_TC_PULSE) == 0) timer_output(0); } else if (m_counter == 2) { if ((get_timer_mode() & TIMER_MODE_TC_PULSE) != 0) { // pulse low on TC being reached timer_output(0); } // set timer flag m_status |= STATUS_TIMER; } else if (m_counter == 0) { timer_output(1); if ((get_timer_mode() & TIMER_MODE_AUTO_RELOAD) == 0 || (m_command & COMMAND_TM_MASK) == COMMAND_TM_STOP_AFTER_TC) { // stop timer timer_stop_count(); LOGMASKED(LOG_TIMER, "Timer stopped\n"); } else { // automatically reload the counter timer_reload_count(); } } }
inline void i8155_device::timer_stop_count() { // stop counting m_timer->enable(0); // clear timer output timer_output(1); }
void i8155_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { // count down m_counter--; if (get_timer_mode() == TIMER_MODE_LOW) { // pulse on every count pulse_timer_output(); } if (m_counter == 0) { if (LOG) logerror("8155 '%s' Timer Count Reached\n", tag()); switch (m_command & COMMAND_TM_MASK) { case COMMAND_TM_STOP_AFTER_TC: // stop timer m_timer->enable(0); if (LOG) logerror("8155 '%s' Timer Stopped\n", tag()); break; } switch (get_timer_mode()) { case TIMER_MODE_SQUARE_WAVE: // toggle timer output m_to = !m_to; timer_output(); break; case TIMER_MODE_SINGLE_PULSE: // single pulse upon TC being reached pulse_timer_output(); // clear timer mode setting m_command &= ~COMMAND_TM_MASK; break; case TIMER_MODE_AUTOMATIC_RELOAD: // automatic reload, i.e. single pulse every time TC is reached pulse_timer_output(); break; } // set timer flag m_status |= STATUS_TIMER; // reload timer counter m_counter = m_count_length & 0x3fff; } }
void bitbanger_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { switch(id) { case TIMER_OUTPUT: timer_output(); break; case TIMER_INPUT: timer_input(); break; } }
inline void i8155_device::timer_reload_count() { m_count_loaded = m_count_length; // valid counts range from 2 to 3FFF if ((m_count_length & 0x3fff) < 2) { timer_stop_count(); return; } // begin the odd half of the count, with one extra cycle if count is odd m_counter = (m_count_loaded & 0x3ffe) | 1; m_count_extra = BIT(m_count_loaded, 0); // set up our timer m_timer->adjust(attotime::zero, 0, clocks_to_attotime(1)); timer_output(1); switch (get_timer_mode()) { case 0: // puts out LOW during second half of count LOGMASKED(LOG_TIMER, "Timer loaded with %d (Mode: LOW)\n", m_count_loaded & 0x3fff); break; case TIMER_MODE_AUTO_RELOAD: // square wave, i.e. the period of the square wave equals the count length programmed with automatic reload at terminal count LOGMASKED(LOG_TIMER, "Timer loaded with %d (Mode: Square wave)\n", m_count_loaded & 0x3fff); break; case TIMER_MODE_TC_PULSE: // single pulse upon TC being reached LOGMASKED(LOG_TIMER, "Timer loaded with %d (Mode: Single pulse)\n", m_count_loaded & 0x3fff); break; case TIMER_MODE_TC_PULSE | TIMER_MODE_AUTO_RELOAD: // automatic reload, i.e. single pulse every time TC is reached LOGMASKED(LOG_TIMER, "Timer loaded with %d (Mode: Automatic reload)\n", m_count_loaded & 0x3fff); break; } }
void i8155_device::device_reset() { // clear output registers m_output[PORT_A] = 0; m_output[PORT_B] = 0; m_output[PORT_C] = 0; // set ports to input mode register_w(REGISTER_COMMAND, m_command & ~(COMMAND_PA | COMMAND_PB | COMMAND_PC_MASK)); // clear timer flag m_status &= ~STATUS_TIMER; // stop counting m_timer->enable(0); // clear timer output m_to = 1; timer_output(); }
inline void i8155_device::pulse_timer_output() { m_to = 0; timer_output(); m_to = 1; timer_output(); }
void i8155_device::register_w(int offset, UINT8 data) { switch (offset & 0x07) { case REGISTER_COMMAND: m_command = data; if (LOG) logerror("8155 '%s' Port A Mode: %s\n", tag(), (data & COMMAND_PA) ? "output" : "input"); if (LOG) logerror("8155 '%s' Port B Mode: %s\n", tag(), (data & COMMAND_PB) ? "output" : "input"); if (LOG) logerror("8155 '%s' Port A Interrupt: %s\n", tag(), (data & COMMAND_IEA) ? "enabled" : "disabled"); if (LOG) logerror("8155 '%s' Port B Interrupt: %s\n", tag(), (data & COMMAND_IEB) ? "enabled" : "disabled"); switch (data & COMMAND_PC_MASK) { case COMMAND_PC_ALT_1: if (LOG) logerror("8155 '%s' Port C Mode: Alt 1\n", tag()); break; case COMMAND_PC_ALT_2: if (LOG) logerror("8155 '%s' Port C Mode: Alt 2\n", tag()); break; case COMMAND_PC_ALT_3: if (LOG) logerror("8155 '%s' Port C Mode: Alt 3\n", tag()); break; case COMMAND_PC_ALT_4: if (LOG) logerror("8155 '%s' Port C Mode: Alt 4\n", tag()); break; } switch (data & COMMAND_TM_MASK) { case COMMAND_TM_NOP: // do not affect counter operation break; case COMMAND_TM_STOP: // NOP if timer has not started, stop counting if the timer is running if (LOG) logerror("8155 '%s' Timer Command: Stop\n", tag()); m_to = 1; timer_output(); m_timer->enable(0); break; case COMMAND_TM_STOP_AFTER_TC: // stop immediately after present TC is reached (NOP if timer has not started) if (LOG) logerror("8155 '%s' Timer Command: Stop after TC\n", tag()); break; case COMMAND_TM_START: if (LOG) logerror("8155 '%s' Timer Command: Start\n", tag()); if (m_timer->enabled()) { // if timer is running, start the new mode and CNT length immediately after present TC is reached } else { // load mode and CNT length and start immediately after loading (if timer is not running) m_counter = m_count_length & 0x3fff; m_timer->adjust(attotime::zero, 0, attotime::from_hz(clock())); } break; } break; case REGISTER_PORT_A: write_port(PORT_A, data); break; case REGISTER_PORT_B: write_port(PORT_B, data); break; case REGISTER_PORT_C: write_port(PORT_C, data & 0x3f); break; case REGISTER_TIMER_LOW: m_count_length = (m_count_length & 0xff00) | data; if (LOG) logerror("8155 '%s' Count Length Low: %04x\n", tag(), m_count_length); break; case REGISTER_TIMER_HIGH: m_count_length = (data << 8) | (m_count_length & 0xff); if (LOG) logerror("8155 '%s' Count Length High: %04x\n", tag(), m_count_length); switch (data & TIMER_MODE_MASK) { case TIMER_MODE_LOW: // puts out LOW during second half of count if (LOG) logerror("8155 '%s' Timer Mode: LOW\n", tag()); break; case TIMER_MODE_SQUARE_WAVE: // square wave, i.e. the period of the square wave equals the count length programmed with automatic reload at terminal count if (LOG) logerror("8155 '%s' Timer Mode: Square wave\n", tag()); break; case TIMER_MODE_SINGLE_PULSE: // single pulse upon TC being reached if (LOG) logerror("8155 '%s' Timer Mode: Single pulse\n", tag()); break; case TIMER_MODE_AUTOMATIC_RELOAD: // automatic reload, i.e. single pulse every time TC is reached if (LOG) logerror("8155 '%s' Timer Mode: Automatic reload\n", tag()); break; } break; } }