diff --git a/src/emu/cpu/mn10200/mn10200.c b/src/emu/cpu/mn10200/mn10200.c index c37f15d0bdf..1c490243bcf 100644 --- a/src/emu/cpu/mn10200/mn10200.c +++ b/src/emu/cpu/mn10200/mn10200.c @@ -85,7 +85,8 @@ bool mn10200_device::check_irq() take_irq(0, 0); else if (group) take_irq(level, group); - else return false; + else + return false; return true; } @@ -105,75 +106,82 @@ void mn10200_device::check_ext_irq() void mn10200_device::refresh_timer(int tmr) { - // enabled? - if (m_simple_timer[tmr].mode & 0x80) + // 0: external pin + // 1: cascaded (handled elsewhere) + // 2: prescaler 0 + // 3: prescaler 1 + int p = m_simple_timer[tmr].mode & 1; + + // enabled, and source is prescaler? + if ((m_simple_timer[tmr].mode & 0x82) == 0x82 && m_simple_timer[tmr].cur != 0 && m_prescaler[p].mode & 0x80) { - UINT8 source = (m_simple_timer[tmr].mode & 3); - - // source is a prescaler? - if (source >= 2) - { - INT32 rate; - - // 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 - { - logerror("MN10200: timer %d using prescaler %d which isn't enabled!\n", tmr, source-2); - } - } + attotime period = m_sysclock_base * (m_prescaler[p].base + 1) * (m_simple_timer[tmr].cur + 1); + m_timer_timers[tmr]->adjust(period, tmr); } - else // disabled, so stop it + else { 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? - if (m_simple_timer[tmr].cur == 0) +int mn10200_device::timer_tick_simple(int tmr) +{ + 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. - m_simple_timer[tmr].cur = m_simple_timer[tmr].base; - - // signal the cascade if we're not timer 9 - if (tmr < (MN10200_NUM_TIMERS_8BIT-1)) + // did it underflow? + if (--m_simple_timer[next].cur == 0xff) { - // is next timer enabled? - if (m_simple_timer[tmr+1].mode & 0x80) + // cascaded underflow? + if (timer_tick_simple(next) != 2) { - // is it's source "cascade"? - if ((m_simple_timer[tmr+1].mode & 0x3) == 1) - { - // recurse! - timer_tick_simple(tmr+1); - } + m_simple_timer[next].cur = m_simple_timer[next].base; + return 1; } } - - m_icrl[1 + (tmr / 4)] |= (1 << (4 + (tmr % 4))); + + return 2; + } + else + { + // reload and trigger irq + m_simple_timer[tmr].cur = m_simple_timer[tmr].base; + m_icrl[1 + (tmr >> 2)] |= (1 << (4 + (tmr & 3))); check_irq(); + + return 0; } } TIMER_CALLBACK_MEMBER( mn10200_device::simple_timer_cb ) { int tmr = param; - + // handle our expiring and also tick our cascaded children - m_simple_timer[tmr].cur = 1; - timer_tick_simple(tmr); + switch (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_timer(tmr); @@ -186,6 +194,8 @@ void mn10200_device::device_start() m_program = &space(AS_PROGRAM); m_io = &space(AS_IO); + m_sysclock_base = attotime::from_hz(unscaled_clock() / 2); + 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)); @@ -210,11 +220,13 @@ void mn10200_device::device_start() } for (int i = 0; i < MN10200_NUM_PRESCALERS; i++) { - m_prescaler[i].cycles = 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].base), i); + save_item(NAME(m_prescaler[i].cur), 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 address = 0xfc04; address < 0x10000; address++) 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 break; + // 0xfc40-0xfc57: irq control // group 0, NMI control case 0x040: 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 0x04c: case 0x04e: case 0x050: case 0x052: case 0x054: 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; case 0x043: case 0x045: case 0x047: case 0x049: case 0x04b: @@ -1666,7 +1673,7 @@ WRITE8_MEMBER(mn10200_device::io_control_w) check_ext_irq(); break; case 0x057: - m_extmdh = data; + m_extmdh = data & 3; break; 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); break; + // 0xfe00-0xfe2f: 8-bit timers + // timer base case 0x210: case 0x211: case 0x212: case 0x213: case 0x214: case 0x215: case 0x216: case 0x217: case 0x218: case 0x219: - m_simple_timer[offset-0x210].base = data + 1; - // printf("MN10200: Timer %d value set %02x\n", offset-0x210, data); - refresh_timer(offset-0x210); + m_simple_timer[offset & 0xf].base = data; break; - case 0x21a: - m_prescaler[0].cycles = data+1; - // printf("MN10200: Prescale 0 cycle count %d\n", data+1); - break; - - case 0x21b: - m_prescaler[1].cycles = data+1; - // printf("MN10200: Prescale 1 cycle count %d\n", data+1); + // prescaler base + case 0x21a: case 0x21b: + m_prescaler[offset & 1].base = data; break; + // timer mode case 0x220: case 0x221: case 0x222: case 0x223: case 0x224: case 0x225: case 0x226: case 0x227: case 0x228: case 0x229: - { - // 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]); + m_simple_timer[offset & 0xf].mode = data & 0xc3; + // reload if (data & 0x40) - { - // 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; - } + m_simple_timer[offset & 0xf].cur = m_simple_timer[offset & 0xf].base; - case 0x22a: - // printf("MN10200: Prescale 0 %s, ps0bc %s\n", - // data & 0x80 ? "on" : "off", data & 0x40 ? "-> ps0br" : "off"); - m_prescaler[0].mode = data; + refresh_timer(offset & 0xf); break; - case 0x22b: - // printf("MN10200: Prescale 1 %s, ps1bc %s\n", - // data & 0x80 ? "on" : "off", data & 0x40 ? "-> ps1br" : "off"); - m_prescaler[1].mode = data; + // prescaler mode + case 0x22a: case 0x22b: + m_prescaler[offset & 1].mode = data & 0xc0; + + // reload + if (data & 0x40) + m_prescaler[offset & 1].cur = m_prescaler[offset & 1].base; + + refresh_all_timers(); break; case 0x230: case 0x240: case 0x250: @@ -2044,11 +2041,13 @@ READ8_MEMBER(mn10200_device::io_control_r) { switch(offset) { + // active irq group case 0x00e: return m_iagr << 1; case 0x00f: return 0; + // 0xfc40-0xfc57: irq control // group 0, NMI control case 0x040: return m_nmicr; @@ -2069,7 +2068,7 @@ READ8_MEMBER(mn10200_device::io_control_r) case 0x056: return m_extmdl; case 0x057: - return (m_extmdh & 3) | (m_p4 << 4); + return m_extmdh | (m_p4 << 4); case 0x180: case 0x190: return m_serial[(offset-0x180) >> 4].ctrll; @@ -2086,10 +2085,33 @@ READ8_MEMBER(mn10200_device::io_control_r) case 0x183: return 0x10; + // 0xfe00-0xfe2f: 8-bit timers + // timer counter (not accurate) case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: 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-0x200].cur; + return m_simple_timer[offset & 0xf].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 return m_io->read_byte(MN10200_PORT1); @@ -2112,7 +2134,7 @@ READ8_MEMBER(mn10200_device::io_control_r) default: log_event("MN102", "internal_r %04x (%03x)", offset+0xfc00, adr); } - + return 0; } diff --git a/src/emu/cpu/mn10200/mn10200.h b/src/emu/cpu/mn10200/mn10200.h index c8923162348..7fad19997c6 100644 --- a/src/emu/cpu/mn10200/mn10200.h +++ b/src/emu/cpu/mn10200/mn10200.h @@ -71,8 +71,10 @@ protected: virtual void device_reset(); // 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_max_cycles() const { return 8; } + virtual UINT32 execute_max_cycles() const { return 13; } virtual UINT32 execute_input_lines() const { return 4; } virtual void execute_run(); virtual void execute_set_input(int inputnum, int state); @@ -119,8 +121,9 @@ private: emu_timer *m_timer_timers[MN10200_NUM_TIMERS_8BIT]; struct { - UINT8 cycles; UINT8 mode; + UINT8 base; + UINT8 cur; } m_prescaler[MN10200_NUM_PRESCALERS]; struct { @@ -140,6 +143,7 @@ private: UINT8 m_ddr[8]; + attotime m_sysclock_base; int m_cycles; address_space *m_program; @@ -164,7 +168,8 @@ private: bool check_irq(); void check_ext_irq(); 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 ); void illegal(UINT8 prefix, UINT8 op); UINT32 do_add(UINT32 a, UINT32 b, UINT32 c);