// license:BSD-3-Clause // copyright-holders:Wilbert Pol /********************************************************************** Fairchild F3853 SRAM interface with integrated interrupt controller and timer (SMI) This chip is a timer shift register, basically the same as in the F3851. Based on a datasheet obtained from www.freetradezone.com 8-bit shift register: Feedback in0 = !((out3 ^ out4) ^ (out5 ^ out7)) Interrupts are at 0xfe 0xff stops the register (0xfe is never reached) **********************************************************************/ #include "emu.h" #include "f3853.h" /*************************************************************************** IMPLEMENTATION ***************************************************************************/ //************************************************************************** // LIVE DEVICE //************************************************************************** // device type definition DEFINE_DEVICE_TYPE(F3853, f3853_device, "f3853_device", "F3853 SMI") //------------------------------------------------- // f3853_device - constructor //------------------------------------------------- f3853_device::f3853_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, F3853, tag, owner, clock) , m_int_req_callback(*this) , m_pri_out_callback(*this) , m_priority_line(false) , m_external_interrupt_line(true) { } void f3853_device::device_resolve_objects() { m_int_req_callback.resolve_safe(); m_pri_out_callback.resolve_safe(); // TODO: not implemented m_int_daisy_chain_callback.bind_relative_to(*owner()); } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void f3853_device::device_start() { uint8_t reg = 0xfe; // Known to get 0xfe after 255 cycles for(int i = reg; i >= 0; i--) { m_value_to_cycle[reg] = i; reg = reg << 1 | (BIT(reg,7) ^ BIT(reg,5) ^ BIT(reg,4) ^ BIT(reg,3) ^ 1); } m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(f3853_device::timer_callback),this)); save_item(NAME(m_int_vector)); save_item(NAME(m_external_enable)); save_item(NAME(m_timer_enable)); save_item(NAME(m_request_flipflop)); save_item(NAME(m_priority_line)); save_item(NAME(m_external_interrupt_line)); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void f3853_device::device_reset() { m_int_vector = 0; m_external_enable = false; m_timer_enable = false; m_request_flipflop = false; m_external_interrupt_line = true; set_interrupt_request_line(); m_timer->enable(false); } void f3853_device::set_interrupt_request_line() { m_int_req_callback(m_request_flipflop && !m_priority_line ? ASSERT_LINE : CLEAR_LINE); } IRQ_CALLBACK_MEMBER(f3853_device::int_acknowledge) { if (m_external_enable && !m_priority_line && m_request_flipflop) { m_request_flipflop = false; set_interrupt_request_line(); return external_interrupt_vector(); } else if (m_timer_enable && !m_priority_line && m_request_flipflop) { m_request_flipflop = false; set_interrupt_request_line(); return timer_interrupt_vector(); } else if (!m_int_daisy_chain_callback.isnull()) return m_int_daisy_chain_callback(device, irqline); else { // should never happen logerror("%s: Spurious interrupt!\n", machine().describe_context()); return 0; } } void f3853_device::timer_start(uint8_t value) { attotime period = (value != 0xff) ? attotime::from_hz(clock()) * (m_value_to_cycle[value]*31) : attotime::never; m_timer->adjust(period); } TIMER_CALLBACK_MEMBER(f3853_device::timer_callback) { if(m_timer_enable) { m_request_flipflop = true; set_interrupt_request_line(); } timer_start(0xfe); } WRITE_LINE_MEMBER(f3853_device::ext_int_w) { if(m_external_interrupt_line && !state && m_external_enable) { m_request_flipflop = true; } m_external_interrupt_line = bool(state); set_interrupt_request_line(); } WRITE_LINE_MEMBER(f3853_device::pri_in_w) { m_priority_line = bool(state); set_interrupt_request_line(); } READ8_MEMBER(f3853_device::read) { uint8_t data = 0; switch (offset) { case 0: data = m_int_vector >> 8; break; case 1: data = m_int_vector & 0xff; break; case 2: // Interrupt control; not readable case 3: // Timer; not readable break; } return data; } WRITE8_MEMBER(f3853_device::write) { switch(offset) { case 0: m_int_vector = (data << 8) | (m_int_vector & 0x00ff); break; case 1: m_int_vector = data | (m_int_vector & 0xff00); break; case 2: //interrupt control m_external_enable = ((data & 3) == 1); m_timer_enable = ((data & 3) == 3); set_interrupt_request_line(); break; case 3: //timer m_request_flipflop = false; set_interrupt_request_line(); timer_start(data); break; } }