mirror of
https://github.com/holub/mame
synced 2025-06-11 07:14:07 +03:00
hmcs40: simplify internal timer (nw)
This commit is contained in:
parent
65ad8907a4
commit
1697740cd5
@ -207,8 +207,6 @@ void hmcs40_cpu_device::device_start()
|
|||||||
m_datamask = (1 << m_datawidth) - 1;
|
m_datamask = (1 << m_datawidth) - 1;
|
||||||
m_pcmask = (1 << m_pcwidth) - 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
|
// resolve callbacks
|
||||||
m_read_r.resolve_all_safe(m_polarity & 0xf);
|
m_read_r.resolve_all_safe(m_polarity & 0xf);
|
||||||
m_write_r.resolve_all_safe();
|
m_write_r.resolve_all_safe();
|
||||||
@ -222,6 +220,7 @@ void hmcs40_cpu_device::device_start()
|
|||||||
m_i = 0;
|
m_i = 0;
|
||||||
m_eint_line = 0;
|
m_eint_line = 0;
|
||||||
m_halt = 0;
|
m_halt = 0;
|
||||||
|
m_prescaler = 0;
|
||||||
m_pc = 0;
|
m_pc = 0;
|
||||||
m_prev_pc = 0;
|
m_prev_pc = 0;
|
||||||
m_page = 0;
|
m_page = 0;
|
||||||
@ -250,7 +249,6 @@ void hmcs40_cpu_device::device_start()
|
|||||||
save_item(NAME(m_i));
|
save_item(NAME(m_i));
|
||||||
save_item(NAME(m_eint_line));
|
save_item(NAME(m_eint_line));
|
||||||
save_item(NAME(m_halt));
|
save_item(NAME(m_halt));
|
||||||
save_item(NAME(m_timer_halted_remain));
|
|
||||||
save_item(NAME(m_pc));
|
save_item(NAME(m_pc));
|
||||||
save_item(NAME(m_prev_pc));
|
save_item(NAME(m_prev_pc));
|
||||||
save_item(NAME(m_page));
|
save_item(NAME(m_page));
|
||||||
@ -263,6 +261,7 @@ void hmcs40_cpu_device::device_start()
|
|||||||
save_item(NAME(m_s));
|
save_item(NAME(m_s));
|
||||||
save_item(NAME(m_c));
|
save_item(NAME(m_c));
|
||||||
save_item(NAME(m_tc));
|
save_item(NAME(m_tc));
|
||||||
|
save_item(NAME(m_prescaler));
|
||||||
save_item(NAME(m_cf));
|
save_item(NAME(m_cf));
|
||||||
save_item(NAME(m_ie));
|
save_item(NAME(m_ie));
|
||||||
save_item(NAME(m_iri));
|
save_item(NAME(m_iri));
|
||||||
@ -307,9 +306,6 @@ void hmcs40_cpu_device::device_reset()
|
|||||||
m_iri = m_irt = 0;
|
m_iri = m_irt = 0;
|
||||||
m_if[0] = m_if[1] = m_tf = 1;
|
m_if[0] = m_if[1] = m_tf = 1;
|
||||||
|
|
||||||
if (!m_halt && m_timer->remaining().is_never())
|
|
||||||
reset_prescaler();
|
|
||||||
|
|
||||||
// clear i/o
|
// clear i/o
|
||||||
m_d = m_polarity;
|
m_d = m_polarity;
|
||||||
for (int i = 0; i < 16; i++)
|
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()
|
void hmcs40_cpu_device::do_interrupt()
|
||||||
{
|
{
|
||||||
m_icount--;
|
|
||||||
push_stack();
|
push_stack();
|
||||||
m_ie = 0;
|
m_ie = 0;
|
||||||
|
|
||||||
@ -470,6 +465,8 @@ void hmcs40_cpu_device::do_interrupt()
|
|||||||
|
|
||||||
standard_irq_callback(line);
|
standard_irq_callback(line);
|
||||||
m_prev_pc = m_pc;
|
m_prev_pc = m_pc;
|
||||||
|
|
||||||
|
cycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmcs40_cpu_device::execute_set_input(int line, int state)
|
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
|
// halt/unhalt mcu
|
||||||
if (line == HMCS40_INPUT_LINE_HLT && state != m_halt)
|
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;
|
m_halt = state;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -512,20 +501,14 @@ void hmcs40_cpu_device::execute_set_input(int line, int state)
|
|||||||
m_int[line] = state;
|
m_int[line] = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmcs40_cpu_device::reset_prescaler()
|
void hmcs40_cpu_device::cycle()
|
||||||
{
|
{
|
||||||
// reset 6-bit timer prescaler
|
m_icount--;
|
||||||
attotime base = attotime::from_ticks(4 * 64, unscaled_clock());
|
m_prescaler = (m_prescaler + 1) & 0x3f;
|
||||||
m_timer->adjust(base);
|
|
||||||
}
|
|
||||||
|
|
||||||
TIMER_CALLBACK_MEMBER( hmcs40_cpu_device::simple_timer_cb )
|
|
||||||
{
|
|
||||||
// timer prescaler overflow
|
// timer prescaler overflow
|
||||||
if (!m_cf)
|
if (m_prescaler == 0 && !m_cf)
|
||||||
increment_tc();
|
increment_tc();
|
||||||
|
|
||||||
reset_prescaler();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmcs40_cpu_device::increment_tc()
|
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
|
// check/handle interrupt, but not in the middle of a long jump
|
||||||
if (m_ie && (m_iri || m_irt) && (m_prev_op & 0x3e0) != 0x340)
|
if (m_ie && (m_iri || m_irt) && (m_prev_op & 0x3e0) != 0x340)
|
||||||
{
|
|
||||||
do_interrupt();
|
do_interrupt();
|
||||||
if (m_icount <= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch next opcode
|
// fetch next opcode
|
||||||
debugger_instruction_hook(m_pc);
|
debugger_instruction_hook(m_pc);
|
||||||
m_icount--;
|
|
||||||
m_op = m_program->read_word(m_pc) & 0x3ff;
|
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)
|
m_i = bitswap<4>(m_op,0,1,2,3); // reversed bit-order for 4-bit immediate param (except for XAMR)
|
||||||
increment_pc();
|
increment_pc();
|
||||||
@ -825,5 +803,7 @@ void hmcs40_cpu_device::execute_run()
|
|||||||
default:
|
default:
|
||||||
op_illegal(); break;
|
op_illegal(); break;
|
||||||
} /* big switch */
|
} /* big switch */
|
||||||
|
|
||||||
|
cycle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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_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 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_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 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_set_input(int line, int state) override;
|
||||||
virtual void execute_run() override;
|
virtual void execute_run() override;
|
||||||
@ -148,9 +148,8 @@ protected:
|
|||||||
u16 m_prev_op;
|
u16 m_prev_op;
|
||||||
u8 m_i; // 4-bit immediate opcode param
|
u8 m_i; // 4-bit immediate opcode param
|
||||||
int m_eint_line; // which input_line caused an interrupt
|
int m_eint_line; // which input_line caused an interrupt
|
||||||
emu_timer *m_timer;
|
|
||||||
int m_halt; // internal HLT state
|
int m_halt; // internal HLT state
|
||||||
attotime m_timer_halted_remain;
|
u8 m_prescaler; // internal timer prescaler
|
||||||
int m_icount;
|
int m_icount;
|
||||||
|
|
||||||
u16 m_pc; // Program Counter
|
u16 m_pc; // Program Counter
|
||||||
@ -194,8 +193,7 @@ protected:
|
|||||||
virtual int read_d(int index);
|
virtual int read_d(int index);
|
||||||
virtual void write_d(int index, int state);
|
virtual void write_d(int index, int state);
|
||||||
|
|
||||||
void reset_prescaler();
|
void cycle();
|
||||||
TIMER_CALLBACK_MEMBER( simple_timer_cb );
|
|
||||||
void increment_tc();
|
void increment_tc();
|
||||||
void do_interrupt();
|
void do_interrupt();
|
||||||
|
|
||||||
|
@ -578,14 +578,14 @@ void hmcs40_cpu_device::op_lti()
|
|||||||
{
|
{
|
||||||
// LTI i: Load Timer/Counter from Immediate
|
// LTI i: Load Timer/Counter from Immediate
|
||||||
m_tc = m_i;
|
m_tc = m_i;
|
||||||
reset_prescaler();
|
m_prescaler = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmcs40_cpu_device::op_lta()
|
void hmcs40_cpu_device::op_lta()
|
||||||
{
|
{
|
||||||
// LTA: Load Timer/Counter from A
|
// LTA: Load Timer/Counter from A
|
||||||
m_tc = m_a;
|
m_tc = m_a;
|
||||||
reset_prescaler();
|
m_prescaler = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hmcs40_cpu_device::op_lat()
|
void hmcs40_cpu_device::op_lat()
|
||||||
@ -661,7 +661,6 @@ void hmcs40_cpu_device::op_lrb()
|
|||||||
void hmcs40_cpu_device::op_p()
|
void hmcs40_cpu_device::op_p()
|
||||||
{
|
{
|
||||||
// P p: Pattern Generation
|
// P p: Pattern Generation
|
||||||
m_icount--;
|
|
||||||
u16 address = m_a | m_b << 4 | m_c << 8 | (m_op & 7) << 9 | (m_pc & ~0x3f);
|
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);
|
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(2, o & 0xf);
|
||||||
write_r(3, o >> 4 & 0xf);
|
write_r(3, o >> 4 & 0xf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cycle();
|
||||||
}
|
}
|
||||||
|
@ -402,11 +402,7 @@ void ucom4_cpu_device::execute_run()
|
|||||||
{
|
{
|
||||||
// handle interrupt, but not during LI($9x) or EI($31) or while skipping
|
// 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)
|
if (m_int_f && m_inte_f && (m_op & 0xf0) != 0x90 && m_op != 0x31 && !m_skip)
|
||||||
{
|
|
||||||
do_interrupt();
|
do_interrupt();
|
||||||
if (m_icount <= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remember previous state
|
// remember previous state
|
||||||
m_prev_op = m_op;
|
m_prev_op = m_op;
|
||||||
|
@ -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_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 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_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 u32 execute_input_lines() const noexcept override { return 1; }
|
||||||
virtual void execute_set_input(int line, int state) override;
|
virtual void execute_set_input(int line, int state) override;
|
||||||
virtual void execute_run() override;
|
virtual void execute_run() override;
|
||||||
|
@ -94,8 +94,8 @@
|
|||||||
- gckong random lockups (tap the jump button repeatedly): mcu stack overflow,
|
- 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?
|
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.
|
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
|
- epacman2 booting the game in demo mode, pacman should take the shortest route to
|
||||||
upper-left power pill: mcu cycle/interrupt timing related
|
the upper-left power pill: mcu cycle/interrupt timing related
|
||||||
- kevtris's HMCS40 ROM dumps are incomplete, missing MCU factory test code from
|
- 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
|
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.
|
to execute unless the chip is in testmode.
|
||||||
|
@ -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
|
it has the same MCU serial (SL90387). They added battery low voltage detection
|
||||||
to it (rightmost digit DP lights up).
|
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"
|
#include "emu.h"
|
||||||
|
@ -7,7 +7,7 @@ SciSys Chess Partner 2000, also sold by Novag with the same name.
|
|||||||
It's probably the last SciSys / Novag collaboration.
|
It's probably the last SciSys / Novag collaboration.
|
||||||
|
|
||||||
Hardware notes:
|
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)
|
- 4KB ROM, 256 bytes RAM(2*2111N)
|
||||||
- 4-digit 7seg panel, sensory chessboard
|
- 4-digit 7seg panel, sensory chessboard
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user