summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/tlcs900/tmp94c241.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/tlcs900/tmp94c241.cpp')
-rw-r--r--src/devices/cpu/tlcs900/tmp94c241.cpp1332
1 files changed, 1332 insertions, 0 deletions
diff --git a/src/devices/cpu/tlcs900/tmp94c241.cpp b/src/devices/cpu/tlcs900/tmp94c241.cpp
new file mode 100644
index 00000000000..e0bfc8dd07b
--- /dev/null
+++ b/src/devices/cpu/tlcs900/tmp94c241.cpp
@@ -0,0 +1,1332 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR,Felipe Sanches
+/****************************************************************************
+
+ Toshiba TMP94C241 microcontroller
+
+****************************************************************************/
+
+#include "emu.h"
+#include "tmp94c241.h"
+#include "dasm900.h"
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(TMP94C241, tmp94c241_device, "tmp94c241", "Toshiba TMP94C241")
+
+enum
+{
+ INTE45,
+ INTE67,
+ INTE89,
+ INTEAB,
+ INTET01,
+ INTET23,
+ INTET45,
+ INTET67,
+ INTET89,
+ INTETAB,
+ INTES0,
+ INTES1,
+ INTETC01,
+ INTETC23,
+ INTETC45,
+ INTETC67,
+ INTE0AD,
+ INTNMWDT
+};
+
+static const struct {
+ uint8_t reg;
+ uint8_t iff;
+ uint8_t vector;
+ uint8_t dma_start_vector;
+} tmp94c241_irq_vector_map[] =
+{
+ { INTE0AD, 0x08, 0x28, 0x0a}, // INT0 Pin
+ { INTE45, 0x08, 0x2c, 0x0b}, // INT4 Pin
+ { INTE45, 0x80, 0x30, 0x0c}, // INT5 Pin
+ { INTE67, 0x08, 0x34, 0x0d}, // INT6 Pin
+ { INTE67, 0x80, 0x38, 0x0e}, // INT7 Pin
+ // 0x3c - reserved
+ { INTE89, 0x08, 0x40, 0x10}, // INT8 Pin
+ { INTE89, 0x80, 0x44, 0x11}, // INT9 Pin
+ { INTEAB, 0x08, 0x48, 0x12}, // INTA Pin
+ { INTEAB, 0x80, 0x4c, 0x13}, // INTB Pin
+ { INTET01, 0x08, 0x50, 0x14}, // INTT0: 8-bit timer (Timer 0)
+ { INTET01, 0x80, 0x54, 0x15}, // INTT1: 8-bit timer (Timer 1)
+ { INTET23, 0x08, 0x58, 0x16}, // INTT2: 8-bit timer (Timer 2)
+ { INTET23, 0x80, 0x5c, 0x17}, // INTT3: 8-bit timer (Timer 3)
+ { INTET45, 0x08, 0x60, 0x18}, // INTTR4: 16-bit timer (Treg 4)
+ { INTET45, 0x80, 0x64, 0x19}, // INTTR5: 16-bit timer (Treg 5)
+ { INTET67, 0x08, 0x68, 0x1a}, // INTTR6: 16-bit timer (Treg 6)
+ { INTET67, 0x80, 0x6c, 0x1b}, // INTTR7: 16-bit timer (Treg 7)
+ { INTET89, 0x08, 0x70, 0x1c}, // INTTR8: 16-bit timer (Treg 8)
+ { INTET89, 0x80, 0x74, 0x1d}, // INTTR9: 16-bit timer (Treg 9)
+ { INTETAB, 0x08, 0x78, 0x1e}, // INTTRA: 16-bit timer (Treg A)
+ { INTETAB, 0x80, 0x7c, 0x1f}, // INTTRB: 16-bit timer (Treg B)
+ { INTES0, 0x08, 0x80, 0x20}, // INTRX0: Serial receive 0
+ { INTES0, 0x80, 0x84, 0x21}, // INTTX0: Serial send 0
+ { INTES1, 0x08, 0x88, 0x22}, // INTRX1: Serial receive 1
+ { INTES1, 0x80, 0x8c, 0x23}, // INTTX1: Serial send 1
+ { INTE0AD, 0x80, 0x90, 0x24}, // INTAD: AD conversion completion
+ { INTETC01, 0x08, 0x94, 0x25}, // INTTC0: micro-DMA completion Ch.0
+ { INTETC01, 0x80, 0x98, 0x26}, // INTTC1: micro-DMA completion Ch.1
+ { INTETC23, 0x08, 0x9c, 0x27}, // INTTC2: micro-DMA completion Ch.2
+ { INTETC23, 0x80, 0xa0, 0x28}, // INTTC3: micro-DMA completion Ch.3
+ { INTETC45, 0x08, 0xa4, 0x29}, // INTTC4: micro-DMA completion Ch.4
+ { INTETC45, 0x80, 0xa8, 0x2a}, // INTTC5: micro-DMA completion Ch.5
+ { INTETC67, 0x08, 0xac, 0x2b}, // INTTC6: micro-DMA completion Ch.6
+ { INTETC67, 0x80, 0xb0, 0x2c}, // INTTC7: micro-DMA completion Ch.7
+ /* 0xb4 ... 0xfc (Reserved) */
+};
+static constexpr u8 NUM_MASKABLE_IRQS = sizeof(tmp94c241_irq_vector_map) / 4;
+
+
+//**************************************************************************
+// DEVICE CONSTRUCTION AND INITIALIZATION
+//**************************************************************************
+
+//-------------------------------------------------
+// tmp94c241_device - constructor
+//-------------------------------------------------
+
+tmp94c241_device::tmp94c241_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ tlcs900h_device(mconfig, TMP94C241, tag, owner, clock),
+ m_an_read(*this, 0),
+ m_port_read(*this, 0),
+ m_port_write(*this),
+ m_port_latch{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ m_port_control{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ m_port_function{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ m_timer_flipflops{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ m_t8run(0),
+ m_t01mod(0),
+ m_t23mod(0),
+ m_t4mod(0),
+ m_t6mod(0),
+ m_t8mod(0),
+ m_tamod(0),
+ m_tffcr(0),
+ m_t4ffcr(0),
+ m_t6ffcr(0),
+ m_t8ffcr(0),
+ m_taffcr(0),
+ m_trdc(0),
+ m_t16run(0),
+ m_treg_8{ 0, 0, 0, 0 },
+ m_treg_16{ 0, 0, 0, 0, 0, 0, 0, 0 },
+ m_t16_cap{ 0, 0, 0, 0, 0, 0, 0, 0 },
+ m_timer_16{ 0, 0, 0, 0 },
+ m_watchdog_mode(0),
+ m_serial_control{ 0, 0 },
+ m_serial_mode{ 0, 0 },
+ m_baud_rate{ 0, 0 },
+ m_od_enable(0),
+ m_ad_mode1(0),
+ m_ad_mode2(0),
+ m_ad_result{ 0, 0, 0, 0 },
+ m_int_reg{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ m_iimc(0),
+ m_dma_vector{ 0, 0, 0, 0 },
+ m_block_cs{ 0, 0, 0, 0 },
+ m_external_cs(0),
+ m_msar{ 0, 0, 0, 0, 0, 0 },
+ m_mamr{ 0, 0, 0, 0, 0, 0 },
+ m_dram_refresh{ 0, 0 },
+ m_dram_access{ 0, 0 },
+ m_da_drive(0)
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - device-specific startup
+//-------------------------------------------------
+
+void tmp94c241_device::device_config_complete()
+{
+ if (m_am8_16 == 0)
+ m_program_config = address_space_config("program", ENDIANNESS_LITTLE, 16, 24, 0, address_map_constructor(FUNC(tmp94c241_device::internal_mem), this));
+ else
+ m_program_config = address_space_config("program", ENDIANNESS_LITTLE, 8, 24, 0, address_map_constructor(FUNC(tmp94c241_device::internal_mem), this));
+}
+
+
+void tmp94c241_device::device_resolve_objects()
+{
+ m_nmi_state = CLEAR_LINE;
+ for (int i = 0; i < TLCS900_NUM_INPUTS; i++)
+ {
+ m_level[i] = CLEAR_LINE;
+ }
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void tmp94c241_device::device_start()
+{
+ tlcs900h_device::device_start();
+
+ save_item(NAME(m_port_latch));
+ save_item(NAME(m_port_control));
+ save_item(NAME(m_port_function));
+ save_item(NAME(m_timer_flipflops));
+ save_item(NAME(m_t8run));
+ save_item(NAME(m_t01mod));
+ save_item(NAME(m_t23mod));
+ save_item(NAME(m_t4mod));
+ save_item(NAME(m_t6mod));
+ save_item(NAME(m_t8mod));
+ save_item(NAME(m_tamod));
+ save_item(NAME(m_trdc));
+ save_item(NAME(m_treg_8));
+ save_item(NAME(m_treg_16));
+ save_item(NAME(m_t16_cap));
+ save_item(NAME(m_tffcr));
+ save_item(NAME(m_t4ffcr));
+ save_item(NAME(m_t6ffcr));
+ save_item(NAME(m_t8ffcr));
+ save_item(NAME(m_taffcr));
+ save_item(NAME(m_t16run));
+ save_item(NAME(m_watchdog_mode));
+ save_item(NAME(m_serial_control));
+ save_item(NAME(m_serial_mode));
+ save_item(NAME(m_baud_rate));
+ save_item(NAME(m_od_enable));
+ save_item(NAME(m_ad_mode1));
+ save_item(NAME(m_ad_mode2));
+ save_item(NAME(m_ad_result));
+ save_item(NAME(m_int_reg));
+ save_item(NAME(m_iimc));
+ save_item(NAME(m_dma_vector));
+ save_item(NAME(m_block_cs));
+ save_item(NAME(m_external_cs));
+ save_item(NAME(m_msar));
+ save_item(NAME(m_mamr));
+ save_item(NAME(m_dram_refresh));
+ save_item(NAME(m_dram_access));
+ save_item(NAME(m_da_drive));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void tmp94c241_device::device_reset()
+{
+ tlcs900h_device::device_reset();
+
+ m_ad_cycles_left = 0;
+ m_timer_pre = 0;
+
+ m_port_latch[PORT_0] = 0x00;
+ m_port_latch[PORT_1] = 0x00;
+ m_port_latch[PORT_2] = 0x00;
+ m_port_latch[PORT_3] = 0x00;
+ m_port_latch[PORT_4] = 0x00;
+ m_port_latch[PORT_5] = 0x00;
+ m_port_latch[PORT_6] = 0x00;
+ m_port_latch[PORT_7] = 0x7f;
+ m_port_latch[PORT_8] = 0x3b;
+ m_port_latch[PORT_A] = 0x1f;
+ m_port_latch[PORT_B] = 0x1f;
+ m_port_latch[PORT_C] = 0x00;
+ m_port_latch[PORT_D] = 0x00;
+ m_port_latch[PORT_E] = 0x00;
+ m_port_latch[PORT_F] = 0x00;
+ m_port_latch[PORT_H] = 0x00;
+ m_port_latch[PORT_Z] = 0x00;
+
+ m_port_function[PORT_0] = 0x01;
+ m_port_function[PORT_1] = 0x01;
+ m_port_function[PORT_2] = 0x01;
+ m_port_function[PORT_3] = 0x01;
+ m_port_function[PORT_4] = 0xff;
+ m_port_function[PORT_5] = 0xff;
+ m_port_function[PORT_6] = 0xff;
+ m_port_function[PORT_7] = 0x01;
+ m_port_function[PORT_8] = 0x00;
+ m_port_function[PORT_A] = 0x00;
+ m_port_function[PORT_B] = 0x00;
+ m_port_function[PORT_C] = 0x00;
+ m_port_function[PORT_D] = 0x00;
+ m_port_function[PORT_E] = 0x00;
+ m_port_function[PORT_F] = 0x00;
+ m_port_function[PORT_H] = 0x00;
+ m_port_function[PORT_Z] = 0x00;
+
+ std::fill_n(&m_port_control[0], NUM_PORTS, 0x00);
+ std::fill_n(&m_timer_flipflops[0], 12, 0x00);
+ m_t8run = 0x00;
+ m_trdc = 0x00;
+ m_t01mod = 0x00;
+ m_t23mod = 0x00;
+ m_t4mod = 0x00;
+ m_t6mod = 0x00;
+ m_t8mod = 0x00;
+ m_tamod = 0x00;
+ m_tffcr = 0x00;
+ m_t4ffcr = 0x00;
+ m_t6ffcr = 0x00;
+ m_t8ffcr = 0x00;
+ m_taffcr = 0x00;
+ std::fill_n(&m_timer_change[0], 8, 0x00);
+ std::fill_n(&m_timer_8[0], 4, 0x00);
+ std::fill_n(&m_timer_16[0], 4, 0x00);
+ m_watchdog_mode = 0x80;
+ for (int i = 0; i < 2; i++)
+ {
+ m_serial_control[i] &= 0x80;
+ m_serial_mode[i] &= 0x80;
+ m_baud_rate[i] = 0x00;
+ }
+ m_od_enable = 0x00;
+ m_ad_mode1 = 0x00;
+ m_ad_mode2 = 0x00;
+ std::fill_n(&m_int_reg[0], 18, 0x00);
+ m_iimc = 0x00;
+ std::fill_n(&m_dma_vector[0], 4, 0x00);
+ m_block_cs[0] = 0x0000;
+ m_block_cs[1] = 0x0000;
+ m_block_cs[2] = 0x1000; //FIXME!
+ m_block_cs[3] = 0x0000;
+ m_block_cs[4] = 0x0000;
+ m_block_cs[5] = 0x0000;
+ m_external_cs = 0x0000;
+ std::fill_n(&m_msar[0], 6, 0xff);
+ std::fill_n(&m_mamr[0], 6, 0xff);
+ std::fill_n(&m_dram_refresh[0], 2, 0x00);
+ std::fill_n(&m_dram_access[0], 2, 0x80);
+ m_da_drive = 0x00;
+}
+
+uint8_t tmp94c241_device::inte_r(offs_t offset)
+{
+ return m_int_reg[offset];
+}
+
+void tmp94c241_device::inte_w(offs_t offset, uint8_t data)
+{
+ if (data & 0x80)
+ data = (data & 0x7f) | (m_int_reg[offset] & 0x80);
+ if (data & 0x08)
+ data = (data & 0xf7) | (m_int_reg[offset] & 0x08);
+
+ m_int_reg[offset] = data;
+ m_check_irqs = 1;
+}
+
+uint8_t tmp94c241_device::intnmwdt_r(offs_t offset)
+{
+ return m_int_reg[INTNMWDT];
+}
+
+void tmp94c241_device::intnmwdt_w(offs_t offset, uint8_t data)
+{
+ if (data & 0x80)
+ data = (data & 0x7f) | (m_int_reg[INTNMWDT] & 0x80);
+ if ( data & 0x08 )
+ data = (data & 0xf7) | (m_int_reg[INTNMWDT] & 0x08);
+
+ m_int_reg[INTNMWDT] = data;
+ m_check_irqs = 1;
+}
+
+void tmp94c241_device::iimc_w(uint8_t data)
+{
+ m_iimc = data;
+ m_check_irqs = 1;
+}
+
+void tmp94c241_device::intclr_w(uint8_t data)
+{
+ for (int i = 0; i < NUM_MASKABLE_IRQS; i++)
+ {
+ if (data == tmp94c241_irq_vector_map[i].dma_start_vector)
+ {
+ // clear interrupt request
+ m_int_reg[tmp94c241_irq_vector_map[i].reg] &= ~ tmp94c241_irq_vector_map[i].iff;
+ return;
+ }
+ }
+}
+
+void tmp94c241_device::dmav_w(offs_t offset, uint8_t data)
+{
+ m_dma_vector[offset] = data;
+}
+
+template <uint8_t N>
+void tmp94c241_device::bNcs_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ COMBINE_DATA(&m_block_cs[N]);
+}
+
+template <uint8_t N>
+void tmp94c241_device::mamr_w(uint8_t data)
+{
+ m_mamr[N] = data;
+}
+
+template <uint8_t N>
+void tmp94c241_device::msar_w(uint8_t data)
+{
+ m_msar[N] = data;
+}
+
+template <uint8_t N>
+uint8_t tmp94c241_device::mamr_r()
+{
+ return m_mamr[N];
+}
+
+template <uint8_t N>
+uint8_t tmp94c241_device::msar_r()
+{
+ return m_msar[N];
+}
+
+uint8_t tmp94c241_device::t8run_r()
+{
+ return m_t8run;
+}
+
+void tmp94c241_device::t8run_w(uint8_t data)
+{
+ m_t8run = data;
+ for (int i = 0; i < 4; i++)
+ {
+ // These correspond to UP_COUNTER and TIMER_CHANGE for 8-bit timers 0, 1, 2 and 3
+ if (!BIT(m_t8run, i)) // Timer isn't running
+ {
+ m_timer_8[i] = 0;
+ m_timer_change[i] = 0;
+ }
+ }
+}
+
+uint8_t tmp94c241_device::t01mod_r()
+{
+ return m_t01mod;
+}
+
+void tmp94c241_device::t01mod_w(uint8_t data)
+{
+ m_t01mod = data;
+}
+
+uint8_t tmp94c241_device::tffcr_r()
+{
+ return m_tffcr;
+}
+
+enum
+{
+ FF_INVERT,
+ FF_SET,
+ FF_CLEAR,
+ FF_DONTCARE
+};
+
+void tmp94c241_device::change_timer_flipflop(uint8_t flipflop, uint8_t operation)
+{
+ /* First we update the timer flip-flop */
+ bool &ff_state = m_timer_flipflops[flipflop];
+
+ switch (operation)
+ {
+ case FF_INVERT:
+ ff_state = !ff_state;
+ break;
+ case FF_SET:
+ ff_state = true;
+ break;
+ case FF_CLEAR:
+ ff_state = false;
+ break;
+ default:
+ // invalid operation
+ return;
+ }
+
+ /* The value of the flipflop is only exposed to a pin in certain modes of operation
+ determined by fields of the port function registers.
+
+ So here we bail out if the flipflop is not routed to its corresponding port bit:
+ */
+ switch (flipflop)
+ {
+ case 0x1:
+ if (!BIT(m_port_function[PORT_C], 0) || BIT(m_port_control[PORT_C], 0)) return;
+ break;
+ case 0x7:
+ if (!BIT(m_port_function[PORT_C], 0) || !BIT(m_port_control[PORT_C], 0)) return;
+ break;
+ case 0x3:
+ if (!BIT(m_port_function[PORT_C], 1) || BIT(m_port_control[PORT_C], 1)) return;
+ break;
+ case 0xb:
+ if (!BIT(m_port_function[PORT_C], 1) || !BIT(m_port_control[PORT_C], 1)) return;
+ break;
+ case 0x4:
+ if (!BIT(m_port_function[PORT_D], 0)) return;
+ break;
+ case 0x6:
+ if (!BIT(m_port_function[PORT_D], 4)) return;
+ break;
+ case 0x8:
+ if (!BIT(m_port_function[PORT_E], 0)) return;
+ break;
+ case 0xA:
+ if (!BIT(m_port_function[PORT_E], 4)) return;
+ break;
+ default:
+ // invalid flip flop
+ return;
+ }
+
+ // And here we actually send the value to the corresponding pin
+ uint8_t new_port_value = 0;
+ switch (flipflop)
+ {
+ case 0x1:
+ case 0x7:
+ new_port_value = m_port_latch[PORT_C] & 0xfe;
+ if (ff_state) new_port_value |= 0x01;
+ port_w<PORT_C>(new_port_value);
+ break;
+ case 0x3:
+ case 0xb:
+ new_port_value = m_port_latch[PORT_C] & 0xfd;
+ if (ff_state) new_port_value |= 0x02;
+ port_w<PORT_C>(new_port_value);
+ break;
+ case 0x4:
+ new_port_value = m_port_latch[PORT_D] & 0xfe;
+ if (ff_state) new_port_value |= 0x01;
+ port_w<PORT_D>(new_port_value);
+ break;
+ case 0x6:
+ new_port_value = m_port_latch[PORT_D] & 0xef;
+ if (ff_state) new_port_value |= 0x10;
+ port_w<PORT_D>(new_port_value);
+ break;
+ case 0x8:
+ new_port_value = m_port_latch[PORT_E] & 0xfe;
+ if (ff_state) new_port_value |= 0x01;
+ port_w<PORT_E>(new_port_value);
+ break;
+ case 0xa:
+ new_port_value = m_port_latch[PORT_E] & 0xef;
+ if (ff_state) new_port_value |= 0x10;
+ port_w<PORT_E>(new_port_value);
+ break;
+ }
+}
+
+void tmp94c241_device::tffcr_w(uint8_t data)
+{
+ change_timer_flipflop( 1, (data >> 2) & 3 );
+ change_timer_flipflop( 3, (data >> 6) & 3 );
+ m_tffcr = data | 0xcc;
+}
+
+uint8_t tmp94c241_device::t23mod_r()
+{
+ return m_t23mod;
+}
+
+void tmp94c241_device::t23mod_w(uint8_t data)
+{
+ m_t23mod = data;
+}
+
+uint8_t tmp94c241_device::trdc_r()
+{
+ return m_trdc;
+}
+
+void tmp94c241_device::trdc_w(uint8_t data)
+{
+ m_trdc = data;
+}
+
+template <uint8_t Timer>
+void tmp94c241_device::treg_8_w(uint8_t data)
+{
+ m_treg_8[Timer] = data;
+}
+
+template <uint8_t Timer>
+void tmp94c241_device::treg_16_w(uint16_t data)
+{
+ m_treg_16[Timer] = data;
+}
+
+uint8_t tmp94c241_device::t4mod_r()
+{
+ return m_t4mod;
+}
+
+void tmp94c241_device::t4mod_w(uint8_t data)
+{
+ m_t4mod = data;
+}
+
+uint8_t tmp94c241_device::t6mod_r()
+{
+ return m_t6mod;
+}
+
+void tmp94c241_device::t6mod_w(uint8_t data)
+{
+ m_t6mod = data;
+}
+
+uint8_t tmp94c241_device::t8mod_r()
+{
+ return m_t8mod;
+}
+
+void tmp94c241_device::t8mod_w(uint8_t data)
+{
+ m_t8mod = data;
+}
+
+uint8_t tmp94c241_device::tamod_r()
+{
+ return m_tamod;
+}
+
+void tmp94c241_device::tamod_w(uint8_t data)
+{
+ m_tamod = data;
+}
+
+uint8_t tmp94c241_device::t4ffcr_r()
+{
+ return m_t4ffcr;
+}
+
+void tmp94c241_device::t4ffcr_w(uint8_t data)
+{
+ change_timer_flipflop( 4, data & 3 );
+ change_timer_flipflop( 5, (data >> 6) & 3 );
+ m_t4ffcr = data | 0xc3;
+}
+
+uint8_t tmp94c241_device::t6ffcr_r()
+{
+ return m_t6ffcr;
+}
+
+void tmp94c241_device::t6ffcr_w(uint8_t data)
+{
+ change_timer_flipflop( 6, data & 3 );
+ change_timer_flipflop( 7, (data >> 6) & 3 );
+ m_t6ffcr = data | 0xc3;
+}
+
+uint8_t tmp94c241_device::t8ffcr_r()
+{
+ return m_t8ffcr;
+}
+
+void tmp94c241_device::t8ffcr_w(uint8_t data)
+{
+ change_timer_flipflop( 8, data & 3 );
+ change_timer_flipflop( 9, (data >> 6) & 3 );
+ m_t8ffcr = data | 0xc3;
+}
+
+uint8_t tmp94c241_device::taffcr_r()
+{
+ return m_taffcr;
+}
+
+void tmp94c241_device::taffcr_w(uint8_t data)
+{
+ change_timer_flipflop( 0xa, data & 3 );
+ change_timer_flipflop( 0xb, (data >> 6) & 3 );
+ m_taffcr = data | 0xc3;
+}
+
+uint8_t tmp94c241_device::t16run_r()
+{
+ return m_t16run;
+}
+
+void tmp94c241_device::t16run_w(uint8_t data)
+{
+ m_t16run = data;
+ for (int i = 0; i < 4; i++)
+ {
+ if (!BIT(m_t16run, i)) // Timer isn't running
+ {
+ // These correspond to UP_COUNTER and TIMER_CHANGE for 16-bit timers 4, 6, 8 and A
+ m_timer_16[i] = 0;
+ m_timer_change[4 + i] = 0;
+ }
+ }
+}
+
+template <uint8_t Timer>
+uint16_t tmp94c241_device::cap_r()
+{
+ return m_t16_cap[Timer];
+}
+
+uint8_t tmp94c241_device::wdmod_r()
+{
+ return m_watchdog_mode;
+}
+
+void tmp94c241_device::wdmod_w(uint8_t data)
+{
+ m_watchdog_mode = data;
+}
+
+void tmp94c241_device::wdcr_w(uint8_t data)
+{
+}
+
+template <uint8_t Channel>
+uint8_t tmp94c241_device::scNbuf_r()
+{
+ return 0;
+}
+
+template <uint8_t Channel>
+void tmp94c241_device::scNbuf_w(uint8_t data)
+{
+ // Fake finish sending data
+ m_int_reg[(Channel == 0) ? INTES0 : INTES1] |= 0x80;
+ m_check_irqs = 1;
+ logerror("sc%dbuf write: %02X\n", Channel, data);
+ //machine().debugger().debug_break();
+}
+
+template <uint8_t Channel>
+uint8_t tmp94c241_device::scNcr_r()
+{
+ uint8_t reg = m_serial_control[Channel];
+ if (!machine().side_effects_disabled())
+ m_serial_control[Channel] &= 0xe3;
+ return reg;
+}
+
+template <uint8_t Channel>
+void tmp94c241_device::scNcr_w(uint8_t data)
+{
+ m_serial_control[Channel] = data;
+}
+
+template <uint8_t Channel>
+uint8_t tmp94c241_device::scNmod_r()
+{
+ return m_serial_mode[Channel];
+}
+
+template <uint8_t Channel>
+void tmp94c241_device::scNmod_w(uint8_t data)
+{
+ m_serial_mode[Channel] = data;
+}
+
+template <uint8_t Channel>
+uint8_t tmp94c241_device::brNcr_r()
+{
+ return m_baud_rate[Channel];
+}
+
+template <uint8_t Channel>
+void tmp94c241_device::brNcr_w(uint8_t data)
+{
+ m_baud_rate[Channel] = data;
+}
+
+uint8_t tmp94c241_device::ode_r()
+{
+ return m_od_enable;
+}
+
+void tmp94c241_device::ode_w(uint8_t data)
+{
+ m_od_enable = data;
+}
+
+uint8_t tmp94c241_device::admod1_r()
+{
+ return m_ad_mode1;
+}
+
+void tmp94c241_device::admod1_w(uint8_t data)
+{
+ // Preserve read-only bits
+ data = (m_ad_mode1 & 0xc0) | ( data & 0x34 );
+
+ // Check for A/D conversion start
+ if (data & 0x04)
+ {
+ data &= ~0x04;
+ data |= 0x40;
+
+ switch ((m_ad_mode2 >> 4) & 3)
+ {
+ case 0: m_ad_cycles_left = 160; break;
+ case 1: m_ad_cycles_left = 320; break;
+ case 2: m_ad_cycles_left = 640; break;
+ case 3: m_ad_cycles_left = 1280; break;
+ }
+ }
+
+ m_ad_mode1 = data;
+}
+
+uint8_t tmp94c241_device::admod2_r()
+{
+ return m_ad_mode2;
+}
+
+void tmp94c241_device::admod2_w(uint8_t data)
+{
+ m_ad_mode2 = data;
+}
+
+uint8_t tmp94c241_device::adreg_r(offs_t offset)
+{
+ if (BIT(offset, 0))
+ return m_ad_result[offset >> 1] >> 2;
+ else
+ return m_ad_result[offset >> 1] << 6 | 0x3f;
+}
+
+uint8_t tmp94c241_device::dadrv_r()
+{
+ return m_da_drive;
+}
+
+void tmp94c241_device::dadrv_w(uint8_t data)
+{
+ m_da_drive = data;
+}
+
+void tmp94c241_device::dareg_w(offs_t offset, uint8_t data)
+{
+}
+
+template <uint8_t P>
+void tmp94c241_device::port_w(uint8_t data)
+{
+ m_port_latch[P] = data;
+ m_port_write[P](0, data, 0xff);
+}
+
+template <uint8_t P>
+uint8_t tmp94c241_device::port_r()
+{
+ return m_port_read[P](0);
+}
+
+template <uint8_t P>
+void tmp94c241_device::port_cr_w(uint8_t data)
+{
+ m_port_control[P] = data;
+}
+
+template <uint8_t P>
+void tmp94c241_device::port_fc_w(uint8_t data)
+{
+ m_port_function[P] = data;
+}
+
+//**************************************************************************
+// INTERNAL REGISTERS
+//**************************************************************************
+
+//-------------------------------------------------
+// internal_mem - memory map for internal RAM and
+// I/O registers
+//-------------------------------------------------
+
+void tmp94c241_device::internal_mem(address_map &map)
+{
+ map(0x000000, 0x000000).rw(FUNC(tmp94c241_device::port_r<PORT_0>), FUNC(tmp94c241_device::port_w<PORT_0>));
+ map(0x000002, 0x000002).w(FUNC(tmp94c241_device::port_cr_w<PORT_0>));
+ map(0x000003, 0x000003).w(FUNC(tmp94c241_device::port_fc_w<PORT_0>));
+ map(0x000004, 0x000004).rw(FUNC(tmp94c241_device::port_r<PORT_1>), FUNC(tmp94c241_device::port_w<PORT_1>));
+ map(0x000006, 0x000006).w(FUNC(tmp94c241_device::port_cr_w<PORT_1>));
+ map(0x000007, 0x000007).w(FUNC(tmp94c241_device::port_fc_w<PORT_1>));
+ map(0x000008, 0x000008).rw(FUNC(tmp94c241_device::port_r<PORT_2>), FUNC(tmp94c241_device::port_w<PORT_2>));
+ map(0x00000a, 0x00000a).w(FUNC(tmp94c241_device::port_cr_w<PORT_2>));
+ map(0x00000b, 0x00000b).w(FUNC(tmp94c241_device::port_fc_w<PORT_2>));
+ map(0x00000c, 0x00000c).rw(FUNC(tmp94c241_device::port_r<PORT_3>), FUNC(tmp94c241_device::port_w<PORT_3>));
+ map(0x00000e, 0x00000e).w(FUNC(tmp94c241_device::port_cr_w<PORT_3>));
+ map(0x00000f, 0x00000f).w(FUNC(tmp94c241_device::port_fc_w<PORT_3>));
+ map(0x000010, 0x000010).rw(FUNC(tmp94c241_device::port_r<PORT_4>), FUNC(tmp94c241_device::port_w<PORT_4>));
+ map(0x000012, 0x000012).w(FUNC(tmp94c241_device::port_cr_w<PORT_4>));
+ map(0x000013, 0x000013).w(FUNC(tmp94c241_device::port_fc_w<PORT_4>));
+ map(0x000014, 0x000014).rw(FUNC(tmp94c241_device::port_r<PORT_5>), FUNC(tmp94c241_device::port_w<PORT_5>));
+ map(0x000016, 0x000016).w(FUNC(tmp94c241_device::port_cr_w<PORT_5>));
+ map(0x000017, 0x000017).w(FUNC(tmp94c241_device::port_fc_w<PORT_5>));
+ map(0x000018, 0x000018).rw(FUNC(tmp94c241_device::port_r<PORT_6>), FUNC(tmp94c241_device::port_w<PORT_6>));
+ map(0x00001a, 0x00001a).w(FUNC(tmp94c241_device::port_cr_w<PORT_6>));
+ map(0x00001b, 0x00001b).w(FUNC(tmp94c241_device::port_fc_w<PORT_6>));
+ map(0x00001c, 0x00001c).rw(FUNC(tmp94c241_device::port_r<PORT_7>), FUNC(tmp94c241_device::port_w<PORT_7>));
+ map(0x00001e, 0x00001e).w(FUNC(tmp94c241_device::port_cr_w<PORT_7>));
+ map(0x00001f, 0x00001f).w(FUNC(tmp94c241_device::port_fc_w<PORT_7>));
+ map(0x000020, 0x000020).rw(FUNC(tmp94c241_device::port_r<PORT_8>), FUNC(tmp94c241_device::port_w<PORT_8>));
+ map(0x000022, 0x000022).w(FUNC(tmp94c241_device::port_cr_w<PORT_8>));
+ map(0x000023, 0x000023).w(FUNC(tmp94c241_device::port_fc_w<PORT_8>));
+ map(0x000028, 0x000028).rw(FUNC(tmp94c241_device::port_r<PORT_A>), FUNC(tmp94c241_device::port_w<PORT_A>));
+ map(0x00002b, 0x00002b).w(FUNC(tmp94c241_device::port_fc_w<PORT_A>));
+ map(0x00002c, 0x00002c).rw(FUNC(tmp94c241_device::port_r<PORT_B>), FUNC(tmp94c241_device::port_w<PORT_B>));
+ map(0x00002f, 0x00002f).w(FUNC(tmp94c241_device::port_fc_w<PORT_B>));
+ map(0x000030, 0x000030).rw(FUNC(tmp94c241_device::port_r<PORT_C>), FUNC(tmp94c241_device::port_w<PORT_C>));
+ map(0x000032, 0x000032).w(FUNC(tmp94c241_device::port_cr_w<PORT_C>));
+ map(0x000033, 0x000033).w(FUNC(tmp94c241_device::port_fc_w<PORT_C>));
+ map(0x000034, 0x000034).rw(FUNC(tmp94c241_device::port_r<PORT_D>), FUNC(tmp94c241_device::port_w<PORT_D>));
+ map(0x000036, 0x000036).w(FUNC(tmp94c241_device::port_cr_w<PORT_D>));
+ map(0x000037, 0x000037).w(FUNC(tmp94c241_device::port_fc_w<PORT_D>));
+ map(0x000038, 0x000038).rw(FUNC(tmp94c241_device::port_r<PORT_E>), FUNC(tmp94c241_device::port_w<PORT_E>));
+ map(0x00003a, 0x00003a).w(FUNC(tmp94c241_device::port_cr_w<PORT_E>));
+ map(0x00003b, 0x00003b).w(FUNC(tmp94c241_device::port_fc_w<PORT_E>));
+ map(0x00003c, 0x00003c).rw(FUNC(tmp94c241_device::port_r<PORT_F>), FUNC(tmp94c241_device::port_w<PORT_F>));
+ map(0x00003e, 0x00003e).w(FUNC(tmp94c241_device::port_cr_w<PORT_F>));
+ map(0x00003f, 0x00003f).w(FUNC(tmp94c241_device::port_fc_w<PORT_F>));
+ map(0x000040, 0x000040).r(FUNC(tmp94c241_device::port_r<PORT_G>));
+ map(0x000044, 0x000044).rw(FUNC(tmp94c241_device::port_r<PORT_H>), FUNC(tmp94c241_device::port_w<PORT_H>));
+ map(0x000046, 0x000046).w(FUNC(tmp94c241_device::port_cr_w<PORT_H>));
+ map(0x000047, 0x000047).w(FUNC(tmp94c241_device::port_fc_w<PORT_H>));
+ map(0x000068, 0x000068).rw(FUNC(tmp94c241_device::port_r<PORT_Z>), FUNC(tmp94c241_device::port_w<PORT_Z>));
+ map(0x00006a, 0x00006a).w(FUNC(tmp94c241_device::port_cr_w<PORT_Z>));
+ map(0x000080, 0x000080).rw(FUNC(tmp94c241_device::t8run_r), FUNC(tmp94c241_device::t8run_w));
+ map(0x000081, 0x000081).rw(FUNC(tmp94c241_device::trdc_r), FUNC(tmp94c241_device::trdc_w));
+ map(0x000082, 0x000082).rw(FUNC(tmp94c241_device::tffcr_r), FUNC(tmp94c241_device::tffcr_w));
+ map(0x000084, 0x000084).rw(FUNC(tmp94c241_device::t01mod_r), FUNC(tmp94c241_device::t01mod_w));
+ map(0x000085, 0x000085).rw(FUNC(tmp94c241_device::t23mod_r), FUNC(tmp94c241_device::t23mod_w));
+ map(0x000088, 0x000088).w(FUNC(tmp94c241_device::treg_8_w<TREG0>));
+ map(0x000089, 0x000089).w(FUNC(tmp94c241_device::treg_8_w<TREG1>));
+ map(0x00008a, 0x00008a).w(FUNC(tmp94c241_device::treg_8_w<TREG2>));
+ map(0x00008b, 0x00008b).w(FUNC(tmp94c241_device::treg_8_w<TREG3>));
+ map(0x000090, 0x000091).w(FUNC(tmp94c241_device::treg_16_w<TREG4>));
+ map(0x000092, 0x000093).w(FUNC(tmp94c241_device::treg_16_w<TREG5>));
+ map(0x000094, 0x000095).r(FUNC(tmp94c241_device::cap_r<CAP4>));
+ map(0x000096, 0x000097).r(FUNC(tmp94c241_device::cap_r<CAP5>));
+ map(0x000098, 0x000098).rw(FUNC(tmp94c241_device::t4mod_r), FUNC(tmp94c241_device::t4mod_w));
+ map(0x000099, 0x000099).rw(FUNC(tmp94c241_device::t4ffcr_r), FUNC(tmp94c241_device::t4ffcr_w));
+ map(0x00009e, 0x00009e).rw(FUNC(tmp94c241_device::t16run_r), FUNC(tmp94c241_device::t16run_w));
+ map(0x0000a0, 0x0000a1).w(FUNC(tmp94c241_device::treg_16_w<TREG6>));
+ map(0x0000a2, 0x0000a3).w(FUNC(tmp94c241_device::treg_16_w<TREG7>));
+ map(0x0000a4, 0x0000a5).r(FUNC(tmp94c241_device::cap_r<CAP6>));
+ map(0x0000a6, 0x0000a7).r(FUNC(tmp94c241_device::cap_r<CAP7>));
+ map(0x0000a8, 0x0000a8).rw(FUNC(tmp94c241_device::t6mod_r), FUNC(tmp94c241_device::t6mod_w));
+ map(0x0000a9, 0x0000a9).rw(FUNC(tmp94c241_device::t6ffcr_r), FUNC(tmp94c241_device::t6ffcr_w));
+ map(0x0000b0, 0x0000b1).w(FUNC(tmp94c241_device::treg_16_w<TREG8>));
+ map(0x0000b2, 0x0000b3).w(FUNC(tmp94c241_device::treg_16_w<TREG9>));
+ map(0x0000b4, 0x0000b5).r(FUNC(tmp94c241_device::cap_r<CAP8>));
+ map(0x0000b6, 0x0000b7).r(FUNC(tmp94c241_device::cap_r<CAP9>));
+ map(0x0000b8, 0x0000b8).rw(FUNC(tmp94c241_device::t8mod_r), FUNC(tmp94c241_device::t8mod_w));
+ map(0x0000b9, 0x0000b9).rw(FUNC(tmp94c241_device::t8ffcr_r), FUNC(tmp94c241_device::t8ffcr_w));
+ map(0x0000c0, 0x0000c1).w(FUNC(tmp94c241_device::treg_16_w<TREGA>));
+ map(0x0000c2, 0x0000c3).w(FUNC(tmp94c241_device::treg_16_w<TREGB>));
+ map(0x0000c4, 0x0000c5).r(FUNC(tmp94c241_device::cap_r<CAPA>));
+ map(0x0000c6, 0x0000c7).r(FUNC(tmp94c241_device::cap_r<CAPB>));
+ map(0x0000c8, 0x0000c8).rw(FUNC(tmp94c241_device::tamod_r), FUNC(tmp94c241_device::tamod_w));
+ map(0x0000c9, 0x0000c9).rw(FUNC(tmp94c241_device::taffcr_r), FUNC(tmp94c241_device::taffcr_w));
+ map(0x0000d0, 0x0000d0).rw(FUNC(tmp94c241_device::scNbuf_r<0>), FUNC(tmp94c241_device::scNbuf_w<0>));
+ map(0x0000d1, 0x0000d1).rw(FUNC(tmp94c241_device::scNcr_r<0>), FUNC(tmp94c241_device::scNcr_w<0>));
+ map(0x0000d2, 0x0000d2).rw(FUNC(tmp94c241_device::scNmod_r<0>), FUNC(tmp94c241_device::scNmod_w<0>));
+ map(0x0000d3, 0x0000d3).rw(FUNC(tmp94c241_device::brNcr_r<0>), FUNC(tmp94c241_device::brNcr_w<0>));
+ map(0x0000d4, 0x0000d4).rw(FUNC(tmp94c241_device::scNbuf_r<1>), FUNC(tmp94c241_device::scNbuf_w<1>));
+ map(0x0000d5, 0x0000d5).rw(FUNC(tmp94c241_device::scNcr_r<1>), FUNC(tmp94c241_device::scNcr_w<1>));
+ map(0x0000d6, 0x0000d6).rw(FUNC(tmp94c241_device::scNmod_r<1>), FUNC(tmp94c241_device::scNmod_w<1>));
+ map(0x0000d7, 0x0000d7).rw(FUNC(tmp94c241_device::brNcr_r<1>), FUNC(tmp94c241_device::brNcr_w<1>));
+ map(0x0000e0, 0x0000f0).rw(FUNC(tmp94c241_device::inte_r), FUNC(tmp94c241_device::inte_w));
+ map(0x0000f6, 0x0000f6).w(FUNC(tmp94c241_device::iimc_w));
+ map(0x0000f7, 0x0000f7).rw(FUNC(tmp94c241_device::intnmwdt_r), FUNC(tmp94c241_device::intnmwdt_w));
+ map(0x0000f8, 0x0000f8).w(FUNC(tmp94c241_device::intclr_w));
+ map(0x000100, 0x000103).w(FUNC(tmp94c241_device::dmav_w));
+ map(0x000110, 0x000110).rw(FUNC(tmp94c241_device::wdmod_r), FUNC(tmp94c241_device::wdmod_w));
+ map(0x000111, 0x000111).w(FUNC(tmp94c241_device::wdcr_w));
+ map(0x000120, 0x000127).r(FUNC(tmp94c241_device::adreg_r));
+ map(0x000128, 0x000128).rw(FUNC(tmp94c241_device::admod1_r), FUNC(tmp94c241_device::admod1_w));
+ map(0x000129, 0x000129).rw(FUNC(tmp94c241_device::admod2_r), FUNC(tmp94c241_device::admod2_w));
+ map(0x000130, 0x000131).w(FUNC(tmp94c241_device::dareg_w));
+ map(0x000132, 0x000132).rw(FUNC(tmp94c241_device::dadrv_r), FUNC(tmp94c241_device::dadrv_w));
+ map(0x000140, 0x000141).w(FUNC(tmp94c241_device::bNcs_w<0>));
+ map(0x000142, 0x000142).rw(FUNC(tmp94c241_device::mamr_r<0>), FUNC(tmp94c241_device::mamr_w<0>));
+ map(0x000143, 0x000143).rw(FUNC(tmp94c241_device::msar_r<0>), FUNC(tmp94c241_device::msar_w<0>));
+ map(0x000144, 0x000145).w(FUNC(tmp94c241_device::bNcs_w<1>));
+ map(0x000146, 0x000146).rw(FUNC(tmp94c241_device::mamr_r<1>), FUNC(tmp94c241_device::mamr_w<1>));
+ map(0x000147, 0x000147).rw(FUNC(tmp94c241_device::msar_r<1>), FUNC(tmp94c241_device::msar_w<1>));
+ map(0x000148, 0x000149).w(FUNC(tmp94c241_device::bNcs_w<2>));
+ map(0x00014a, 0x00014a).rw(FUNC(tmp94c241_device::mamr_r<2>), FUNC(tmp94c241_device::mamr_w<2>));
+ map(0x00014b, 0x00014b).rw(FUNC(tmp94c241_device::msar_r<2>), FUNC(tmp94c241_device::msar_w<2>));
+ map(0x00014c, 0x00014d).w(FUNC(tmp94c241_device::bNcs_w<3>));
+ map(0x00014e, 0x00014e).rw(FUNC(tmp94c241_device::mamr_r<3>), FUNC(tmp94c241_device::mamr_w<3>));
+ map(0x00014f, 0x00014f).rw(FUNC(tmp94c241_device::msar_r<3>), FUNC(tmp94c241_device::msar_w<3>));
+ map(0x000150, 0x000151).w(FUNC(tmp94c241_device::bNcs_w<4>));
+ map(0x000152, 0x000152).rw(FUNC(tmp94c241_device::mamr_r<4>), FUNC(tmp94c241_device::mamr_w<4>));
+ map(0x000153, 0x000153).rw(FUNC(tmp94c241_device::msar_r<4>), FUNC(tmp94c241_device::msar_w<4>));
+ map(0x000154, 0x000155).w(FUNC(tmp94c241_device::bNcs_w<5>));
+ map(0x000156, 0x000156).rw(FUNC(tmp94c241_device::mamr_r<5>), FUNC(tmp94c241_device::mamr_w<5>));
+ map(0x000157, 0x000157).rw(FUNC(tmp94c241_device::msar_r<5>), FUNC(tmp94c241_device::msar_w<5>));
+ map(0x000400, 0x000bff).ram();
+}
+
+//**************************************************************************
+// EXECUTION CALLBACKS
+//**************************************************************************
+
+//-------------------------------------------------
+// tlcs900_check_hdma -
+//-------------------------------------------------
+
+void tmp94c241_device::tlcs900_check_hdma()
+{
+}
+
+
+//-------------------------------------------------
+// tlcs900_check_irqs -
+//-------------------------------------------------
+
+void tmp94c241_device::tlcs900_check_irqs()
+{
+ // Check for NMI
+ if (m_nmi_state == ASSERT_LINE)
+ {
+ m_xssp.d -= 4;
+ WRMEML(m_xssp.d, m_pc.d);
+ m_xssp.d -= 2;
+ WRMEMW(m_xssp.d, m_sr.w.l);
+ m_pc.d = RDMEML( 0xffff00 + 0x20 );
+ m_cycles += 18;
+ m_prefetch_clear = true;
+ m_halted = 0;
+ m_nmi_state = CLEAR_LINE;
+ return;
+ }
+
+ /* Check regular IRQs
+ The smaller the vector value, the higher the priority. */
+ int irq_vectors[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
+ for (int i = NUM_MASKABLE_IRQS - 1; i >= 0; i--)
+ {
+ if (m_int_reg[tmp94c241_irq_vector_map[i].reg] & tmp94c241_irq_vector_map[i].iff)
+ {
+ switch (tmp94c241_irq_vector_map[i].iff)
+ {
+ case 0x80:
+ irq_vectors[(m_int_reg[tmp94c241_irq_vector_map[i].reg] >> 4) & 0x07] = i;
+ break;
+ case 0x08:
+ irq_vectors[m_int_reg[tmp94c241_irq_vector_map[i].reg] & 0x07] = i;
+ break;
+ }
+ }
+ }
+
+ // Check highest allowed priority IRQ
+ int irq = -1;
+ int level = 0;
+ for (int i = std::max(1, (m_sr.b.h & 0x70) >> 4); i < 7; i++)
+ {
+ if (irq_vectors[i] >= 0)
+ {
+ irq = irq_vectors[i];
+ level = i + 1;
+ }
+ }
+
+ // Take IRQ
+ if (irq >= 0)
+ {
+ uint8_t vector = tmp94c241_irq_vector_map[irq].vector;
+
+ m_xssp.d -= 4;
+ WRMEML(m_xssp.d, m_pc.d);
+ m_xssp.d -= 2;
+ WRMEMW(m_xssp.d, m_sr.w.l);
+
+ // Mask off any lower priority interrupts
+ m_sr.b.h = (m_sr.b.h & 0x8f) | (level << 4);
+
+ m_pc.d = RDMEML(0xffff00 + vector);
+
+ m_cycles += 18;
+ m_prefetch_clear = true;
+
+ m_halted = 0;
+
+ // Clear taken IRQ
+ m_int_reg[tmp94c241_irq_vector_map[irq].reg] &= ~ tmp94c241_irq_vector_map[irq].iff;
+ }
+}
+
+
+//-------------------------------------------------
+// tlcs900_handle_ad -
+//-------------------------------------------------
+
+void tmp94c241_device::tlcs900_handle_ad()
+{
+}
+
+
+//-------------------------------------------------
+// tlcs900_handle_timers -
+//-------------------------------------------------
+
+// Prescaler shift amounts corresponding to each possible timer input clock source:
+static constexpr uint8_t T1 = 3;
+static constexpr uint8_t T4 = 5;
+static constexpr uint8_t T16 = 7;
+static constexpr uint8_t T256 = 11;
+
+void tmp94c241_device::tlcs900_handle_timers()
+{
+ auto const update_timer_count =
+ [this, old_pre = m_timer_pre] (
+ uint8_t timer_index,
+ uint8_t input_clk_select,
+ uint8_t s1,
+ uint8_t s2,
+ uint8_t s3)
+ {
+ switch (input_clk_select)
+ {
+ case 0:
+ /* Not yet implemented.
+ - For the 8 bit timers: TIO, TO0TRG, invalid and TO2TRG
+ - For all 16 bit timers: TIA
+ */
+ break;
+ case 1: m_timer_change[timer_index] += ((m_timer_pre >> s1) - (old_pre >> s1)); break;
+ case 2: m_timer_change[timer_index] += ((m_timer_pre >> s2) - (old_pre >> s2)); break;
+ case 3: m_timer_change[timer_index] += ((m_timer_pre >> s3) - (old_pre >> s3)); break;
+ }
+ };
+
+ auto const timer_8bits =
+ [this] (
+ uint8_t timer_index,
+ uint8_t timer_reg,
+ uint8_t interrupt,
+ uint8_t interrupt_mask,
+ uint8_t operating_mode,
+ bool invert)
+ {
+ for ( ; m_timer_change[timer_index] > 0; m_timer_change[timer_index]--)
+ {
+ m_timer_8[timer_index]++;
+ if (m_timer_8[timer_index] == m_treg_8[timer_reg])
+ {
+ if (BIT(timer_index, 0) == 0)
+ {
+ if (operating_mode == 0) // mode == MODE_8BIT_TIMER
+ m_timer_change[timer_index | 1]++;
+
+ // In 16-bit timer mode the timer should not be reset
+ if (operating_mode != 1) // mode != MODE_16BIT_TIMER
+ {
+ m_timer_8[timer_index] = 0;
+ m_int_reg[interrupt] |= interrupt_mask;
+ m_check_irqs = 1;
+ }
+ }
+ else
+ {
+ m_timer_8[timer_index] = 0;
+ m_int_reg[interrupt] |= interrupt_mask;
+ m_check_irqs = 1;
+
+ // In 16-bit timer mode also reset its 8-bit counterpart (timer N-1)
+ if (operating_mode == 1) // mode == MODE_16BIT_TIMER
+ m_timer_8[timer_index & ~1] = 0;
+ }
+
+ if (invert)
+ change_timer_flipflop(timer_index | 1, FF_INVERT);
+ }
+ }
+ };
+
+ auto const timer_16bits =
+ [this] (
+ uint8_t timer_id,
+ uint8_t timer_reg_low,
+ uint8_t timer_reg_high,
+ uint8_t tffcr,
+ uint8_t interrupt)
+ {
+ /*
+ timer_id 4 => m_timer_16[0] m_timer_change[4]
+ timer_id 6 => m_timer_16[1] m_timer_change[5]
+ timer_id 8 => m_timer_16[2] m_timer_change[6]
+ timer_id A => m_timer_16[3] m_timer_change[7]
+ */
+ uint8_t timer_index = (timer_id - 4)/2;
+
+ for ( ; m_timer_change[timer_index + 4] > 0; m_timer_change[timer_index + 4]--)
+ {
+ m_timer_16[timer_index]++;
+ // TODO: also check for criteria of up counter matching CAPn registers
+ if (((m_timer_16[timer_index] == m_treg_16[timer_reg_high]) && BIT(tffcr, 3)) ||
+ ((m_timer_16[timer_index] == m_treg_16[timer_reg_low]) && BIT(tffcr, 2)) )
+ {
+ change_timer_flipflop(timer_id, FF_INVERT);
+ m_timer_16[timer_index] = 0;
+ m_int_reg[interrupt] |= 0x08;
+ m_check_irqs = 1;
+ }
+ }
+ };
+
+ if (BIT(m_t16run, 7)) // prescaler is active
+ m_timer_pre += m_cycles;
+
+ if (BIT(m_t8run, 0)) // Timer 0 is running
+ {
+ update_timer_count(0, m_t01mod & 3, T1, T4, T16);
+ timer_8bits(
+ 0, TREG0, INTET01, 0x08,
+ (m_t01mod >> 6) & 3, // TO1_OPERATING_MODE
+ (m_tffcr & 3) == 2); // "FF1 Invert Enable" && "Invert by 8-bit timer 0"
+ }
+
+ if (BIT(m_t8run, 1)) // Timer 1 is running
+ {
+ update_timer_count(1, (m_t01mod >> 2) & 3, T1, T16, T256);
+ timer_8bits(
+ 1, TREG1, INTET01, 0x80,
+ (m_t01mod >> 6) & 3, // TO1_OPERATING_MODE
+ (m_tffcr & 3) == 3); // "FF1 Invert Enable" && "Invert by 8-bit timer 1"
+ }
+
+ if (BIT(m_t8run, 2)) // Timer 2 is running
+ {
+ update_timer_count(2, m_t23mod & 3, T1, T4, T16);
+ timer_8bits(
+ 2, TREG2, INTET23, 0x08,
+ (m_t23mod >> 6) & 3, // T23_OPERATING_MODE
+ ((m_tffcr >> 4) & 3) == 2); // "FF3 Invert Enable" && "Invert by 8-bit timer 2"
+ }
+
+ if (BIT(m_t8run, 3)) // Timer 3 is running
+ {
+ update_timer_count(3, (m_t23mod >> 2) & 3, T1, T16, T256);
+ timer_8bits(
+ 3, TREG3, INTET23, 0x80,
+ (m_t23mod >> 6) & 3, // T23_OPERATING_MODE
+ ((m_tffcr >> 4) & 3) == 3); // "FF3 Invert Enable" && "Invert by 8-bit timer 3"
+ }
+
+ if (BIT(m_t16run, 0)) // Timer 4 is running
+ {
+ update_timer_count(4, m_t4mod & 3, T1, T4, T16);
+ timer_16bits(4, TREG4, TREG5, m_t4ffcr, INTET45);
+ }
+
+ if (BIT(m_t16run, 1)) // Timer 6 is running
+ {
+ update_timer_count(5, m_t6mod & 3, T1, T4, T16);
+ timer_16bits(6, TREG6, TREG7, m_t6ffcr, INTET67);
+ }
+
+ if (BIT(m_t16run, 2)) // Timer 8 is running
+ {
+ update_timer_count(6, m_t8mod & 3, T1, T4, T16);
+ timer_16bits(8, TREG8, TREG9, m_t8ffcr, INTET89);
+ }
+
+ if (BIT(m_t16run, 3)) // Timer A is running
+ {
+ update_timer_count(7, m_tamod & 3, T1, T4, T16);
+ timer_16bits(0xa, TREGA, TREGB, m_taffcr, INTETAB);
+ }
+
+ m_timer_pre &= 0xffffff;
+}
+
+
+//-------------------------------------------------
+// execute_set_input - called when a synchronized
+// input is changed
+//-------------------------------------------------
+
+void tmp94c241_device::execute_set_input(int input, int level)
+{
+ auto const update_int_reg =
+ [this, level, input] (uint8_t reg, uint8_t mask)
+ {
+ if (level != m_level[input])
+ {
+ m_level[input] = level;
+ if (level == ASSERT_LINE)
+ m_int_reg[reg] |= mask;
+ else
+ m_int_reg[reg] &= ~mask;
+ }
+ };
+
+ switch (input)
+ {
+ case INPUT_LINE_NMI:
+ case TLCS900_NMI:
+ if (level != m_level[TLCS900_NMI])
+ {
+ m_level[TLCS900_NMI] = level;
+ if (level == ASSERT_LINE)
+ m_nmi_state = ASSERT_LINE;
+ }
+ break;
+
+ case TLCS900_INTWD:
+ break;
+
+ case TLCS900_INT0:
+ if (m_iimc & 0x02)
+ {
+ // Rising edge detect
+ if (level != m_level[TLCS900_INT0] && level == ASSERT_LINE)
+ {
+ // Leave HALT state
+ m_halted = 0;
+ m_int_reg[INTE0AD] |= 0x08;
+ }
+ m_level[TLCS900_INT0] = level;
+ }
+ else
+ {
+ // Level detect
+ update_int_reg(INTE0AD, 0x08);
+ }
+ break;
+
+ case TLCS900_INT4: update_int_reg(INTE45, 0x08); break;
+ case TLCS900_INT5: update_int_reg(INTE45, 0x80); break;
+ case TLCS900_INT6: update_int_reg(INTE67, 0x08); break;
+ case TLCS900_INT7: update_int_reg(INTE67, 0x80); break;
+ case TLCS900_INT8: update_int_reg(INTE89, 0x08); break;
+ case TLCS900_INT9: update_int_reg(INTE89, 0x80); break;
+ case TLCS900_INTA: update_int_reg(INTEAB, 0x08); break;
+ case TLCS900_INTB: update_int_reg(INTEAB, 0x80); break;
+
+ default:
+ // invalid
+ return;
+ }
+ m_check_irqs = 1;
+}
+
+std::unique_ptr<util::disasm_interface> tmp94c241_device::create_disassembler()
+{
+ return std::make_unique<tlcs900_disassembler>();
+}