From 555bfc95cc92b2f6fad606a81bcf4c93aa266115 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Mon, 16 Jan 2017 12:11:18 +1100 Subject: [PATCH] m68705: re-implement timer/counter * Support MOR-controlled mode * Correct count direction * Correct startup and reset states a2bus/mouse.cpp: use new MC68705P3 core and remove obsolete glue * the card works before and after the change, but by default axes are only mapped to inc/dec keys, not host mouse quizpun: use new MC68705P5 core, MCU now gets timer interrupts correctly --- src/devices/bus/a2bus/mouse.cpp | 198 +++---------------------- src/devices/bus/a2bus/mouse.h | 25 +--- src/devices/cpu/m6805/m6805.cpp | 10 +- src/devices/cpu/m6805/m6805.h | 3 + src/devices/cpu/m6805/m68705.cpp | 241 +++++++++++++++++-------------- src/devices/cpu/m6805/m68705.h | 73 ++++++---- src/mame/drivers/m68705prg.cpp | 3 +- src/mame/drivers/quizpun2.cpp | 57 ++++---- 8 files changed, 241 insertions(+), 369 deletions(-) diff --git a/src/devices/bus/a2bus/mouse.cpp b/src/devices/bus/a2bus/mouse.cpp index fa0f8377007..6c0c7410c9a 100644 --- a/src/devices/bus/a2bus/mouse.cpp +++ b/src/devices/bus/a2bus/mouse.cpp @@ -78,35 +78,22 @@ const device_type A2BUS_MOUSE = &device_creator; #define MOUSE_ROM_REGION "a2mse_rom" #define MOUSE_PIA_TAG "a2mse_pia" #define MOUSE_MCU_TAG "a2mse_mcu" -#define MOUSE_MCU_ROM "a2mse_mcurom" #define MOUSE_BUTTON_TAG "a2mse_button" #define MOUSE_XAXIS_TAG "a2mse_x" #define MOUSE_YAXIS_TAG "a2mse_y" -#define TIMER_68705 0 -#define TIMER_QUADRATURE 1 - -static ADDRESS_MAP_START( mcu_mem, AS_PROGRAM, 8, a2bus_mouse_device ) - ADDRESS_MAP_GLOBAL_MASK(0x7ff) - AM_RANGE(0x0000, 0x0000) AM_READWRITE(mcu_port_a_r, mcu_port_a_w) - AM_RANGE(0x0001, 0x0001) AM_READWRITE(mcu_port_b_r, mcu_port_b_w) - AM_RANGE(0x0002, 0x0002) AM_READWRITE(mcu_port_c_r, mcu_port_c_w) - AM_RANGE(0x0004, 0x0004) AM_WRITE(mcu_ddr_a_w) - AM_RANGE(0x0005, 0x0005) AM_WRITE(mcu_ddr_b_w) - AM_RANGE(0x0006, 0x0006) AM_WRITE(mcu_ddr_c_w) - AM_RANGE(0x0008, 0x0009) AM_READWRITE(mcu_timer_r, mcu_timer_w) - AM_RANGE(0x0010, 0x007f) AM_RAM - AM_RANGE(0x0080, 0x07ff) AM_ROM AM_REGION(MOUSE_MCU_ROM, 0x80) -ADDRESS_MAP_END +#define TIMER_QUADRATURE 0 MACHINE_CONFIG_FRAGMENT( mouse ) - MCFG_CPU_ADD(MOUSE_MCU_TAG, M68705, 2043600) - MCFG_CPU_PROGRAM_MAP(mcu_mem) + MCFG_CPU_ADD(MOUSE_MCU_TAG, M68705P3, 2043600) + MCFG_M68705_PORTA_R_CB(READ8(a2bus_mouse_device, mcu_port_a_r)) + MCFG_M68705_PORTB_R_CB(READ8(a2bus_mouse_device, mcu_port_b_r)) + MCFG_M68705_PORTA_W_CB(WRITE8(a2bus_mouse_device, mcu_port_a_w)) + MCFG_M68705_PORTB_W_CB(WRITE8(a2bus_mouse_device, mcu_port_b_w)) + MCFG_M68705_PORTC_W_CB(WRITE8(a2bus_mouse_device, mcu_port_c_w)) MCFG_DEVICE_ADD(MOUSE_PIA_TAG, PIA6821, 1021800) - MCFG_PIA_READPA_HANDLER(READ8(a2bus_mouse_device, pia_in_a)) - MCFG_PIA_READPB_HANDLER(READ8(a2bus_mouse_device, pia_in_b)) MCFG_PIA_WRITEPA_HANDLER(WRITE8(a2bus_mouse_device, pia_out_a)) MCFG_PIA_WRITEPB_HANDLER(WRITE8(a2bus_mouse_device, pia_out_b)) MCFG_PIA_IRQA_HANDLER(WRITELINE(a2bus_mouse_device, pia_irqa_w)) @@ -117,7 +104,7 @@ ROM_START( mouse ) ROM_REGION(0x800, MOUSE_ROM_REGION, 0) ROM_LOAD( "341-0270-c.4b", 0x000000, 0x000800, CRC(0bcd1e8e) SHA1(3a9d881a8a8d30f55b9719aceebbcf717f829d6f) ) - ROM_REGION(0x800, MOUSE_MCU_ROM, 0) + ROM_REGION(0x800, MOUSE_MCU_TAG, 0) ROM_LOAD( "341-0269.2b", 0x000000, 0x000800, CRC(94067f16) SHA1(3a2baa6648efe4456d3ec3721216e57c64f7acfc) ) ROM_REGION(0xc00, "pal", 0) @@ -177,25 +164,18 @@ a2bus_mouse_device::a2bus_mouse_device(const machine_config &mconfig, device_typ device_a2bus_card_interface(mconfig, *this), m_pia(*this, MOUSE_PIA_TAG), m_mcu(*this, MOUSE_MCU_TAG), - m_mouseb(*this, MOUSE_BUTTON_TAG), - m_mousex(*this, MOUSE_XAXIS_TAG), - m_mousey(*this, MOUSE_YAXIS_TAG), m_rom(nullptr), m_ddr_a(0), m_ddr_b(0), m_ddr_c(0), m_port_a_out(0), m_port_b_out(0), m_port_c_out(0), m_port_a_in(0), m_port_b_in(0), - m_port_c_in(0), m_timer_cnt(0), m_timer_ctl(0), m_mask_option(0), last_mx(0), last_my(0), count_x(0), count_y(0), m_timer(nullptr), m_read_timer(nullptr) + m_mouseb(*this, MOUSE_BUTTON_TAG), m_mousex(*this, MOUSE_XAXIS_TAG), m_mousey(*this, MOUSE_YAXIS_TAG), + m_rom(*this, MOUSE_ROM_REGION), + m_port_a_in(0), m_port_b_in(0), + last_mx(0), last_my(0), count_x(0), count_y(0), + m_read_timer(nullptr) { - m_started = false; m_rom_bank = 0; } a2bus_mouse_device::a2bus_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, A2BUS_MOUSE, "Apple II Mouse Card", tag, owner, clock, "a2mouse", __FILE__), - device_a2bus_card_interface(mconfig, *this), - m_pia(*this, MOUSE_PIA_TAG), - m_mcu(*this, MOUSE_MCU_TAG), - m_mouseb(*this, MOUSE_BUTTON_TAG), - m_mousex(*this, MOUSE_XAXIS_TAG), - m_mousey(*this, MOUSE_YAXIS_TAG), m_rom(nullptr), m_ddr_a(0), m_ddr_b(0), m_ddr_c(0), m_port_a_out(0), m_port_b_out(0), m_port_c_out(0), m_port_a_in(0), m_port_b_in(0), m_port_c_in(0), m_timer_cnt(0), m_timer_ctl(0), m_mask_option(0), last_mx(0), last_my(0), count_x(0), count_y(0), m_timer(nullptr), m_read_timer(nullptr) + a2bus_mouse_device(mconfig, A2BUS_MOUSE, "Apple II Mouse Card", tag, owner, clock, "a2mouse", __FILE__) { - m_started = false; m_rom_bank = 0; } @@ -208,29 +188,13 @@ void a2bus_mouse_device::device_start() // set_a2bus_device makes m_slot valid set_a2bus_device(); - m_rom = device().machine().root_device().memregion(this->subtag(MOUSE_ROM_REGION).c_str())->base(); - - // allocate two timers: one for the 68705, one for the quadrature magic - m_timer = timer_alloc(TIMER_68705, nullptr); + // allocate a timer for the quadrature magic m_read_timer = timer_alloc(TIMER_QUADRATURE, nullptr); - m_timer->adjust(attotime::never, TIMER_68705); m_read_timer->adjust(attotime::never, TIMER_QUADRATURE); - // get 68705P3 mask option byte - m_mask_option = m_rom[0x784]; - // register save state variables - save_item(NAME(m_ddr_a)); - save_item(NAME(m_ddr_b)); - save_item(NAME(m_ddr_c)); - save_item(NAME(m_port_a_out)); - save_item(NAME(m_port_b_out)); - save_item(NAME(m_port_c_out)); save_item(NAME(m_port_a_in)); save_item(NAME(m_port_b_in)); - save_item(NAME(m_port_c_in)); - save_item(NAME(m_timer_cnt)); - save_item(NAME(m_timer_ctl)); save_item(NAME(last_mx)); save_item(NAME(last_my)); save_item(NAME(count_x)); @@ -239,20 +203,10 @@ void a2bus_mouse_device::device_start() void a2bus_mouse_device::device_reset() { - m_started = true; m_rom_bank = 0; last_mx = last_my = count_x = count_y = 0; - m_timer_cnt = 0xff; - m_timer_ctl = 0x40; // disable interrupt, everything else clear m_port_a_in = 0; m_port_b_in = 0x80; - m_port_c_in = 0; - - // are we emulating the mask part with a semi-programmable timer? - if (m_mask_option & 0x40) - { - m_timer_ctl |= m_mask_option & 0x17; - } m_read_timer->adjust(attotime::from_hz(600.0), TIMER_QUADRATURE, attotime::from_hz(600.0)); } @@ -285,16 +239,6 @@ uint8_t a2bus_mouse_device::read_cnxx(address_space &space, uint8_t offset) return m_rom[offset+m_rom_bank]; } -READ8_MEMBER(a2bus_mouse_device::pia_in_a) -{ - return m_port_a_out; -} - -READ8_MEMBER(a2bus_mouse_device::pia_in_b) -{ - return (m_port_c_out << 4); -} - WRITE8_MEMBER(a2bus_mouse_device::pia_out_a) { m_port_a_in = data; @@ -302,8 +246,7 @@ WRITE8_MEMBER(a2bus_mouse_device::pia_out_a) WRITE8_MEMBER(a2bus_mouse_device::pia_out_b) { - m_port_c_in &= 0xf0; - m_port_c_in |= ((data >> 4) & 0xf); + m_mcu->pc_w(space, 0, 0xf0 | ((data >> 4) & 0x0f)); m_rom_bank = (data & 0xe) << 7; } @@ -318,17 +261,12 @@ WRITE_LINE_MEMBER(a2bus_mouse_device::pia_irqb_w) READ8_MEMBER(a2bus_mouse_device::mcu_port_a_r) { - return (m_port_a_out & m_ddr_a) | (m_port_a_in & ~m_ddr_a); + return m_port_a_in; } WRITE8_MEMBER(a2bus_mouse_device::mcu_port_a_w) { - m_port_a_out = data; -} - -WRITE8_MEMBER(a2bus_mouse_device::mcu_ddr_a_w) -{ - m_ddr_a = data; + m_pia->set_a_input(data, ~mem_mask); } READ8_MEMBER(a2bus_mouse_device::mcu_port_b_r) @@ -338,14 +276,12 @@ READ8_MEMBER(a2bus_mouse_device::mcu_port_b_r) // clear the gates, leave everything else alone between pulses m_port_b_in &= 0x85; - return (m_port_b_out & m_ddr_b) | (b_in & ~m_ddr_b); + return b_in; } WRITE8_MEMBER(a2bus_mouse_device::mcu_port_b_w) { - m_port_b_out = data; - - if (!(data & 0x40)) + if (!BIT(data, 6)) { raise_slot_irq(); } @@ -355,91 +291,9 @@ WRITE8_MEMBER(a2bus_mouse_device::mcu_port_b_w) } } -WRITE8_MEMBER(a2bus_mouse_device::mcu_ddr_b_w) -{ - m_ddr_b = data; -} - -READ8_MEMBER(a2bus_mouse_device::mcu_port_c_r) -{ - return (m_port_c_out & m_ddr_c) | (m_port_c_in & ~m_ddr_c); -} - WRITE8_MEMBER(a2bus_mouse_device::mcu_port_c_w) { - m_port_c_out = data; -} - -WRITE8_MEMBER(a2bus_mouse_device::mcu_ddr_c_w) -{ - m_ddr_c = data; -} - -READ8_MEMBER(a2bus_mouse_device::mcu_timer_r) -{ - if (offset == 1) - { - return m_timer_ctl; - } - - return m_timer_cnt; -} - -WRITE8_MEMBER(a2bus_mouse_device::mcu_timer_w) -{ - static const int prescale[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; - bool recalc = false; - - // offset 0 = timer data (counts down) - if (offset == 0) - { - m_timer_cnt = data; - recalc = true; - } - // offset 1 = timer control: b7 = IRQ, b6 = IRQ mask (1=suppress), - // b5 = input select (0=CPU clk, 1=ext), - // b4 = enable external timer input, - // b3 = clear, b2-b0 = scaler (1/2/4/8/16/32/64/128) - else - { - // clearing the interrupt? - if ((m_timer_ctl & 0x80) && !(data & 0x80)) - { - m_mcu->set_input_line(M68705_INT_TIMER, CLEAR_LINE); - } - - if (m_mask_option & 0x40) - { - m_timer_ctl &= 0x3f; - m_timer_ctl |= (data & 0xc0); - } - else - { - // if any parameters that affect the timer changed, recalc now - if ((data & 0x3f) != (m_timer_ctl & 0x3f)) - { - recalc = true; - } - - // if prescaler reset, recalc - if (data & 0x8) - { - recalc = true; - } - - m_timer_ctl = data; - } - - } - - if (recalc) - { - // recalculate the timer now - uint32_t m_ticks = 2043600 / 4; - m_ticks /= prescale[m_timer_ctl & 7]; - m_ticks /= (int)(m_timer_cnt + 1); - m_timer->adjust(attotime::from_hz((double)m_ticks), TIMER_68705, attotime::from_hz((double)m_ticks)); - } + m_pia->portb_w(data << 4); } /* @@ -452,15 +306,7 @@ WRITE8_MEMBER(a2bus_mouse_device::mcu_timer_w) */ void a2bus_mouse_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { - if (id == TIMER_68705) // 68705's built-in timer - { - m_timer_ctl |= 0x80; // indicate timer expired - if (!(m_timer_ctl & 0x40)) // if interrupt not suppressed, fire! - { - m_mcu->set_input_line(M68705_INT_TIMER, ASSERT_LINE); - } - } - else if (id == TIMER_QUADRATURE) + if (id == TIMER_QUADRATURE) { int new_mx, new_my; m_port_b_in = 0x80; diff --git a/src/devices/bus/a2bus/mouse.h b/src/devices/bus/a2bus/mouse.h index 5eead183edb..c5a36319d79 100644 --- a/src/devices/bus/a2bus/mouse.h +++ b/src/devices/bus/a2bus/mouse.h @@ -35,8 +35,6 @@ public: virtual ioport_constructor device_input_ports() const override; virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - DECLARE_READ8_MEMBER(pia_in_a); - DECLARE_READ8_MEMBER(pia_in_b); DECLARE_WRITE8_MEMBER(pia_out_a); DECLARE_WRITE8_MEMBER(pia_out_b); DECLARE_WRITE_LINE_MEMBER(pia_irqa_w); @@ -44,15 +42,9 @@ public: DECLARE_READ8_MEMBER(mcu_port_a_r); DECLARE_READ8_MEMBER(mcu_port_b_r); - DECLARE_READ8_MEMBER(mcu_port_c_r); DECLARE_WRITE8_MEMBER(mcu_port_a_w); DECLARE_WRITE8_MEMBER(mcu_port_b_w); DECLARE_WRITE8_MEMBER(mcu_port_c_w); - DECLARE_WRITE8_MEMBER(mcu_ddr_a_w); - DECLARE_WRITE8_MEMBER(mcu_ddr_b_w); - DECLARE_WRITE8_MEMBER(mcu_ddr_c_w); - DECLARE_READ8_MEMBER(mcu_timer_r); - DECLARE_WRITE8_MEMBER(mcu_timer_w); protected: virtual void device_start() override; @@ -64,27 +56,16 @@ protected: virtual uint8_t read_cnxx(address_space &space, uint8_t offset) override; required_device m_pia; - required_device m_mcu; + required_device m_mcu; required_ioport m_mouseb, m_mousex, m_mousey; private: - uint8_t *m_rom; - bool m_started; + required_region_ptr m_rom; int m_rom_bank; - uint8_t m_ddr_a; - uint8_t m_ddr_b; - uint8_t m_ddr_c; - uint8_t m_port_a_out; - uint8_t m_port_b_out; - uint8_t m_port_c_out; uint8_t m_port_a_in; uint8_t m_port_b_in; - uint8_t m_port_c_in; - uint8_t m_timer_cnt; - uint8_t m_timer_ctl; - uint8_t m_mask_option; int last_mx, last_my, count_x, count_y; - emu_timer *m_timer, *m_read_timer; + emu_timer *m_read_timer; }; // device type definition diff --git a/src/devices/cpu/m6805/m6805.cpp b/src/devices/cpu/m6805/m6805.cpp index fbd99f7e82f..bc1844f5bbf 100644 --- a/src/devices/cpu/m6805/m6805.cpp +++ b/src/devices/cpu/m6805/m6805.cpp @@ -235,6 +235,7 @@ void m6805_base_device::interrupt() m_pending_interrupts &= ~(1 << HD63705_INT_NMI); m_icount -= 11; + burn_cycles(11); } else if((m_pending_interrupts & ((1 << M6805_IRQ_LINE) | HD63705_INT_MASK)) != 0) { @@ -254,6 +255,7 @@ void m6805_base_device::interrupt() m_pending_interrupts &= ~(1 << M6805_IRQ_LINE); } m_icount -= 11; + burn_cycles(11); } } @@ -498,9 +500,9 @@ void m6805_base_device::execute_run() debugger_instruction_hook(this, PC); - ireg=M_RDOP(PC++); + ireg = M_RDOP(PC++); - switch( ireg ) + switch (ireg) { case 0x00: brset(0x01); break; case 0x01: brclr(0x01); break; @@ -764,7 +766,9 @@ void m6805_base_device::execute_run() case 0xff: stx_ix(); break; } m_icount -= m_cycles1[ireg]; - } while( m_icount > 0 ); + burn_cycles(m_cycles1[ireg]); + } + while (m_icount > 0); } /**************************************************************************** diff --git a/src/devices/cpu/m6805/m6805.h b/src/devices/cpu/m6805/m6805.h index 6a65920c6d9..5d0dfede083 100644 --- a/src/devices/cpu/m6805/m6805.h +++ b/src/devices/cpu/m6805/m6805.h @@ -52,6 +52,9 @@ protected: // device_state_interface overrides virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + // for devices with timing-sensitive peripherals + virtual void burn_cycles(unsigned count) { } + private: // opcode/condition tables static const uint8_t m_flags8i[256]; diff --git a/src/devices/cpu/m6805/m68705.cpp b/src/devices/cpu/m6805/m68705.cpp index 3e273102442..b678954e386 100644 --- a/src/devices/cpu/m6805/m68705.cpp +++ b/src/devices/cpu/m6805/m68705.cpp @@ -244,6 +244,9 @@ m68705_new_device::m68705_new_device( , m_port_ddr{ 0x00, 0x00, 0x00, 0x00 } , m_port_cb_r{ { *this }, { *this }, { *this }, { *this } } , m_port_cb_w{ { *this }, { *this }, { *this }, { *this } } + , m_prescaler(0x7f) + , m_tdr(0xff) + , m_tcr(0x7f) , m_vihtp(CLEAR_LINE) , m_pcr(0xff) , m_pl_data(0xff) @@ -254,15 +257,15 @@ m68705_new_device::m68705_new_device( template READ8_MEMBER(m68705_new_device::eprom_r) { // read locked out when /VPON and /PLE are asserted - return (BIT(m_pcr, 2) || BIT(m_pcr, 0)) ? m_user_rom[B + offset] : 0xff; + return (!pcr_vpon() || !pcr_ple()) ? m_user_rom[B + offset] : 0xff; } template WRITE8_MEMBER(m68705_new_device::eprom_w) { // programming latch enabled when /VPON and /PLE are asserted - if (!BIT(m_pcr, 2) && !BIT(m_pcr, 0)) + if (pcr_vpon() && pcr_ple()) { - if (BIT(m_pcr, 1)) + if (!pcr_pge()) { m_pl_data = data; m_pl_addr = B + offset; @@ -317,6 +320,65 @@ template void m68705_new_device::port_cb_w() m_port_cb_w[N](space(AS_PROGRAM), 0, data, mask); } +READ8_MEMBER(m68705_new_device::tdr_r) +{ + return m_tdr; +} + +WRITE8_MEMBER(m68705_new_device::tdr_w) +{ + m_tdr = data; +} + +READ8_MEMBER(m68705_new_device::tcr_r) +{ + // in MOR controlled mode, only TIR, TIM and TOPT are visible + return m_tcr | (tcr_topt() ? 0x37 : 0x00); +} + +WRITE8_MEMBER(m68705_new_device::tcr_w) +{ + // 7 TIR RW Timer Interrupt Request Status + // 6 TIM RW Timer Interrupt Mask + // 5 TIN RW Timer Input Select + // 4 TIE RW Timer External Input Enable + // 3 TOPT R Timer Mask/Programmable Option + // 3 PSC W Prescaler Clear + // 2 PS2 RW Prescaler Option + // 1 PS1 RW Prescaler Option + // 0 PS0 RW Prescaler Option + + // TIN TIE CLOCK + // 0 0 Internal Clock (phase 2) + // 0 1 Gated (AND) of External and Internal Clocks + // 1 0 No Clock + // 1 1 External Clock + + // in MOR controlled mode, TIN/PS2/PS1/PS0 are loaded from MOR on reset and TIE is always 1 + // in MOR controlled mode, TIN, TIE, PS2, PS1, and PS0 always read as 1 + + // TOPT isn't a real bit in this register, it's a pass-through to the MOR register + // it's theoretically possible to get into a weird state by writing to the MOR while running + // for simplicity, we don't emulate this - we just check the MOR on initialisation and reset + + if (tcr_topt()) + { + m_tcr = (m_tcr & 0x3f) | (data & 0xc0); + } + else + { + if (BIT(data, 3)) + m_prescaler = 0; + m_tcr = (m_tcr & 0x08) | (data & 0xf7); + } + + // TODO: this is tied up with /INT2 on R/U devices + if (tcr_tir() && !tcr_tim()) + set_input_line(M68705_INT_TIMER, ASSERT_LINE); + else + set_input_line(M68705_INT_TIMER, CLEAR_LINE); +} + READ8_MEMBER(m68705_new_device::misc_r) { logerror("unsupported read MISC\n"); @@ -348,7 +410,7 @@ WRITE8_MEMBER(m68705_new_device::pcr_w) data |= ((data & 0x01) << 1); // write EPROM if /PGE is asserted (erase requires UV so don't clear bits) - if (!BIT(m_pcr, 2) && (0x20 & ((m_pcr ^ data) & ~data))) + if (pcr_vpon() && !pcr_pge() && !BIT(data, 1)) m_user_rom[m_pl_addr] |= m_pl_data; m_pcr = (m_pcr & 0xfc) | (data & 0x03); @@ -399,132 +461,62 @@ WRITE8_MEMBER(m68705_new_device::arr_w) logerror("unsupported write ARR = %02X\n", data); } -READ8_MEMBER(m68705_new_device::internal_68705_tdr_r) -{ - //logerror("internal_68705 TDR read, returning %02X\n", m_tdr); - return m_tdr; -} - -WRITE8_MEMBER(m68705_new_device::internal_68705_tdr_w) -{ - //logerror("internal_68705 TDR written with %02X, was %02X\n", data, m_tdr); - m_tdr = data; -} - - -READ8_MEMBER(m68705_new_device::internal_68705_tcr_r) -{ - //logerror("internal_68705 TCR read, returning %02X\n", (m_tcr&0xF7)); - return (m_tcr & 0xF7); -} - -WRITE8_MEMBER(m68705_new_device::internal_68705_tcr_w) -{ -/* - logerror("internal_68705 TCR written with %02X\n", data); - if (data&0x80) logerror(" TIR=1, Timer Interrupt state is set\n"); else logerror(" TIR=0; Timer Interrupt state is cleared\n"); - if (data&0x40) logerror(" TIM=1, Timer Interrupt is now masked\n"); else logerror(" TIM=0, Timer Interrupt is now unmasked\n"); - if (data&0x20) logerror(" TIN=1, Timer Clock source is set to external\n"); else logerror(" TIN=0, Timer Clock source is set to internal\n"); - if (data&0x10) logerror(" TIE=1, Timer External pin is enabled\n"); else logerror(" TIE=0, Timer External pin is disabled\n"); - if (data&0x08) logerror(" PSC=1, Prescaler counter cleared\n"); else logerror(" PSC=0, Prescaler counter left alone\n"); - logerror(" Prescaler: %d\n", (1<<(data&0x7))); -*/ - // if timer was enabled but now isn't, shut it off. - // below is a hack assuming the TIMER pin isn't going anywhere except tied to +5v, so basically TIN is acting as an active-low timer enable, and TIE is ignored even in the case where TIE=1, the timer will end up being 5v ANDED against the internal timer clock which == the internal timer clock. - // Note this hack is incorrect; the timer pin actually does connect somewhere (vblank or maybe one of the V counter bits?), but the game never actually uses the timer pin in external clock mode, so the TIMER connection must be left over from development. We can apparently safely ignore it. - if ((m_tcr^data)&0x20)// check if TIN state changed - { - /* logerror("timer enable state changed!\n"); */ - if (data&0x20) m_68705_timer->adjust(attotime::never, TIMER_68705_PRESCALER_EXPIRED); - else m_68705_timer->adjust(attotime::from_hz(((clock())/4)/(1<<(data&0x7))), TIMER_68705_PRESCALER_EXPIRED); - } - // prescaler check: if timer prescaler has changed, or the PSC bit is set, adjust the timer length for the prescaler expired timer, but only if the timer would be running - if ( (((m_tcr&0x07)!=(data&0x07))||(data&0x08)) && ((data&0x20)==0) ) - { - /* logerror("timer reset due to PSC or prescaler change!\n"); */ - m_68705_timer->adjust(attotime::from_hz(((clock())/4)/(1<<(data&0x7))), TIMER_68705_PRESCALER_EXPIRED); - } - m_tcr = data; - // if int state is set, and TIM is unmasked, assert an interrupt. otherwise clear it. - if ((m_tcr&0xC0) == 0x80) - set_input_line(M68705_INT_TIMER, ASSERT_LINE); - else - set_input_line(M68705_INT_TIMER, CLEAR_LINE); - -} - -TIMER_CALLBACK_MEMBER(m68705_new_device::timer_68705_increment) -{ - m_tdr++; - if (m_tdr == 0x00) m_tcr |= 0x80; // if we overflowed, set the int bit - if ((m_tcr&0xC0) == 0x80) - set_input_line(M68705_INT_TIMER, ASSERT_LINE); - else - set_input_line(M68705_INT_TIMER, CLEAR_LINE); - m_68705_timer->adjust(attotime::from_hz((clock() / 4) / (1 << (m_tcr & 0x07))), TIMER_68705_PRESCALER_EXPIRED); -} - -void m68705_new_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - switch (id) - { - case TIMER_68705_PRESCALER_EXPIRED: - timer_68705_increment(ptr, param); - break; - default: - m68705_device::device_timer(timer, id, param, ptr); - } -} - void m68705_new_device::device_start() { m68705_device::device_start(); - save_item(NAME(m_tdr)); - save_item(NAME(m_tcr)); - save_item(NAME(m_port_input)); save_item(NAME(m_port_latch)); save_item(NAME(m_port_ddr)); + save_item(NAME(m_prescaler)); + save_item(NAME(m_tdr)); + save_item(NAME(m_tcr)); + save_item(NAME(m_vihtp)); save_item(NAME(m_pcr)); save_item(NAME(m_pl_data)); save_item(NAME(m_pl_addr)); + // initialise digital I/O for (u8 &input : m_port_input) input = 0xff; for (devcb_read8 &cb : m_port_cb_r) cb.resolve(); for (devcb_write8 &cb : m_port_cb_w) cb.resolve_safe(); + // initialise timer/counter + u8 const options(get_mask_options()); + m_tcr = 0x40 | (options & 0x37); + if (BIT(options, 6)) + m_tcr |= 0x18; + + // initialise EPROM control m_vihtp = CLEAR_LINE; m_pcr = 0xff; m_pl_data = 0xff; m_pl_addr = 0xffff; - - // allocate the MCU timer, and set it to fire NEVER. - m_68705_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m68705_new_device::timer_68705_increment),this)); - m_68705_timer->adjust(attotime::never); } void m68705_new_device::device_reset() { m68705_device::device_reset(); - if (CLEAR_LINE != m_vihtp) - RM16(0xfff6, &m_pc); - + // reset digital I/O port_ddr_w<0>(space(AS_PROGRAM), 0, 0x00, 0xff); port_ddr_w<1>(space(AS_PROGRAM), 0, 0x00, 0xff); port_ddr_w<2>(space(AS_PROGRAM), 0, 0x00, 0xff); port_ddr_w<3>(space(AS_PROGRAM), 0, 0x00, 0xff); + // reset timer/counter + u8 const options(get_mask_options()); + m_prescaler = 0x7f; + m_tdr = 0xff; + m_tcr = BIT(options, 6) ? (0x58 | (options & 0x27)) : (0x40 | (m_tcr & 0x37)); + + // reset EPROM control m_pcr |= 0xfb; // b2 (/VPON) is driven by external input and hence unaffected by reset - m_tdr = 0xff; - m_tcr = 0xff; - - //set_input_line(M68705_IRQ_LINE, CLEAR_LINE); - m_68705_timer->adjust(attotime::from_hz((clock() / 4) / (1 << 7))); + if (CLEAR_LINE != m_vihtp) + RM16(0xfff6, &m_pc); } void m68705_new_device::execute_set_input(int inputnum, int state) @@ -532,10 +524,7 @@ void m68705_new_device::execute_set_input(int inputnum, int state) switch (inputnum) { case M68705_VPP_LINE: - if (ASSERT_LINE == state) - m_pcr &= 0xfb; - else - m_pcr |= 0x04; + m_pcr = (m_pcr & 0xfb) | ((ASSERT_LINE == state) ? 0x00 : 0x04); break; case M68705_VIHTP_LINE: // TODO: this is actually the same physical pin as the timer input, so they should be tied up @@ -560,6 +549,26 @@ void m68705_new_device::nvram_write(emu_file &file) file.write(&m_user_rom[0], m_user_rom.bytes()); } +void m68705_new_device::burn_cycles(unsigned count) +{ + // handle internal timer/counter source + if (!tcr_tin()) // TODO: check tcr_tie() and gate on TIMER if appropriate + { + unsigned const ps_opt(tcr_ps()); + unsigned const ps_mask((1 << ps_opt) - 1); + unsigned const decrements((count + (m_prescaler & ps_mask)) >> ps_opt); + + if (decrements && (decrements >= m_tdr)) + { + m_tcr |= 0x80; + if (!tcr_tim()) + set_input_line(M68705_INT_TIMER, ASSERT_LINE); + } + m_prescaler = (count + m_prescaler) & 0x7f; + m_tdr = (m_tdr - decrements) & 0xff; + } +} + /**************************************************************************** * M68705Px family @@ -577,8 +586,8 @@ DEVICE_ADDRESS_MAP_START( p_map, 8, m68705p_device ) AM_RANGE(0x0005, 0x0005) AM_WRITE(port_ddr_w<1>) AM_RANGE(0x0006, 0x0006) AM_WRITE(port_ddr_w<2>) // 0x0007 not used (no port D) - AM_RANGE(0x0008, 0x0008) AM_READWRITE(internal_68705_tdr_r, internal_68705_tdr_w) - AM_RANGE(0x0009, 0x0009) AM_READWRITE(internal_68705_tcr_r, internal_68705_tcr_w) + AM_RANGE(0x0008, 0x0008) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x0009, 0x0009) AM_READWRITE(tcr_r, tcr_w) // 0x000a not used AM_RANGE(0x000b, 0x000b) AM_READWRITE(pcr_r, pcr_w) // 0x000c-0x000f not used @@ -631,8 +640,8 @@ DEVICE_ADDRESS_MAP_START( u_map, 8, m68705u_device ) AM_RANGE(0x0005, 0x0005) AM_WRITE(port_ddr_w<1>) AM_RANGE(0x0006, 0x0006) AM_WRITE(port_ddr_w<2>) // 0x0007 not used (port D is input only) - AM_RANGE(0x0008, 0x0008) AM_READWRITE(internal_68705_tdr_r, internal_68705_tdr_w) - AM_RANGE(0x0009, 0x0009) AM_READWRITE(internal_68705_tcr_r, internal_68705_tcr_w) + AM_RANGE(0x0008, 0x0008) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x0009, 0x0009) AM_READWRITE(tcr_r, tcr_w) AM_RANGE(0x000a, 0x000a) AM_READWRITE(misc_r, misc_w) AM_RANGE(0x000b, 0x000b) AM_READWRITE(pcr_r, pcr_w) // 0x000c-0x000f not used @@ -698,8 +707,8 @@ DEVICE_ADDRESS_MAP_START( r_map, 8, m68705r_device ) AM_RANGE(0x0005, 0x0005) AM_WRITE(port_ddr_w<1>) AM_RANGE(0x0006, 0x0006) AM_WRITE(port_ddr_w<2>) // 0x0007 not used (port D is input only) - AM_RANGE(0x0008, 0x0008) AM_READWRITE(internal_68705_tdr_r, internal_68705_tdr_w) - AM_RANGE(0x0009, 0x0009) AM_READWRITE(internal_68705_tcr_r, internal_68705_tcr_w) + AM_RANGE(0x0008, 0x0008) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x0009, 0x0009) AM_READWRITE(tcr_r, tcr_w) AM_RANGE(0x000a, 0x000a) AM_READWRITE(misc_r, misc_w) AM_RANGE(0x000b, 0x000b) AM_READWRITE(pcr_r, pcr_w) // 0x000c-0x000d not used @@ -750,6 +759,11 @@ tiny_rom_entry const *m68705p3_device::device_rom_region() const return ROM_NAME(m68705p3); } +u8 m68705p3_device::get_mask_options() const +{ + return get_user_rom()[0x0784] & 0xf7; // no SNM bit +} + /**************************************************************************** * M68705P5 device @@ -765,6 +779,11 @@ tiny_rom_entry const *m68705p5_device::device_rom_region() const return ROM_NAME(m68705p5); } +u8 m68705p5_device::get_mask_options() const +{ + return get_user_rom()[0x0784]; +} + /**************************************************************************** * M68705R3 device @@ -780,6 +799,11 @@ tiny_rom_entry const *m68705r3_device::device_rom_region() const return ROM_NAME(m68705r3); } +u8 m68705r3_device::get_mask_options() const +{ + return get_user_rom()[0x0784] & 0xf7; // no SNM bit +} + /**************************************************************************** * M68705U3 device @@ -794,3 +818,8 @@ tiny_rom_entry const *m68705u3_device::device_rom_region() const { return ROM_NAME(m68705u3); } + +u8 m68705u3_device::get_mask_options() const +{ + return get_user_rom()[0x0784] & 0xf7; // no SNM bit +} diff --git a/src/devices/cpu/m6805/m68705.h b/src/devices/cpu/m6805/m68705.h index 09a0c872539..e89517e5735 100644 --- a/src/devices/cpu/m6805/m68705.h +++ b/src/devices/cpu/m6805/m68705.h @@ -97,11 +97,6 @@ protected: PORT_COUNT = 4 }; - enum - { - TIMER_68705_PRESCALER_EXPIRED, - }; - m68705_new_device( machine_config const &mconfig, char const *tag, @@ -125,10 +120,10 @@ protected: template DECLARE_WRITE8_MEMBER(port_ddr_w); template void port_cb_w(); - DECLARE_READ8_MEMBER(internal_68705_tdr_r); - DECLARE_WRITE8_MEMBER(internal_68705_tdr_w); - DECLARE_READ8_MEMBER(internal_68705_tcr_r); - DECLARE_WRITE8_MEMBER(internal_68705_tcr_w); + DECLARE_READ8_MEMBER(tdr_r); + DECLARE_WRITE8_MEMBER(tdr_w); + DECLARE_READ8_MEMBER(tcr_r); + DECLARE_WRITE8_MEMBER(tcr_w); DECLARE_READ8_MEMBER(misc_r); DECLARE_WRITE8_MEMBER(misc_w); @@ -141,11 +136,6 @@ protected: DECLARE_READ8_MEMBER(arr_r); DECLARE_WRITE8_MEMBER(arr_w); - TIMER_CALLBACK_MEMBER(timer_68705_increment); - - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; - - // device-level overrides virtual void device_start() override; virtual void device_reset() override; virtual void execute_set_input(int inputnum, int state) override; @@ -153,27 +143,44 @@ protected: virtual void nvram_read(emu_file &file) override; virtual void nvram_write(emu_file &file) override; - u8 m_tdr; - u8 m_tcr; + virtual void burn_cycles(unsigned count) override; - /* Timers */ - emu_timer *m_68705_timer; + u8 *const get_user_rom() const { return &m_user_rom[0]; } + virtual u8 get_mask_options() const = 0; private: + bool tcr_tir() const { return BIT(m_tcr, 7); } + bool tcr_tim() const { return BIT(m_tcr, 6); } + bool tcr_tin() const { return BIT(m_tcr, 5); } + bool tcr_tie() const { return BIT(m_tcr, 4); } + bool tcr_topt() const { return BIT(m_tcr, 3); } + u8 tcr_ps() const { return m_tcr & 0x07; } + + bool pcr_vpon() const { return !BIT(m_pcr, 2); } + bool pcr_pge() const { return !BIT(m_pcr, 1); } + bool pcr_ple() const { return !BIT(m_pcr, 0); } + required_region_ptr m_user_rom; - bool m_port_open_drain[PORT_COUNT]; - u8 m_port_mask[PORT_COUNT]; - u8 m_port_input[PORT_COUNT]; - u8 m_port_latch[PORT_COUNT]; - u8 m_port_ddr[PORT_COUNT]; - devcb_read8 m_port_cb_r[PORT_COUNT]; - devcb_write8 m_port_cb_w[PORT_COUNT]; + // digital I/O + bool m_port_open_drain[PORT_COUNT]; + u8 m_port_mask[PORT_COUNT]; + u8 m_port_input[PORT_COUNT]; + u8 m_port_latch[PORT_COUNT]; + u8 m_port_ddr[PORT_COUNT]; + devcb_read8 m_port_cb_r[PORT_COUNT]; + devcb_write8 m_port_cb_w[PORT_COUNT]; - u8 m_vihtp; - u8 m_pcr; - u8 m_pl_data; - u16 m_pl_addr; + // timer/counter + u8 m_prescaler; + u8 m_tdr; + u8 m_tcr; + + // EPROM control + u8 m_vihtp; + u8 m_pcr; + u8 m_pl_data; + u16 m_pl_addr; }; @@ -288,6 +295,8 @@ public: protected: virtual tiny_rom_entry const *device_rom_region() const override; + + virtual u8 get_mask_options() const override; }; @@ -300,6 +309,8 @@ public: protected: virtual tiny_rom_entry const *device_rom_region() const override; + + virtual u8 get_mask_options() const override; }; @@ -312,6 +323,8 @@ public: protected: virtual tiny_rom_entry const *device_rom_region() const override; + + virtual u8 get_mask_options() const override; }; @@ -324,6 +337,8 @@ public: protected: virtual tiny_rom_entry const *device_rom_region() const override; + + virtual u8 get_mask_options() const override; }; diff --git a/src/mame/drivers/m68705prg.cpp b/src/mame/drivers/m68705prg.cpp index 16d7da89c8c..965fa9bb8cf 100644 --- a/src/mame/drivers/m68705prg.cpp +++ b/src/mame/drivers/m68705prg.cpp @@ -22,7 +22,8 @@ * When programming is complete, the "Programmed" LED will be lit. When * verification is complete, the "Verified" LED will be lit. If * verification fails, the program stops and the "Address" digits show - * the address one past the location that failed. + * the address one past the location that failed for P3/P5, or the + * location that failed for R3/U3. */ #include "emu.h" diff --git a/src/mame/drivers/quizpun2.cpp b/src/mame/drivers/quizpun2.cpp index a22e4677284..4f6b61ed3a5 100644 --- a/src/mame/drivers/quizpun2.cpp +++ b/src/mame/drivers/quizpun2.cpp @@ -82,12 +82,16 @@ Notes: ***************************************************************************/ #include "emu.h" -#include "cpu/z80/z80.h" + #include "cpu/m6805/m68705.h" -#include "machine/gen_latch.h" +#include "cpu/z80/z80.h" + #include "machine/eepromser.h" +#include "machine/gen_latch.h" + #include "sound/2203intf.h" + // very preliminary quizpun2 protection simulation #define VERBOSE_PROTECTION_LOG 0 @@ -150,7 +154,7 @@ public: DECLARE_WRITE8_MEMBER(quizpun2_protection_w); // quizpun - uint8_t m_port_a, m_port_b, m_port_c; + uint8_t m_port_a, m_port_b; bool m_quizpun_pending; bool m_quizpun_written; bool m_quizpun_repeat; @@ -269,7 +273,7 @@ void quizpun2_state::machine_reset() m_prot.addr = 0; // quizpun - m_port_a = m_port_b = m_port_c = 0; + m_port_a = m_port_b = 0; m_quizpun_pending = m_quizpun_written = m_quizpun_repeat = false; } @@ -529,10 +533,11 @@ READ8_MEMBER(quizpun2_state::quizpun_68705_port_b_r) // bit 1: 0 = main cpu has written // bit 0: 0 = main cpu is reading - uint8_t ret = m_port_b & 0xf4; - ret |= ( m_quizpun_pending ? 0 : (1 << 3)) | - ( (m_quizpun_pending && m_quizpun_written) ? 0 : (1 << 1)) | - ( (m_quizpun_pending && !m_quizpun_written) ? 0 : (1 << 0)) ; + uint8_t const ret = + 0xf4 | + ( m_quizpun_pending ? 0 : (1 << 3)) | + ((m_quizpun_pending && m_quizpun_written) ? 0 : (1 << 1)) | + ((m_quizpun_pending && !m_quizpun_written) ? 0 : (1 << 0)); // logerror("%s: port B read %02x\n", machine().describe_context(), ret); return ret; @@ -544,7 +549,7 @@ WRITE8_MEMBER(quizpun2_state::quizpun_68705_port_b_w) // bit 2: 0->1 run main cpu - if (!(m_port_b & 0x04) && (data & 0x04)) + if (!BIT(m_port_b, 2) && BIT(data, 2)) { m_quizpun_pending = false; m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); @@ -556,8 +561,7 @@ WRITE8_MEMBER(quizpun2_state::quizpun_68705_port_b_w) READ8_MEMBER(quizpun2_state::quizpun_68705_port_c_r) { - uint8_t ret = m_port_c & 0xf7; - ret |= m_eeprom->do_read() ? 0x08 : 0; + uint8_t const ret = 0xf7 | (m_eeprom->do_read() ? 0x08 : 0x00); // logerror("%s: port C read %02x\n", machine().describe_context(), ret); return ret; } @@ -565,33 +569,17 @@ READ8_MEMBER(quizpun2_state::quizpun_68705_port_c_r) WRITE8_MEMBER(quizpun2_state::quizpun_68705_port_c_w) { // latch the bit - m_eeprom->di_write((data & 0x04) >> 2); + m_eeprom->di_write(BIT(data, 2)); // reset line asserted: reset. - m_eeprom->cs_write((data & 0x02) ? ASSERT_LINE : CLEAR_LINE); + m_eeprom->cs_write(BIT(data, 1) ? ASSERT_LINE : CLEAR_LINE); // clock line asserted: write latch or select next bit to read - m_eeprom->clk_write((data & 0x01) ? ASSERT_LINE : CLEAR_LINE); + m_eeprom->clk_write(BIT(data, 0) ? ASSERT_LINE : CLEAR_LINE); // logerror("%s: port C write %02x\n", machine().describe_context(), data); - m_port_c = data; } -static ADDRESS_MAP_START( mcu_map, AS_PROGRAM, 8, quizpun2_state ) - ADDRESS_MAP_GLOBAL_MASK(0x7ff) - - AM_RANGE(0x000, 0x000) AM_READWRITE(quizpun_68705_port_a_r, quizpun_68705_port_a_w) - AM_RANGE(0x001, 0x001) AM_READWRITE(quizpun_68705_port_b_r, quizpun_68705_port_b_w) - AM_RANGE(0x002, 0x002) AM_READWRITE(quizpun_68705_port_c_r, quizpun_68705_port_c_w) - - AM_RANGE(0x004, 0x004) AM_NOP // DDR A - AM_RANGE(0x005, 0x005) AM_NOP // DDR B - AM_RANGE(0x006, 0x006) AM_NOP // DDR C - - AM_RANGE(0x010, 0x07f) AM_RAM - AM_RANGE(0x080, 0x7ff) AM_ROM -ADDRESS_MAP_END - /*************************************************************************** Memory Maps - Sound CPU ***************************************************************************/ @@ -731,8 +719,13 @@ static MACHINE_CONFIG_DERIVED( quizpun, quizpun2 ) MCFG_CPU_MODIFY("maincpu") MCFG_CPU_IO_MAP(quizpun_io_map) - MCFG_CPU_ADD("mcu", M68705, XTAL_4MHz) // xtal is 4MHz, divided by 4 internally - MCFG_CPU_PROGRAM_MAP(mcu_map) + MCFG_CPU_ADD("mcu", M68705P5, XTAL_4MHz) // xtal is 4MHz, divided by 4 internally + MCFG_M68705_PORTA_R_CB(READ8(quizpun2_state, quizpun_68705_port_a_r)) + MCFG_M68705_PORTB_R_CB(READ8(quizpun2_state, quizpun_68705_port_b_r)) + MCFG_M68705_PORTC_R_CB(READ8(quizpun2_state, quizpun_68705_port_c_r)) + MCFG_M68705_PORTA_W_CB(WRITE8(quizpun2_state, quizpun_68705_port_a_w)) + MCFG_M68705_PORTB_W_CB(WRITE8(quizpun2_state, quizpun_68705_port_b_w)) + MCFG_M68705_PORTC_W_CB(WRITE8(quizpun2_state, quizpun_68705_port_c_w)) MACHINE_CONFIG_END /***************************************************************************