From 1697740cd576838b764eeb64507d927131fef5e7 Mon Sep 17 00:00:00 2001 From: hap Date: Thu, 23 Apr 2020 00:23:27 +0200 Subject: [PATCH] hmcs40: simplify internal timer (nw) --- src/devices/cpu/hmcs40/hmcs40.cpp | 40 +++++++--------------------- src/devices/cpu/hmcs40/hmcs40.h | 8 +++--- src/devices/cpu/hmcs40/hmcs40op.cpp | 7 ++--- src/devices/cpu/ucom4/ucom4.cpp | 4 --- src/devices/cpu/ucom4/ucom4.h | 2 +- src/mame/drivers/hh_hmcs40.cpp | 4 +-- src/mame/drivers/saitek_chesstrv.cpp | 4 +++ src/mame/drivers/saitek_cp2000.cpp | 2 +- 8 files changed, 25 insertions(+), 46 deletions(-) diff --git a/src/devices/cpu/hmcs40/hmcs40.cpp b/src/devices/cpu/hmcs40/hmcs40.cpp index 0d3b331d531..c11d25bff56 100644 --- a/src/devices/cpu/hmcs40/hmcs40.cpp +++ b/src/devices/cpu/hmcs40/hmcs40.cpp @@ -207,8 +207,6 @@ void hmcs40_cpu_device::device_start() m_datamask = (1 << m_datawidth) - 1; m_pcmask = (1 << m_pcwidth) - 1; - m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(hmcs40_cpu_device::simple_timer_cb), this)); - // resolve callbacks m_read_r.resolve_all_safe(m_polarity & 0xf); m_write_r.resolve_all_safe(); @@ -222,6 +220,7 @@ void hmcs40_cpu_device::device_start() m_i = 0; m_eint_line = 0; m_halt = 0; + m_prescaler = 0; m_pc = 0; m_prev_pc = 0; m_page = 0; @@ -250,7 +249,6 @@ void hmcs40_cpu_device::device_start() save_item(NAME(m_i)); save_item(NAME(m_eint_line)); save_item(NAME(m_halt)); - save_item(NAME(m_timer_halted_remain)); save_item(NAME(m_pc)); save_item(NAME(m_prev_pc)); save_item(NAME(m_page)); @@ -263,6 +261,7 @@ void hmcs40_cpu_device::device_start() save_item(NAME(m_s)); save_item(NAME(m_c)); save_item(NAME(m_tc)); + save_item(NAME(m_prescaler)); save_item(NAME(m_cf)); save_item(NAME(m_ie)); save_item(NAME(m_iri)); @@ -307,9 +306,6 @@ void hmcs40_cpu_device::device_reset() m_iri = m_irt = 0; m_if[0] = m_if[1] = m_tf = 1; - if (!m_halt && m_timer->remaining().is_never()) - reset_prescaler(); - // clear i/o m_d = m_polarity; for (int i = 0; i < 16; i++) @@ -453,7 +449,6 @@ void hmcs45_cpu_device::write_r(int index, u8 data) void hmcs40_cpu_device::do_interrupt() { - m_icount--; push_stack(); m_ie = 0; @@ -470,6 +465,8 @@ void hmcs40_cpu_device::do_interrupt() standard_irq_callback(line); m_prev_pc = m_pc; + + cycle(); } void hmcs40_cpu_device::execute_set_input(int line, int state) @@ -479,14 +476,6 @@ void hmcs40_cpu_device::execute_set_input(int line, int state) // halt/unhalt mcu if (line == HMCS40_INPUT_LINE_HLT && state != m_halt) { - if (state) - { - m_timer_halted_remain = m_timer->remaining(); - m_timer->reset(); - } - else - m_timer->adjust(m_timer_halted_remain); - m_halt = state; return; } @@ -512,20 +501,14 @@ void hmcs40_cpu_device::execute_set_input(int line, int state) m_int[line] = state; } -void hmcs40_cpu_device::reset_prescaler() +void hmcs40_cpu_device::cycle() { - // reset 6-bit timer prescaler - attotime base = attotime::from_ticks(4 * 64, unscaled_clock()); - m_timer->adjust(base); -} + m_icount--; + m_prescaler = (m_prescaler + 1) & 0x3f; -TIMER_CALLBACK_MEMBER( hmcs40_cpu_device::simple_timer_cb ) -{ // timer prescaler overflow - if (!m_cf) + if (m_prescaler == 0 && !m_cf) increment_tc(); - - reset_prescaler(); } void hmcs40_cpu_device::increment_tc() @@ -583,15 +566,10 @@ void hmcs40_cpu_device::execute_run() // check/handle interrupt, but not in the middle of a long jump if (m_ie && (m_iri || m_irt) && (m_prev_op & 0x3e0) != 0x340) - { do_interrupt(); - if (m_icount <= 0) - break; - } // fetch next opcode debugger_instruction_hook(m_pc); - m_icount--; m_op = m_program->read_word(m_pc) & 0x3ff; m_i = bitswap<4>(m_op,0,1,2,3); // reversed bit-order for 4-bit immediate param (except for XAMR) increment_pc(); @@ -825,5 +803,7 @@ void hmcs40_cpu_device::execute_run() default: op_illegal(); break; } /* big switch */ + + cycle(); } } diff --git a/src/devices/cpu/hmcs40/hmcs40.h b/src/devices/cpu/hmcs40/hmcs40.h index ffc480395f4..38ea2490c80 100644 --- a/src/devices/cpu/hmcs40/hmcs40.h +++ b/src/devices/cpu/hmcs40/hmcs40.h @@ -111,7 +111,7 @@ protected: virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 4 - 1) / 4; } // 4 cycles per machine cycle virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles * 4); } // " virtual u32 execute_min_cycles() const noexcept override { return 1; } - virtual u32 execute_max_cycles() const noexcept override { return 2; } + virtual u32 execute_max_cycles() const noexcept override { return 2+1; } // max 2 + interrupt virtual u32 execute_input_lines() const noexcept override { return 2+1; } // 3rd one is internal virtual void execute_set_input(int line, int state) override; virtual void execute_run() override; @@ -148,9 +148,8 @@ protected: u16 m_prev_op; u8 m_i; // 4-bit immediate opcode param int m_eint_line; // which input_line caused an interrupt - emu_timer *m_timer; int m_halt; // internal HLT state - attotime m_timer_halted_remain; + u8 m_prescaler; // internal timer prescaler int m_icount; u16 m_pc; // Program Counter @@ -194,8 +193,7 @@ protected: virtual int read_d(int index); virtual void write_d(int index, int state); - void reset_prescaler(); - TIMER_CALLBACK_MEMBER( simple_timer_cb ); + void cycle(); void increment_tc(); void do_interrupt(); diff --git a/src/devices/cpu/hmcs40/hmcs40op.cpp b/src/devices/cpu/hmcs40/hmcs40op.cpp index b90cdcda2b3..a10629cf639 100644 --- a/src/devices/cpu/hmcs40/hmcs40op.cpp +++ b/src/devices/cpu/hmcs40/hmcs40op.cpp @@ -578,14 +578,14 @@ void hmcs40_cpu_device::op_lti() { // LTI i: Load Timer/Counter from Immediate m_tc = m_i; - reset_prescaler(); + m_prescaler = 0; } void hmcs40_cpu_device::op_lta() { // LTA: Load Timer/Counter from A m_tc = m_a; - reset_prescaler(); + m_prescaler = 0; } void hmcs40_cpu_device::op_lat() @@ -661,7 +661,6 @@ void hmcs40_cpu_device::op_lrb() void hmcs40_cpu_device::op_p() { // P p: Pattern Generation - m_icount--; u16 address = m_a | m_b << 4 | m_c << 8 | (m_op & 7) << 9 | (m_pc & ~0x3f); u16 o = m_program->read_word(address & m_prgmask); @@ -679,4 +678,6 @@ void hmcs40_cpu_device::op_p() write_r(2, o & 0xf); write_r(3, o >> 4 & 0xf); } + + cycle(); } diff --git a/src/devices/cpu/ucom4/ucom4.cpp b/src/devices/cpu/ucom4/ucom4.cpp index 225e5a1f72d..3eab39eca70 100644 --- a/src/devices/cpu/ucom4/ucom4.cpp +++ b/src/devices/cpu/ucom4/ucom4.cpp @@ -402,11 +402,7 @@ void ucom4_cpu_device::execute_run() { // handle interrupt, but not during LI($9x) or EI($31) or while skipping if (m_int_f && m_inte_f && (m_op & 0xf0) != 0x90 && m_op != 0x31 && !m_skip) - { do_interrupt(); - if (m_icount <= 0) - break; - } // remember previous state m_prev_op = m_op; diff --git a/src/devices/cpu/ucom4/ucom4.h b/src/devices/cpu/ucom4/ucom4.h index c22cee94edb..ad8c087f928 100644 --- a/src/devices/cpu/ucom4/ucom4.h +++ b/src/devices/cpu/ucom4/ucom4.h @@ -91,7 +91,7 @@ protected: virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 4 - 1) / 4; } // 4 cycles per machine cycle virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles * 4); } // " virtual u32 execute_min_cycles() const noexcept override { return 1; } - virtual u32 execute_max_cycles() const noexcept override { return 2; } + virtual u32 execute_max_cycles() const noexcept override { return 2+1; } // max 2 + interrupt virtual u32 execute_input_lines() const noexcept override { return 1; } virtual void execute_set_input(int line, int state) override; virtual void execute_run() override; diff --git a/src/mame/drivers/hh_hmcs40.cpp b/src/mame/drivers/hh_hmcs40.cpp index c6326cab70e..bca1230bae2 100644 --- a/src/mame/drivers/hh_hmcs40.cpp +++ b/src/mame/drivers/hh_hmcs40.cpp @@ -94,8 +94,8 @@ - gckong random lockups (tap the jump button repeatedly): mcu stack overflow, works ok if stack levels is increased, 38800 B rev. has more stack levels? Or it could be a race condition: irq happening too late/early. - - epacman2 booting the game in demo mode, pacman should go straight to the - upper-left power pill: mcu cycle/interrupt timing related + - epacman2 booting the game in demo mode, pacman should take the shortest route to + the upper-left power pill: mcu cycle/interrupt timing related - kevtris's HMCS40 ROM dumps are incomplete, missing MCU factory test code from the 2nd half of the ROM, none of the games access it though and it's impossible to execute unless the chip is in testmode. diff --git a/src/mame/drivers/saitek_chesstrv.cpp b/src/mame/drivers/saitek_chesstrv.cpp index f008c21171a..0f3f313ebe4 100644 --- a/src/mame/drivers/saitek_chesstrv.cpp +++ b/src/mame/drivers/saitek_chesstrv.cpp @@ -17,6 +17,10 @@ SciSys/Novag's "Chess Champion: Pocket Chess" is assumed to be the same game, it has the same MCU serial (SL90387). They added battery low voltage detection to it (rightmost digit DP lights up). +TODO: +- MCU frequency was actually measured ~3MHz, but this is much too slow when compared + to a video recording (of Novag Pocket Chess), need to reverify + ******************************************************************************/ #include "emu.h" diff --git a/src/mame/drivers/saitek_cp2000.cpp b/src/mame/drivers/saitek_cp2000.cpp index 4a848139cf0..610e11c7eef 100644 --- a/src/mame/drivers/saitek_cp2000.cpp +++ b/src/mame/drivers/saitek_cp2000.cpp @@ -7,7 +7,7 @@ SciSys Chess Partner 2000, also sold by Novag with the same name. It's probably the last SciSys / Novag collaboration. Hardware notes: -- 3850PK CPU at ~2.8MHz, 3853PK memory interface +- 3850PK CPU at ~2.77MHz(averaged), 3853PK memory interface - 4KB ROM, 256 bytes RAM(2*2111N) - 4-digit 7seg panel, sensory chessboard