hmcs40: simplify internal timer (nw)

This commit is contained in:
hap 2020-04-23 00:23:27 +02:00
parent 65ad8907a4
commit 1697740cd5
8 changed files with 25 additions and 46 deletions

View File

@ -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();
}
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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"

View File

@ -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