summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author hap <happppp@users.noreply.github.com>2022-08-07 02:14:07 +0200
committer hap <happppp@users.noreply.github.com>2022-08-07 02:14:16 +0200
commit4aff04831cb1f8bd8578086a9089e7d71c6ca271 (patch)
tree6c0cb9f09d8f742615cfbb36917c687d1ccdc1a6
parent2aa5f656730d90aee91b7f21ccef528fd89ae930 (diff)
tms2100: add timer interrupt
-rw-r--r--src/devices/cpu/tms1000/tms1k_base.cpp1
-rw-r--r--src/devices/cpu/tms1000/tms1k_base.h19
-rw-r--r--src/devices/cpu/tms1000/tms2100.cpp155
-rw-r--r--src/devices/cpu/tms1000/tms2100.h29
-rw-r--r--src/mame/handheld/hh_tms1k.cpp16
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));