mirror of
https://github.com/holub/mame
synced 2025-06-07 13:23:50 +03:00
improved 8bit timers
This commit is contained in:
parent
b1592d4f2d
commit
6fa4137852
@ -85,7 +85,8 @@ bool mn10200_device::check_irq()
|
|||||||
take_irq(0, 0);
|
take_irq(0, 0);
|
||||||
else if (group)
|
else if (group)
|
||||||
take_irq(level, group);
|
take_irq(level, group);
|
||||||
else return false;
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -105,65 +106,58 @@ void mn10200_device::check_ext_irq()
|
|||||||
|
|
||||||
void mn10200_device::refresh_timer(int tmr)
|
void mn10200_device::refresh_timer(int tmr)
|
||||||
{
|
{
|
||||||
// enabled?
|
// 0: external pin
|
||||||
if (m_simple_timer[tmr].mode & 0x80)
|
// 1: cascaded (handled elsewhere)
|
||||||
{
|
// 2: prescaler 0
|
||||||
UINT8 source = (m_simple_timer[tmr].mode & 3);
|
// 3: prescaler 1
|
||||||
|
int p = m_simple_timer[tmr].mode & 1;
|
||||||
|
|
||||||
// source is a prescaler?
|
// enabled, and source is prescaler?
|
||||||
if (source >= 2)
|
if ((m_simple_timer[tmr].mode & 0x82) == 0x82 && m_simple_timer[tmr].cur != 0 && m_prescaler[p].mode & 0x80)
|
||||||
{
|
{
|
||||||
INT32 rate;
|
attotime period = m_sysclock_base * (m_prescaler[p].base + 1) * (m_simple_timer[tmr].cur + 1);
|
||||||
|
m_timer_timers[tmr]->adjust(period, tmr);
|
||||||
// is prescaler enabled?
|
|
||||||
if (m_prescaler[source-2].mode & 0x80)
|
|
||||||
{
|
|
||||||
// rate = (sysclock / prescaler) / our count
|
|
||||||
rate = unscaled_clock() / m_prescaler[source-2].cycles;
|
|
||||||
rate /= m_simple_timer[tmr].base;
|
|
||||||
|
|
||||||
if (tmr != 8) // HACK: timer 8 is run at 500 kHz by the Taito program for no obvious reason, which kills performance
|
|
||||||
m_timer_timers[tmr]->adjust(attotime::from_hz(rate), tmr);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
logerror("MN10200: timer %d using prescaler %d which isn't enabled!\n", tmr, source-2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // disabled, so stop it
|
|
||||||
{
|
{
|
||||||
m_timer_timers[tmr]->adjust(attotime::never, tmr);
|
m_timer_timers[tmr]->adjust(attotime::never, tmr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mn10200_device::timer_tick_simple(int tmr)
|
void mn10200_device::refresh_all_timers()
|
||||||
{
|
{
|
||||||
m_simple_timer[tmr].cur--;
|
for (int tmr = 0; tmr < MN10200_NUM_TIMERS_8BIT; tmr++)
|
||||||
|
refresh_timer(tmr);
|
||||||
|
}
|
||||||
|
|
||||||
// did we expire?
|
int mn10200_device::timer_tick_simple(int tmr)
|
||||||
if (m_simple_timer[tmr].cur == 0)
|
{
|
||||||
|
int next = tmr + 1;
|
||||||
|
|
||||||
|
// is it a cascaded timer, and enabled?
|
||||||
|
if (next < MN10200_NUM_TIMERS_8BIT && m_simple_timer[next].mode & 0x83 && (m_simple_timer[next].mode & 0x83) == 0x81)
|
||||||
{
|
{
|
||||||
// does timer auto-reload? apparently.
|
// did it underflow?
|
||||||
|
if (--m_simple_timer[next].cur == 0xff)
|
||||||
|
{
|
||||||
|
// cascaded underflow?
|
||||||
|
if (timer_tick_simple(next) != 2)
|
||||||
|
{
|
||||||
|
m_simple_timer[next].cur = m_simple_timer[next].base;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// reload and trigger irq
|
||||||
m_simple_timer[tmr].cur = m_simple_timer[tmr].base;
|
m_simple_timer[tmr].cur = m_simple_timer[tmr].base;
|
||||||
|
m_icrl[1 + (tmr >> 2)] |= (1 << (4 + (tmr & 3)));
|
||||||
// signal the cascade if we're not timer 9
|
|
||||||
if (tmr < (MN10200_NUM_TIMERS_8BIT-1))
|
|
||||||
{
|
|
||||||
// is next timer enabled?
|
|
||||||
if (m_simple_timer[tmr+1].mode & 0x80)
|
|
||||||
{
|
|
||||||
// is it's source "cascade"?
|
|
||||||
if ((m_simple_timer[tmr+1].mode & 0x3) == 1)
|
|
||||||
{
|
|
||||||
// recurse!
|
|
||||||
timer_tick_simple(tmr+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_icrl[1 + (tmr / 4)] |= (1 << (4 + (tmr % 4)));
|
|
||||||
check_irq();
|
check_irq();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,8 +166,22 @@ TIMER_CALLBACK_MEMBER( mn10200_device::simple_timer_cb )
|
|||||||
int tmr = param;
|
int tmr = param;
|
||||||
|
|
||||||
// handle our expiring and also tick our cascaded children
|
// handle our expiring and also tick our cascaded children
|
||||||
m_simple_timer[tmr].cur = 1;
|
switch (timer_tick_simple(tmr))
|
||||||
timer_tick_simple(tmr);
|
{
|
||||||
|
// cascaded, underflow
|
||||||
|
case 1:
|
||||||
|
m_simple_timer[tmr].cur = m_simple_timer[tmr].base;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// cascaded, no underflow
|
||||||
|
case 2:
|
||||||
|
m_simple_timer[tmr].cur = 0xff;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// no action needed
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// refresh this timer
|
// refresh this timer
|
||||||
refresh_timer(tmr);
|
refresh_timer(tmr);
|
||||||
@ -186,6 +194,8 @@ void mn10200_device::device_start()
|
|||||||
m_program = &space(AS_PROGRAM);
|
m_program = &space(AS_PROGRAM);
|
||||||
m_io = &space(AS_IO);
|
m_io = &space(AS_IO);
|
||||||
|
|
||||||
|
m_sysclock_base = attotime::from_hz(unscaled_clock() / 2);
|
||||||
|
|
||||||
for (int tmr = 0; tmr < MN10200_NUM_TIMERS_8BIT; tmr++)
|
for (int tmr = 0; tmr < MN10200_NUM_TIMERS_8BIT; tmr++)
|
||||||
{
|
{
|
||||||
m_timer_timers[tmr] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mn10200_device::simple_timer_cb), this));
|
m_timer_timers[tmr] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mn10200_device::simple_timer_cb), this));
|
||||||
@ -210,11 +220,13 @@ void mn10200_device::device_start()
|
|||||||
}
|
}
|
||||||
for (int i = 0; i < MN10200_NUM_PRESCALERS; i++)
|
for (int i = 0; i < MN10200_NUM_PRESCALERS; i++)
|
||||||
{
|
{
|
||||||
m_prescaler[i].cycles = 0;
|
|
||||||
m_prescaler[i].mode = 0;
|
m_prescaler[i].mode = 0;
|
||||||
|
m_prescaler[i].base = 0;
|
||||||
|
m_prescaler[i].cur = 0;
|
||||||
|
|
||||||
save_item(NAME(m_prescaler[i].cycles), i);
|
|
||||||
save_item(NAME(m_prescaler[i].mode), i);
|
save_item(NAME(m_prescaler[i].mode), i);
|
||||||
|
save_item(NAME(m_prescaler[i].base), i);
|
||||||
|
save_item(NAME(m_prescaler[i].cur), i);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
@ -324,15 +336,6 @@ void mn10200_device::device_reset()
|
|||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
for (int address = 0xfc04; address < 0x10000; address++)
|
for (int address = 0xfc04; address < 0x10000; address++)
|
||||||
write_mem16(address, 0);
|
write_mem16(address, 0);
|
||||||
|
|
||||||
// reset all timers
|
|
||||||
for (int tmr = 0; tmr < MN10200_NUM_TIMERS_8BIT; tmr++)
|
|
||||||
{
|
|
||||||
m_simple_timer[tmr].mode = 0;
|
|
||||||
m_simple_timer[tmr].cur = 0;
|
|
||||||
m_simple_timer[tmr].base = 0;
|
|
||||||
m_timer_timers[tmr]->adjust(attotime::never, tmr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1640,6 +1643,7 @@ WRITE8_MEMBER(mn10200_device::io_control_w)
|
|||||||
case 0x036: case 0x037: // Memory mode reg 3
|
case 0x036: case 0x037: // Memory mode reg 3
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// 0xfc40-0xfc57: irq control
|
||||||
// group 0, NMI control
|
// group 0, NMI control
|
||||||
case 0x040:
|
case 0x040:
|
||||||
m_nmicr &= data; // nmi ack
|
m_nmicr &= data; // nmi ack
|
||||||
@ -1651,7 +1655,10 @@ WRITE8_MEMBER(mn10200_device::io_control_w)
|
|||||||
case 0x042: case 0x044: case 0x046: case 0x048: case 0x04a:
|
case 0x042: case 0x044: case 0x046: case 0x048: case 0x04a:
|
||||||
case 0x04c: case 0x04e: case 0x050: case 0x052: case 0x054:
|
case 0x04c: case 0x04e: case 0x050: case 0x052: case 0x054:
|
||||||
m_icrl[(offset & 0x3f) >> 1] &= data; // irq ack
|
m_icrl[(offset & 0x3f) >> 1] &= data; // irq ack
|
||||||
if (offset == 0x050) check_ext_irq(); // group 8, external irqs might still be active
|
|
||||||
|
// group 8, external irqs might still be active
|
||||||
|
if (offset == 0x050)
|
||||||
|
check_ext_irq();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x043: case 0x045: case 0x047: case 0x049: case 0x04b:
|
case 0x043: case 0x045: case 0x047: case 0x049: case 0x04b:
|
||||||
@ -1666,7 +1673,7 @@ WRITE8_MEMBER(mn10200_device::io_control_w)
|
|||||||
check_ext_irq();
|
check_ext_irq();
|
||||||
break;
|
break;
|
||||||
case 0x057:
|
case 0x057:
|
||||||
m_extmdh = data;
|
m_extmdh = data & 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x100: case 0x101: // DRAM control reg
|
case 0x100: case 0x101: // DRAM control reg
|
||||||
@ -1717,49 +1724,39 @@ WRITE8_MEMBER(mn10200_device::io_control_w)
|
|||||||
log_event("MN102", "AN chans=0-%d current=%d", (data >> 4) & 7, data & 7);
|
log_event("MN102", "AN chans=0-%d current=%d", (data >> 4) & 7, data & 7);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// 0xfe00-0xfe2f: 8-bit timers
|
||||||
|
// timer base
|
||||||
case 0x210: case 0x211: case 0x212: case 0x213: case 0x214:
|
case 0x210: case 0x211: case 0x212: case 0x213: case 0x214:
|
||||||
case 0x215: case 0x216: case 0x217: case 0x218: case 0x219:
|
case 0x215: case 0x216: case 0x217: case 0x218: case 0x219:
|
||||||
m_simple_timer[offset-0x210].base = data + 1;
|
m_simple_timer[offset & 0xf].base = data;
|
||||||
// printf("MN10200: Timer %d value set %02x\n", offset-0x210, data);
|
|
||||||
refresh_timer(offset-0x210);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x21a:
|
// prescaler base
|
||||||
m_prescaler[0].cycles = data+1;
|
case 0x21a: case 0x21b:
|
||||||
// printf("MN10200: Prescale 0 cycle count %d\n", data+1);
|
m_prescaler[offset & 1].base = data;
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x21b:
|
|
||||||
m_prescaler[1].cycles = data+1;
|
|
||||||
// printf("MN10200: Prescale 1 cycle count %d\n", data+1);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// timer mode
|
||||||
case 0x220: case 0x221: case 0x222: case 0x223: case 0x224:
|
case 0x220: case 0x221: case 0x222: case 0x223: case 0x224:
|
||||||
case 0x225: case 0x226: case 0x227: case 0x228: case 0x229:
|
case 0x225: case 0x226: case 0x227: case 0x228: case 0x229:
|
||||||
{
|
m_simple_timer[offset & 0xf].mode = data & 0xc3;
|
||||||
// const char *source[4] = { "TMxIO", "cascade", "prescale 0", "prescale 1" };
|
|
||||||
m_simple_timer[offset-0x220].mode = data;
|
|
||||||
// printf("MN10200: Timer %d %s b6=%d, source=%s\n", offset-0x220, data & 0x80 ? "on" : "off", (data & 0x40) != 0, source[data & 3]);
|
|
||||||
|
|
||||||
|
// reload
|
||||||
if (data & 0x40)
|
if (data & 0x40)
|
||||||
{
|
m_simple_timer[offset & 0xf].cur = m_simple_timer[offset & 0xf].base;
|
||||||
// printf("MN10200: loading timer %d\n", offset-0x220);
|
|
||||||
m_simple_timer[offset-0x220].cur = m_simple_timer[offset-0x220].base;
|
|
||||||
}
|
|
||||||
refresh_timer(offset-0x220);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x22a:
|
refresh_timer(offset & 0xf);
|
||||||
// printf("MN10200: Prescale 0 %s, ps0bc %s\n",
|
|
||||||
// data & 0x80 ? "on" : "off", data & 0x40 ? "-> ps0br" : "off");
|
|
||||||
m_prescaler[0].mode = data;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x22b:
|
// prescaler mode
|
||||||
// printf("MN10200: Prescale 1 %s, ps1bc %s\n",
|
case 0x22a: case 0x22b:
|
||||||
// data & 0x80 ? "on" : "off", data & 0x40 ? "-> ps1br" : "off");
|
m_prescaler[offset & 1].mode = data & 0xc0;
|
||||||
m_prescaler[1].mode = data;
|
|
||||||
|
// reload
|
||||||
|
if (data & 0x40)
|
||||||
|
m_prescaler[offset & 1].cur = m_prescaler[offset & 1].base;
|
||||||
|
|
||||||
|
refresh_all_timers();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x230: case 0x240: case 0x250:
|
case 0x230: case 0x240: case 0x250:
|
||||||
@ -2044,11 +2041,13 @@ READ8_MEMBER(mn10200_device::io_control_r)
|
|||||||
{
|
{
|
||||||
switch(offset)
|
switch(offset)
|
||||||
{
|
{
|
||||||
|
// active irq group
|
||||||
case 0x00e:
|
case 0x00e:
|
||||||
return m_iagr << 1;
|
return m_iagr << 1;
|
||||||
case 0x00f:
|
case 0x00f:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// 0xfc40-0xfc57: irq control
|
||||||
// group 0, NMI control
|
// group 0, NMI control
|
||||||
case 0x040:
|
case 0x040:
|
||||||
return m_nmicr;
|
return m_nmicr;
|
||||||
@ -2069,7 +2068,7 @@ READ8_MEMBER(mn10200_device::io_control_r)
|
|||||||
case 0x056:
|
case 0x056:
|
||||||
return m_extmdl;
|
return m_extmdl;
|
||||||
case 0x057:
|
case 0x057:
|
||||||
return (m_extmdh & 3) | (m_p4 << 4);
|
return m_extmdh | (m_p4 << 4);
|
||||||
|
|
||||||
case 0x180: case 0x190:
|
case 0x180: case 0x190:
|
||||||
return m_serial[(offset-0x180) >> 4].ctrll;
|
return m_serial[(offset-0x180) >> 4].ctrll;
|
||||||
@ -2086,10 +2085,33 @@ READ8_MEMBER(mn10200_device::io_control_r)
|
|||||||
case 0x183:
|
case 0x183:
|
||||||
return 0x10;
|
return 0x10;
|
||||||
|
|
||||||
|
// 0xfe00-0xfe2f: 8-bit timers
|
||||||
|
// timer counter (not accurate)
|
||||||
case 0x200: case 0x201: case 0x202: case 0x203: case 0x204:
|
case 0x200: case 0x201: case 0x202: case 0x203: case 0x204:
|
||||||
case 0x205: case 0x206: case 0x207: case 0x208: case 0x209:
|
case 0x205: case 0x206: case 0x207: case 0x208: case 0x209:
|
||||||
// printf("MN10200: timer %d value read = %d\n", offset-0x200, m_simple_timer[offset-0x200].cur);
|
return m_simple_timer[offset & 0xf].cur;
|
||||||
return m_simple_timer[offset-0x200].cur;
|
|
||||||
|
// prescaler counter (not accurate)
|
||||||
|
case 0x20a: case 0x20b:
|
||||||
|
return m_prescaler[offset & 1].cur;
|
||||||
|
|
||||||
|
// timer base
|
||||||
|
case 0x210: case 0x211: case 0x212: case 0x213: case 0x214:
|
||||||
|
case 0x215: case 0x216: case 0x217: case 0x218: case 0x219:
|
||||||
|
return m_simple_timer[offset & 0xf].base;
|
||||||
|
|
||||||
|
// prescaler base
|
||||||
|
case 0x21a: case 0x21b:
|
||||||
|
return m_prescaler[offset & 1].base;
|
||||||
|
|
||||||
|
// timer mode
|
||||||
|
case 0x220: case 0x221: case 0x222: case 0x223: case 0x224:
|
||||||
|
case 0x225: case 0x226: case 0x227: case 0x228: case 0x229:
|
||||||
|
return m_simple_timer[offset & 0xf].mode;
|
||||||
|
|
||||||
|
// prescaler mode
|
||||||
|
case 0x22a: case 0x22b:
|
||||||
|
return m_prescaler[offset & 1].mode;
|
||||||
|
|
||||||
case 0x264: // port 1 data
|
case 0x264: // port 1 data
|
||||||
return m_io->read_byte(MN10200_PORT1);
|
return m_io->read_byte(MN10200_PORT1);
|
||||||
|
@ -71,8 +71,10 @@ protected:
|
|||||||
virtual void device_reset();
|
virtual void device_reset();
|
||||||
|
|
||||||
// device_execute_interface overrides
|
// device_execute_interface overrides
|
||||||
|
virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 2 - 1) / 2; }
|
||||||
|
virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); }
|
||||||
virtual UINT32 execute_min_cycles() const { return 1; }
|
virtual UINT32 execute_min_cycles() const { return 1; }
|
||||||
virtual UINT32 execute_max_cycles() const { return 8; }
|
virtual UINT32 execute_max_cycles() const { return 13; }
|
||||||
virtual UINT32 execute_input_lines() const { return 4; }
|
virtual UINT32 execute_input_lines() const { return 4; }
|
||||||
virtual void execute_run();
|
virtual void execute_run();
|
||||||
virtual void execute_set_input(int inputnum, int state);
|
virtual void execute_set_input(int inputnum, int state);
|
||||||
@ -119,8 +121,9 @@ private:
|
|||||||
emu_timer *m_timer_timers[MN10200_NUM_TIMERS_8BIT];
|
emu_timer *m_timer_timers[MN10200_NUM_TIMERS_8BIT];
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
UINT8 cycles;
|
|
||||||
UINT8 mode;
|
UINT8 mode;
|
||||||
|
UINT8 base;
|
||||||
|
UINT8 cur;
|
||||||
} m_prescaler[MN10200_NUM_PRESCALERS];
|
} m_prescaler[MN10200_NUM_PRESCALERS];
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@ -140,6 +143,7 @@ private:
|
|||||||
|
|
||||||
UINT8 m_ddr[8];
|
UINT8 m_ddr[8];
|
||||||
|
|
||||||
|
attotime m_sysclock_base;
|
||||||
int m_cycles;
|
int m_cycles;
|
||||||
|
|
||||||
address_space *m_program;
|
address_space *m_program;
|
||||||
@ -164,7 +168,8 @@ private:
|
|||||||
bool check_irq();
|
bool check_irq();
|
||||||
void check_ext_irq();
|
void check_ext_irq();
|
||||||
void refresh_timer(int tmr);
|
void refresh_timer(int tmr);
|
||||||
void timer_tick_simple(int tmr);
|
void refresh_all_timers();
|
||||||
|
int timer_tick_simple(int tmr);
|
||||||
TIMER_CALLBACK_MEMBER( simple_timer_cb );
|
TIMER_CALLBACK_MEMBER( simple_timer_cb );
|
||||||
void illegal(UINT8 prefix, UINT8 op);
|
void illegal(UINT8 prefix, UINT8 op);
|
||||||
UINT32 do_add(UINT32 a, UINT32 b, UINT32 c);
|
UINT32 do_add(UINT32 a, UINT32 b, UINT32 c);
|
||||||
|
Loading…
Reference in New Issue
Block a user