mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
m50734: Partially emulate stepper motor controller registers
This commit is contained in:
parent
6c22952441
commit
19a765d75a
@ -35,6 +35,9 @@ m50734_device::m50734_device(const machine_config &mconfig, const char *tag, dev
|
||||
, m_ad_register(0)
|
||||
, m_prescaler_reload{0xff, 0xff, 0xff}
|
||||
, m_timer_reload{0xff, 0xff, 0xff}
|
||||
, m_step_counter{0, 0}
|
||||
, m_phase_counter(0)
|
||||
, m_smcon{0, 0}
|
||||
{
|
||||
program_config.m_internal_map = address_map_constructor(FUNC(m50734_device::internal_map), this);
|
||||
}
|
||||
@ -56,6 +59,25 @@ void m50734_device::device_resolve_objects()
|
||||
m_analog_in_cb.resolve_all_safe(0);
|
||||
}
|
||||
|
||||
void m50734_device::step_motor(int which)
|
||||
{
|
||||
if (!BIT(m_smcon[which], 2))
|
||||
return;
|
||||
|
||||
if (--m_step_counter[which] == 0 && !BIT(m_interrupt_control[0], which * 2 + 5))
|
||||
{
|
||||
LOGMASKED(LOG_TIMER, "%s counter empty at %s\n", which ? "Vertical" : "Horizontal", machine().time().to_string());
|
||||
m_interrupt_control[0] |= 0x20 << (which * 2);
|
||||
if (BIT(m_interrupt_control[0], which * 2 + 4))
|
||||
set_input_line(M740_INT3_LINE, ASSERT_LINE);
|
||||
}
|
||||
|
||||
// Increment or decrement HPHC/VPHC
|
||||
m_phase_counter = (m_phase_counter + ((BIT(m_smcon[which], 1) ? 7 : 1) << (which * 4))) & 0x77;
|
||||
|
||||
// TODO: single shot mode, phase decoder and P2 output
|
||||
}
|
||||
|
||||
template <int N>
|
||||
TIMER_CALLBACK_MEMBER(m50734_device::timer_interrupt)
|
||||
{
|
||||
@ -69,6 +91,11 @@ TIMER_CALLBACK_MEMBER(m50734_device::timer_interrupt)
|
||||
}
|
||||
}
|
||||
|
||||
if (N == 2)
|
||||
step_motor(0); // Timer 3 steps HC
|
||||
else if (N == 0)
|
||||
step_motor(1); // Timer 0 steps VC
|
||||
|
||||
// Reload timer and prescaler
|
||||
m_timer[N]->adjust(clocks_to_attotime(16 * u32(m_prescaler_reload[N] + 1) * (m_timer_reload[N] + 1)));
|
||||
}
|
||||
@ -92,6 +119,9 @@ void m50734_device::device_start()
|
||||
save_item(NAME(m_ad_register));
|
||||
save_item(NAME(m_prescaler_reload));
|
||||
save_item(NAME(m_timer_reload));
|
||||
save_item(NAME(m_step_counter));
|
||||
save_item(NAME(m_phase_counter));
|
||||
save_item(NAME(m_smcon));
|
||||
save_item(NAME(m_interrupt_control));
|
||||
}
|
||||
|
||||
@ -100,17 +130,25 @@ void m50734_device::device_reset()
|
||||
m740_device::device_reset();
|
||||
SP = 0x01ff;
|
||||
|
||||
// Reset port registers
|
||||
std::fill(std::begin(m_port_direction), std::end(m_port_direction), 0x00);
|
||||
for (int n = 0; n < 4; n++)
|
||||
m_port_out_cb[n](m_port_3state[n]);
|
||||
m_p0_function = 0x00;
|
||||
m_p2_p3_function = 0x00;
|
||||
|
||||
// Reset A-D
|
||||
m_ad_control |= 0x04;
|
||||
m_ad_timer->adjust(attotime::never);
|
||||
|
||||
// Reset stepper motor control registers (datasheet has no implication of RESET affecting these, but mps1200 never fully initializes SMCONH)
|
||||
m_smcon[0] = 0;
|
||||
m_smcon[1] = 0;
|
||||
|
||||
// Reset interrupts
|
||||
std::fill(std::begin(m_interrupt_control), std::end(m_interrupt_control), 0x00);
|
||||
set_input_line(M740_INT2_LINE, CLEAR_LINE);
|
||||
set_input_line(M740_INT3_LINE, CLEAR_LINE);
|
||||
}
|
||||
|
||||
void m50734_device::read_dummy(u16 adr)
|
||||
@ -144,7 +182,17 @@ void m50734_device::interrupt_control_w(offs_t offset, u8 data)
|
||||
if (offset == 1)
|
||||
data &= 0x3f;
|
||||
u8 old_control = std::exchange(m_interrupt_control[2 - offset], data);
|
||||
if (offset == 1)
|
||||
if (offset == 2)
|
||||
{
|
||||
bool he_ve_interrupt = (data & (data >> 1) & 0x50) != 0;
|
||||
bool old_interrupt = (old_control & (old_control >> 1) & 0x50) != 0;
|
||||
if (he_ve_interrupt != old_interrupt)
|
||||
{
|
||||
LOGMASKED(LOG_TIMER, "%s: HE/VE interrupt %sactivated by write to interrupt control register 1 ($%02X -> $%02X)\n", machine().describe_context(), he_ve_interrupt ? "": "de", old_control, data);
|
||||
set_input_line(M740_INT3_LINE, he_ve_interrupt ? ASSERT_LINE : CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
else if (offset == 1)
|
||||
{
|
||||
bool timer_interrupt = (data & (data >> 1) & 0x15) != 0;
|
||||
bool old_interrupt = (old_control & (old_control >> 1) & 0x15) != 0;
|
||||
@ -252,30 +300,69 @@ void m50734_device::timer_w(offs_t offset, u8 data)
|
||||
u8 pre = m_prescaler_reload[offset >> 1];
|
||||
if (BIT(offset, 0))
|
||||
{
|
||||
LOGMASKED(LOG_INIT, "%s: Reload timer %d latch = %d\n", machine().describe_context(), (offset >> 1) + 1, data);
|
||||
attotime expire_time = clocks_to_attotime(16 * (data * pre + (ticks % (pre + 1)) + 1));
|
||||
LOGMASKED(LOG_INIT, "%s: Reload timer %d latch = %u (expires in %.1f usec)\n", machine().describe_context(), (offset >> 1) + 1, data, expire_time.as_double() * 1.0E6);
|
||||
m_timer_reload[offset >> 1] = data;
|
||||
m_timer[offset >> 1]->adjust(clocks_to_attotime(16 * (data * pre + (ticks % (pre + 1)) + 1)));
|
||||
m_timer[offset >> 1]->adjust(expire_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_INIT, "%s: Reload prescaler %d latch = %d\n", machine().describe_context(), (offset >> 1) + 1, data);
|
||||
attotime expire_time = clocks_to_attotime(16 * (data + 1) * (std::min<u32>(ticks / (pre + 1), 0xff) + 1));
|
||||
LOGMASKED(LOG_INIT, "%s: Reload prescaler %d latch = %u (expires in %.1f usec)\n", machine().describe_context(), (offset >> 1) + 1, data, expire_time.as_double() * 1.0E6);
|
||||
m_prescaler_reload[offset >> 1] = data;
|
||||
m_timer[offset >> 1]->adjust(clocks_to_attotime(16 * (data + 1) * (std::min<u32>(ticks / (pre + 1), 0xff) + 1)));
|
||||
m_timer[offset >> 1]->adjust(expire_time);
|
||||
}
|
||||
}
|
||||
|
||||
u8 m50734_device::step_counter_r(offs_t offset)
|
||||
{
|
||||
return m_step_counter[offset];
|
||||
}
|
||||
|
||||
void m50734_device::step_counter_w(offs_t offset, u8 data)
|
||||
{
|
||||
LOGMASKED(LOG_INIT, "%s: %s counter = %u steps\n", machine().describe_context(), BIT(offset, 0) ? "Vertical" : "Horizontal", data);
|
||||
m_step_counter[offset] = data;
|
||||
}
|
||||
|
||||
u8 m50734_device::phase_counter_r()
|
||||
{
|
||||
return m_phase_counter;
|
||||
}
|
||||
|
||||
void m50734_device::phase_counter_w(u8 data)
|
||||
{
|
||||
// HPHC and VPHC are 3-bit counters (TODO: P2 output)
|
||||
m_phase_counter = data & 0x77;
|
||||
}
|
||||
|
||||
u8 m50734_device::smcon_r(offs_t offset)
|
||||
{
|
||||
return m_smcon[offset];
|
||||
}
|
||||
|
||||
void m50734_device::smcon_w(offs_t offset, u8 data)
|
||||
{
|
||||
if (m_smcon[offset] != (data & 0x0f))
|
||||
LOGMASKED(LOG_INIT, "%s: SMCON%c = $%02X\n", machine().describe_context(), "HV"[offset], data);
|
||||
m_smcon[offset] = data & 0x0f;
|
||||
}
|
||||
|
||||
void m50734_device::internal_map(address_map &map)
|
||||
{
|
||||
// TODO: other timers, UART, etc.
|
||||
map(0x00dc, 0x00e1).rw(FUNC(m50734_device::timer_r), FUNC(m50734_device::timer_w));
|
||||
map(0x00e2, 0x00e3).rw(FUNC(m50734_device::step_counter_r), FUNC(m50734_device::step_counter_w));
|
||||
map(0x00e9, 0x00e9).rw(FUNC(m50734_device::ad_control_r), FUNC(m50734_device::ad_control_w));
|
||||
map(0x00ea, 0x00ea).r(FUNC(m50734_device::ad_r));
|
||||
map(0x00eb, 0x00eb).r(FUNC(m50734_device::p4_r));
|
||||
map(0x00ec, 0x00ec).rw(FUNC(m50734_device::phase_counter_r), FUNC(m50734_device::phase_counter_w));
|
||||
map(0x00ed, 0x00ed).rw(FUNC(m50734_device::p2_p3_function_r), FUNC(m50734_device::p2_p3_function_w));
|
||||
map(0x00ee, 0x00ef).rw(FUNC(m50734_device::port_r<3>), FUNC(m50734_device::port_w<3>));
|
||||
map(0x00f0, 0x00f1).rw(FUNC(m50734_device::port_r<2>), FUNC(m50734_device::port_w<2>));
|
||||
map(0x00f3, 0x00f4).rw(FUNC(m50734_device::port_r<1>), FUNC(m50734_device::port_w<1>));
|
||||
map(0x00f5, 0x00f5).rw(FUNC(m50734_device::p0_function_r), FUNC(m50734_device::p0_function_w));
|
||||
map(0x00f6, 0x00f7).rw(FUNC(m50734_device::port_r<0>), FUNC(m50734_device::port_w<0>));
|
||||
map(0x00f8, 0x00f9).rw(FUNC(m50734_device::smcon_r), FUNC(m50734_device::smcon_w));
|
||||
map(0x00fd, 0x00ff).rw(FUNC(m50734_device::interrupt_control_r), FUNC(m50734_device::interrupt_control_w));
|
||||
}
|
||||
|
@ -114,7 +114,14 @@ private:
|
||||
|
||||
u8 timer_r(offs_t offset);
|
||||
void timer_w(offs_t offset, u8 data);
|
||||
void step_motor(int which);
|
||||
template <int N> TIMER_CALLBACK_MEMBER(timer_interrupt);
|
||||
u8 step_counter_r(offs_t offset);
|
||||
void step_counter_w(offs_t offset, u8 data);
|
||||
u8 phase_counter_r();
|
||||
void phase_counter_w(u8 data);
|
||||
u8 smcon_r(offs_t offset);
|
||||
void smcon_w(offs_t offset, u8 data);
|
||||
|
||||
void internal_map(address_map &map);
|
||||
|
||||
@ -137,6 +144,9 @@ private:
|
||||
u8 m_ad_register;
|
||||
u8 m_prescaler_reload[3];
|
||||
u8 m_timer_reload[3];
|
||||
u8 m_step_counter[2];
|
||||
u8 m_phase_counter;
|
||||
u8 m_smcon[2];
|
||||
u8 m_interrupt_control[3];
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user