diff options
-rw-r--r-- | src/devices/cpu/tms1000/tms1k_base.cpp | 1 | ||||
-rw-r--r-- | src/devices/cpu/tms1000/tms1k_base.h | 19 | ||||
-rw-r--r-- | src/devices/cpu/tms1000/tms2100.cpp | 155 | ||||
-rw-r--r-- | src/devices/cpu/tms1000/tms2100.h | 29 | ||||
-rw-r--r-- | src/mame/handheld/hh_tms1k.cpp | 16 |
5 files changed, 207 insertions, 13 deletions
diff --git a/src/devices/cpu/tms1000/tms1k_base.cpp b/src/devices/cpu/tms1000/tms1k_base.cpp index d21d7eeea90..8034c2c7b4c 100644 --- a/src/devices/cpu/tms1000/tms1k_base.cpp +++ b/src/devices/cpu/tms1000/tms1k_base.cpp @@ -86,6 +86,7 @@ tms1k_base_device::tms1k_base_device(const machine_config &mconfig, device_type m_byte_bits(byte_bits), m_x_bits(x_bits), m_stack_levels(stack_levels), + m_option_dec_div(0), m_read_k(*this), m_write_o(*this), m_write_r(*this), diff --git a/src/devices/cpu/tms1000/tms1k_base.h b/src/devices/cpu/tms1000/tms1k_base.h index 36bae1c4921..136a54e61c7 100644 --- a/src/devices/cpu/tms1000/tms1k_base.h +++ b/src/devices/cpu/tms1000/tms1k_base.h @@ -28,6 +28,7 @@ public: // TMS2100 handlers auto read_j() { return m_read_j.bind(); } // J input pins auto read_r() { return m_read_r.bind(); } // R0-R3 input pins + auto &set_option_dec_div(u8 div) { m_option_dec_div = div; return *this; } // OFF request on TMS0980 and up auto power_off() { return m_power_off.bind(); } @@ -187,6 +188,8 @@ protected: address_space_config m_program_config; address_space_config m_data_config; + address_space *m_program; + address_space *m_data; optional_device<pla_device> m_mpla; optional_device<pla_device> m_ipla; @@ -194,6 +197,7 @@ protected: optional_memory_region m_opla_b; // binary dump of output PLA, in place of PLA file optional_device<pla_device> m_spla; + // internal state u8 m_pc; // 6 or 7-bit program counter u32 m_sr; // 6 or 7-bit subroutine return register(s) u8 m_pa; // 4-bit page address register @@ -232,6 +236,7 @@ protected: int m_subcycle; u8 m_o_index; + // fixed settings or mask options u8 m_o_pins; // how many O pins u8 m_r_pins; // how many R pins u8 m_pc_bits; // how many program counter bits @@ -239,9 +244,14 @@ protected: u8 m_x_bits; // how many X register bits u8 m_stack_levels; // number of stack levels (max 4) - address_space *m_program; - address_space *m_data; + u32 m_o_mask; + u32 m_r_mask; + u32 m_pc_mask; + u32 m_x_mask; + + u8 m_option_dec_div; + // i/o handlers devcb_read8 m_read_k; devcb_write16 m_write_o; devcb_write32 m_write_r; @@ -258,11 +268,6 @@ protected: const u16 *m_output_pla_table; devcb_read32 m_decode_micro; - u32 m_o_mask; - u32 m_r_mask; - u32 m_pc_mask; - u32 m_x_mask; - int m_icount; int m_state_count; diff --git a/src/devices/cpu/tms1000/tms2100.cpp b/src/devices/cpu/tms1000/tms2100.cpp index efe561e787e..fc9b16bb3bc 100644 --- a/src/devices/cpu/tms1000/tms2100.cpp +++ b/src/devices/cpu/tms1000/tms2100.cpp @@ -22,7 +22,6 @@ Extra functions are controlled with the R register (not mapped to pins): - R24: enable interrupts TODO: -- timer interrupt - external interrupt (INT pin) - event counter (EC1 pin) - R0-R3 I/O, TRA opcode @@ -88,13 +87,44 @@ void tms2100_cpu_device::device_start() { tms1100_cpu_device::device_start(); + m_prescaler = timer_alloc(FUNC(tms2100_cpu_device::prescaler_timeout), this); + reset_prescaler(); + // zerofill m_ac2 = 0; m_ivr = 0; + m_dec = 0xff; + m_il = 0; + m_int_pending = false; + m_r_prev = 0; + + m_pb_save = 0; + m_cb_save = 0; + m_a_save = 0; + m_ac2_save = 0; + m_x_save = 0; + m_y_save = 0; + m_s_save = 0; + m_sl_save = 0; + m_o_save = 0; // register for savestates save_item(NAME(m_ac2)); save_item(NAME(m_ivr)); + save_item(NAME(m_dec)); + save_item(NAME(m_il)); + save_item(NAME(m_int_pending)); + save_item(NAME(m_r_prev)); + + save_item(NAME(m_pb_save)); + save_item(NAME(m_cb_save)); + save_item(NAME(m_a_save)); + save_item(NAME(m_ac2_save)); + save_item(NAME(m_x_save)); + save_item(NAME(m_y_save)); + save_item(NAME(m_s_save)); + save_item(NAME(m_sl_save)); + save_item(NAME(m_o_save)); state_add(++m_state_count, "AC2", m_ac2).formatstr("%01X"); // 9 } @@ -103,6 +133,9 @@ void tms2100_cpu_device::device_reset() { tms1100_cpu_device::device_reset(); + m_il = 0; + m_int_pending = false; + // changed/added fixed instructions m_fixed_decode[0x09] = F_TAX; m_fixed_decode[0x0e] = F_TADM; @@ -113,6 +146,92 @@ void tms2100_cpu_device::device_reset() } +// interrupt/timer +void tms2100_cpu_device::read_opcode() +{ + // return from interrupt + if ((m_fixed & F_RETN) && m_il == 1) + { + m_il = 0; + + // restore registers + m_pb = m_pb_save; + m_cb = m_cb_save; + m_a = m_a_save; + m_ac2 = m_ac2_save; + m_x = m_x_save; + m_y = m_y_save; + m_status = m_s_save; + m_status_latch = m_sl_save; + write_o_reg(m_o_save); + } + + // interrupt pending (blocked during jump opcodes) + if (m_int_pending && !(m_fixed & (F_BR | F_CALL | F_RETN))) + { + m_int_pending = false; + + // interrupt enabled + if (BIT(m_r, 24)) + { + interrupt(); + return; + } + } + + tms1100_cpu_device::read_opcode(); +} + +void tms2100_cpu_device::interrupt() +{ + // save registers + m_pb_save = m_pb; + m_cb_save = m_cb; + m_a_save = m_a; + m_ac2_save = m_ac2; + m_x_save = m_x; + m_y_save = m_y; + m_s_save = m_status; + m_sl_save = m_status_latch; + m_o_save = m_o_index; + + // insert CALL to 0 + m_opcode = 0xc0; + m_fixed = m_fixed_decode[m_opcode]; + m_micro = m_micro_decode[m_opcode]; + + m_pb = 0; + m_cb = 0; + m_status = 1; + m_il |= 1; +} + +TIMER_CALLBACK_MEMBER(tms2100_cpu_device::prescaler_timeout) +{ + // clock decrementer if internal timer is enabled + if (!BIT(m_r, 18) && m_dec != 0xff) + { + if (--m_dec == 0) + { + // possible pending interrupt + m_int_pending = true; + + // reload decrementer + if (BIT(m_r, 23)) + m_dec = m_ivr; + } + } +} + +void tms2100_cpu_device::reset_prescaler() +{ + // prescaler divider is a mask option + static const u16 div[4] = { 32, 128, 256, 1024 }; + attotime period = attotime::from_ticks(div[m_option_dec_div & 3] * 6, clock()); + m_prescaler->adjust(period, 0, period); +} + + // i/o handling u8 tms2100_cpu_device::read_k_input() { @@ -120,8 +239,42 @@ u8 tms2100_cpu_device::read_k_input() return (BIT(m_r, 16) ? m_read_j() : m_read_k()) & 0xf; } +void tms2100_cpu_device::write_r_output(u32 data) +{ + if (m_r != m_r_prev) + { + // R15 falling edge: reset decrementer + if (BIT(m_r_prev, 15) && !BIT(m_r, 15)) + m_dec = 0xff; + + // R23 rising edge: load decrementer + if (!BIT(m_r_prev, 23) && BIT(m_r, 23)) + m_dec = m_ivr; + + m_r_prev = m_r; + } + + tms1100_cpu_device::write_r_output(data); +} + // opcode deviations +void tms2100_cpu_device::op_call() +{ + // CALL: take IL/ILC into account + // it can only do 1 extra call inside an interrupt routine + if (m_status) + m_il = ((m_il << 1) | (m_il & 1)) & 7; + tms1100_cpu_device::op_call(); +} + +void tms2100_cpu_device::op_retn() +{ + // RETN: take IL/ILC into account + m_il >>= 1; + tms1100_cpu_device::op_retn(); +} + void tms2100_cpu_device::op_tax() { // TAX: transfer accumulator to X register diff --git a/src/devices/cpu/tms1000/tms2100.h b/src/devices/cpu/tms1000/tms2100.h index e80862e91e3..7d45a0c82c0 100644 --- a/src/devices/cpu/tms1000/tms2100.h +++ b/src/devices/cpu/tms1000/tms2100.h @@ -72,11 +72,20 @@ protected: virtual void device_start() override; virtual void device_reset() override; virtual void device_add_mconfig(machine_config &config) override; + virtual void device_clock_changed() override { reset_prescaler(); } virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + virtual void read_opcode() override; + void interrupt(); + TIMER_CALLBACK_MEMBER(prescaler_timeout); + void reset_prescaler(); + virtual u8 read_k_input() override; + virtual void write_r_output(u32 data) override; + virtual void op_call() override; + virtual void op_retn() override; virtual void op_tax() override; virtual void op_tra() override; virtual void op_tac() override; @@ -84,8 +93,26 @@ protected: virtual void op_tadm() override; virtual void op_tma() override; + emu_timer *m_prescaler; + + // internal state u8 m_ac2; // 4-bit storage register, or R0-R3 output latch - u8 m_ivr; // initial value register + u8 m_ivr; // 8-bit initial value register + u8 m_dec; // 8-bit decrementer counter + u8 m_il; // interrupt latch(es) + bool m_int_pending; + u32 m_r_prev; + + // interrupt stack + u8 m_pb_save; + u8 m_cb_save; + u8 m_a_save; + u8 m_ac2_save; + u8 m_x_save; + u8 m_y_save; + u8 m_s_save; + u8 m_sl_save; + u8 m_o_save; }; class tms2170_cpu_device : public tms2100_cpu_device diff --git a/src/mame/handheld/hh_tms1k.cpp b/src/mame/handheld/hh_tms1k.cpp index 43b0cb5b026..c0114fee6c1 100644 --- a/src/mame/handheld/hh_tms1k.cpp +++ b/src/mame/handheld/hh_tms1k.cpp @@ -55,7 +55,7 @@ TODO: - tithermos temperature sensor comparator (right now just the digital clock works) - is alphie(patent) the same as the final version? - is starwbcp the same as MP3438? (starwbc is MP3438A) -- tgpachi is not working: incomplete MCU emulation, no SVG +- add SVG for tgpachi ============================================================================ @@ -14269,7 +14269,7 @@ ROM_END * PCB label: TOFL003 * TMS2670 M95041 (die label: TMS2400, M95041, 40H-01D-ND02-PHI0032-TTL O300-R300) * TMS1024 I/O expander - * cyan/red/green VFD display NEC FIP9AM31T no. 21-84, 2-bit sound + * cyan/red/green VFD display NEC FIP9AM31T no. 21-84, 1-bit sound ***************************************************************************/ @@ -14309,6 +14309,9 @@ void tgpachi_state::expander_w(offs_t offset, u8 data) void tgpachi_state::write_r(u32 data) { + // R13: speaker out + m_speaker->level_w(BIT(data, 13)); + // R9,R10: TMS1024 S0,S1 (S2 forced high) // R8: TMS1024 STD m_expander->write_s((data >> 9 & 3) | 4); @@ -14319,8 +14322,6 @@ void tgpachi_state::write_r(u32 data) m_grid = data & 0xff; m_plate = (m_plate & 0xfffff) | (BIT(data, 11) << 20); update_display(); - - // R13,R14: speaker out } void tgpachi_state::write_o(u16 data) @@ -14341,6 +14342,12 @@ static INPUT_PORTS_START( tgpachi ) PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_START ) PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON2 ) // Slot + + PORT_START("IN.1") // J + PORT_BIT( 0x07, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_CONFNAME( 0x08, 0x00, DEF_STR( Difficulty ) ) + PORT_CONFSETTING( 0x00, "1" ) + PORT_CONFSETTING( 0x08, "2" ) INPUT_PORTS_END void tgpachi_state::tgpachi(machine_config &config) @@ -14348,6 +14355,7 @@ void tgpachi_state::tgpachi(machine_config &config) // basic machine hardware TMS2670(config, m_maincpu, 450000); // approximation - RC osc. R=47K, C=47pF m_maincpu->read_k().set_ioport("IN.0"); + m_maincpu->read_j().set_ioport("IN.1"); m_maincpu->write_r().set(FUNC(tgpachi_state::write_r)); m_maincpu->write_o().set(FUNC(tgpachi_state::write_o)); |