diff --git a/src/devices/cpu/z80/z80.lst b/src/devices/cpu/z80/z80.lst index 05f8592cb3209..b0019f4ed983b 100644 --- a/src/devices/cpu/z80/z80.lst +++ b/src/devices/cpu/z80/z80.lst @@ -902,6 +902,7 @@ macro take_nmi macro z80n:take_nmi leave_halt(); m_iff1 = 0; + m_nmiack_cb(1); m_r++; + 5 if (m_stackless) { diff --git a/src/devices/cpu/z80/z80n.cpp b/src/devices/cpu/z80/z80n.cpp index 2f00d96e0b4ec..73168c9a0c34a 100644 --- a/src/devices/cpu/z80/z80n.cpp +++ b/src/devices/cpu/z80/z80n.cpp @@ -25,20 +25,13 @@ std::unique_ptr z80n_device::create_disassembler() z80n_device::z80n_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : z80_device(mconfig, Z80N, tag, owner, clock) + , m_nmiack_cb(*this) , m_out_retn_seen_cb(*this) , m_in_nextreg_cb(*this, 0) , m_out_nextreg_cb(*this) { } -void z80n_device::nmi(int state) -{ - if (state != CLEAR_LINE) - set_service_attention(); - else - set_service_attention(); -} - void z80n_device::execute_run() { #include "cpu/z80/z80n.hxx" diff --git a/src/devices/cpu/z80/z80n.h b/src/devices/cpu/z80/z80n.h index a2816f23e9b32..1d1baeaf0d7d7 100644 --- a/src/devices/cpu/z80/z80n.h +++ b/src/devices/cpu/z80/z80n.h @@ -13,6 +13,7 @@ class z80n_device : public z80_device // construction/destruction z80n_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + auto nmiack_cb() { return m_nmiack_cb.bind(); } auto in_nextreg_cb() { return m_in_nextreg_cb.bind(); } auto out_nextreg_cb() { return m_out_nextreg_cb.bind(); } auto out_retn_seen_cb() { return m_out_retn_seen_cb.bind(); } @@ -20,8 +21,6 @@ class z80n_device : public z80_device bool nmi_stackless_r() { return m_stackless; } void nmi_stackless_w(bool data) { m_stackless = data; } - void nmi(int state); - protected: virtual void device_start() override ATTR_COLD; virtual void device_reset() override ATTR_COLD; @@ -29,6 +28,7 @@ class z80n_device : public z80_device // device_execute_interface implementation virtual void execute_run() override; + devcb_write_line m_nmiack_cb; devcb_write8 m_out_retn_seen_cb; devcb_read8 m_in_nextreg_cb; devcb_write8 m_out_nextreg_cb; diff --git a/src/mame/sinclair/specnext.cpp b/src/mame/sinclair/specnext.cpp index 3f98e3c1c393c..50080aa0af5a5 100644 --- a/src/mame/sinclair/specnext.cpp +++ b/src/mame/sinclair/specnext.cpp @@ -144,8 +144,7 @@ class specnext_state : public spectrum_128_state, public device_state_interface void ks2(machine_config &config); void ks3(machine_config &config); - INPUT_CHANGED_MEMBER(on_mf_nmi); - INPUT_CHANGED_MEMBER(on_divmmc_nmi); + INPUT_CHANGED_MEMBER(on_nmi_button); protected: virtual void machine_start() override ATTR_COLD; @@ -158,8 +157,8 @@ class specnext_state : public spectrum_128_state, public device_state_interface void update_video_mode(); u8 do_m1(offs_t offset); - void do_mf_nmi(); - void nmi(); + void nmi_rq(); + void nmi_ack(int state); void leave_nmi(int state); void map_fetch(address_map &map) ATTR_COLD; void map_mem(address_map &map) ATTR_COLD; @@ -216,6 +215,8 @@ class specnext_state : public spectrum_128_state, public device_state_interface bool machine_type_128() const { return m_nr_03_machine_type == 2 || m_nr_03_machine_type == 4; } bool machine_type_p3() const { return !machine_type_48() && !machine_type_128(); } + bool nmi_assert_mf() { return ((m_io_nmi->read() & 1) || m_nr_02_generate_mf_nmi) && m_nr_06_button_m1_nmi_en; } + bool nmi_assert_divmmc() { return ((m_io_nmi->read() & 2) || m_nr_02_generate_divmmc_nmi) && m_nr_06_button_drive_nmi_en; } void nr_02_w(u8 nr_wr_dat); bool nr_02_iotrap() { return m_nr_da_iotrap_cause & 3; } void nr_07_cpu_speed_w(u8 data); @@ -390,9 +391,6 @@ class specnext_state : public spectrum_128_state, public device_state_interface u8 m_nr_register; u8 m_port_e3_reg; bool m_divmmc_delayed_check; - bool m_copper_req; - u8 m_copper_nr_reg; - u8 m_copper_nr_dat; u8 m_sram_rom; bool m_sram_rom3; @@ -742,8 +740,6 @@ void specnext_state::bank_update(u8 bank) m_divmmc->en_w(port_divmmc_io_en()); m_divmmc->automap_reset_w(!port_divmmc_io_en() || !m_nr_0a_divmmc_automap_en); m_divmmc->automap_active_w(sram_divmmc_automap_en); - m_divmmc->retn_seen_w(0); - m_divmmc->divmmc_button_w(m_nr_02_generate_divmmc_nmi); for (s8 cpu_rd_n = 1; cpu_rd_n >= 0; --cpu_rd_n) // check W then R { @@ -1868,18 +1864,6 @@ u8 specnext_state::reg_r(offs_t nr_register) void specnext_state::reg_w(offs_t nr_wr_reg, u8 nr_wr_dat) { - if (m_copper_req) - { - if (nr_wr_reg == 0x02) - { - LOGINTVVV("Copper write: reg=%02x data=%02x\n", nr_wr_reg, nr_wr_dat); - m_copper_nr_reg = nr_wr_reg; - m_copper_nr_dat = nr_wr_dat; - return; - } - m_copper_req = false; - } - switch (nr_wr_reg) { case 0x02: @@ -2526,28 +2510,8 @@ void specnext_state::nr_02_w(u8 nr_wr_dat) m_nr_da_iotrap_cause = 0; m_nr_02_generate_mf_nmi = BIT(nr_wr_dat, 3); - do_mf_nmi(); - - if (BIT(nr_wr_dat, 2)) - { - if (m_nr_06_button_drive_nmi_en) - { - m_nr_02_generate_divmmc_nmi = 1; - nmi(); - } - } - else - { - m_nr_02_generate_divmmc_nmi = 0; - } - - const u16 mask = 1 << INT_PRIORITY_NMI; - if (!m_nr_02_generate_mf_nmi && !m_nr_02_generate_divmmc_nmi && (m_im2_int_status & mask)) - { - m_maincpu->nmi(CLEAR_LINE); - m_im2_int_status &= ~mask; - update_dma_delay(); - } + m_nr_02_generate_divmmc_nmi = BIT(nr_wr_dat, 2); + nmi_rq(); if (BIT(nr_wr_dat, 1)) // hard reset { @@ -2680,45 +2644,38 @@ void specnext_state::line_irq_adjust() m_irq_line_timer->reset(); } -INPUT_CHANGED_MEMBER(specnext_state::on_mf_nmi) +INPUT_CHANGED_MEMBER(specnext_state::on_nmi_button) { - if (m_nr_03_config_mode) - return; - - m_nr_02_generate_mf_nmi = newval & 1; - do_mf_nmi(); - m_nr_02_generate_mf_nmi = 0; + nmi_rq(); } -INPUT_CHANGED_MEMBER(specnext_state::on_divmmc_nmi) +void specnext_state::nmi_rq() { - if (m_nr_03_config_mode) - return; - - m_nr_02_generate_divmmc_nmi = newval & 1; - if (m_nr_06_button_drive_nmi_en && m_nr_02_generate_divmmc_nmi) - nmi(); -} - -void specnext_state::do_mf_nmi() -{ - if (m_nr_06_button_m1_nmi_en && m_nr_02_generate_mf_nmi) + if (!m_nr_03_config_mode) { - nmi(); - m_mf->button_w(1); + m_mf->button_w(nmi_assert_mf()); m_mf->clock_w(); - m_mf->button_w(0); + + m_divmmc->divmmc_button_w(nmi_assert_divmmc()); + m_divmmc->clock_w(); + + if ((nmi_assert_mf() || nmi_assert_divmmc())) + { + LOGINTVVV("NMI: on (%s)\n", nmi_assert_mf() ? "MF" : "DivMMC"); + m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); + m_maincpu->abort_timeslice(); + } } } -void specnext_state::nmi() +void specnext_state::nmi_ack(int state) { - const u16 mask = 1 << INT_PRIORITY_NMI; - if (~m_im2_int_status & mask) + if (state) { - m_maincpu->nmi(ASSERT_LINE); - m_im2_int_status |= mask; + LOGINTVVV("NMI: ack\n"); + m_im2_int_status |= 1 << INT_PRIORITY_NMI; update_dma_delay(); + bank_update(0, 2); } } @@ -2726,14 +2683,20 @@ void specnext_state::leave_nmi(int state) { m_mf->cpu_retn_seen_w(1); m_mf->clock_w(); + m_mf->cpu_retn_seen_w(0); + m_mf->clock_w(); m_divmmc->retn_seen_w(1); m_divmmc->clock_w(); + m_divmmc->retn_seen_w(0); + m_divmmc->clock_w(); - m_mf->cpu_retn_seen_w(0); - m_mf->clock_w(); - + m_im2_int_status &= ~(1 << INT_PRIORITY_NMI); + update_dma_delay(); bank_update(0, 2); + + LOGINTVVV("NMI: off\n"); + m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); } u8 specnext_state::do_m1(offs_t offset) @@ -2777,7 +2740,7 @@ void specnext_state::map_fetch(address_map &map) if (m_divmmc_delayed_check) { /* Happens after RW cycles (before next M1 fetch). - Fell like side effects check must be ignored here, + Feels like side effects check must be ignored here, because doesn't matter who reset this lines and such approach gives better experience in debugger UI. */ do_m1(offset); @@ -2789,12 +2752,6 @@ void specnext_state::map_fetch(address_map &map) m_maincpu->adjust_icount(1); } } - - if (m_copper_req) - { - m_copper_req = 0; - reg_w(m_copper_nr_reg, m_copper_nr_dat); - } } return m_program.read_byte(offset); @@ -3206,8 +3163,8 @@ INPUT_PORTS_START(specnext) PORT_BIT(0x800, IP_ACTIVE_HIGH, IPT_BUTTON7) PORT_PLAYER(2) PORT_CODE(JOYCODE_BUTTON7) PORT_NAME("Joystick (R) Mode") PORT_MODIFY("NMI") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("NMI MF") PORT_CODE(KEYCODE_F12) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(specnext_state::on_mf_nmi), 0) - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("NMI DivMMC") PORT_CODE(KEYCODE_F11) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(specnext_state::on_divmmc_nmi), 0) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("NMI MF") PORT_CODE(KEYCODE_F12) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(specnext_state::on_nmi_button), 0) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_OTHER) PORT_NAME("NMI DivMMC") PORT_CODE(KEYCODE_F11) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(specnext_state::on_nmi_button), 0) PORT_START("LYRS") PORT_CONFNAME(0x08, 0x00, "Disable Sprites") @@ -3262,9 +3219,6 @@ void specnext_state::machine_start() save_item(NAME(m_nr_register)); save_item(NAME(m_port_e3_reg)); save_item(NAME(m_divmmc_delayed_check)); - save_item(NAME(m_copper_req)); - save_item(NAME(m_copper_nr_reg)); - save_item(NAME(m_copper_nr_dat)); save_item(NAME(m_sram_rom)); save_item(NAME(m_sram_rom3)); save_item(NAME(m_sram_alt_128_n)); @@ -3615,6 +3569,7 @@ void specnext_state::machine_reset() // TODO prevent from soft reset in config mode? spectrum_128_state::machine_reset(); + m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); m_irq_line_timer->reset(); if (m_nr_02_hard_reset) @@ -3680,9 +3635,6 @@ void specnext_state::machine_reset() port_ff3b_ulap_en_w(0); m_nr_register = 0x24; //copper_requester_d = 0; - m_copper_req = 0; - m_copper_nr_reg = 0x00; - m_copper_nr_dat = 0x00; //cpu_requester_d = 0; //cpu_req = 0; //cpu_nr_reg = 0x00; @@ -3917,6 +3869,7 @@ void specnext_state::tbblue(machine_config &config) m_maincpu->set_io_map(&specnext_state::map_io); m_maincpu->set_vblank_int("screen", FUNC(specnext_state::specnext_interrupt)); m_maincpu->set_irq_acknowledge_callback(NAME([](device_t &, int){ return 0xff; })); + m_maincpu->nmiack_cb().set(FUNC(specnext_state::nmi_ack)); m_maincpu->out_nextreg_cb().set([this](offs_t offset, u8 data) { m_next_regs.write_byte(offset, data); }); m_maincpu->in_nextreg_cb().set([this](offs_t offset) { return m_next_regs.read_byte(offset); }); m_maincpu->out_retn_seen_cb().set(FUNC(specnext_state::leave_nmi)); @@ -3993,7 +3946,7 @@ void specnext_state::tbblue(machine_config &config) SPECNEXT_SPRITES(config, m_sprites, 0).set_palette(m_palette->device().tag(), 0x600, 0x700); SPECNEXT_COPPER(config, m_copper, 28_MHz_XTAL); - m_copper->out_nextreg_cb().set([this](offs_t offset, u8 data) { m_copper_req = 1; m_next_regs.write_byte(offset, data); }); + m_copper->out_nextreg_cb().set([this](offs_t offset, u8 data) { m_next_regs.write_byte(offset, data); }); m_copper->set_in_until_pos_cb(FUNC(specnext_state::copper_until_pos_r)); SOFTWARE_LIST(config, "sd_list").set_original("specnext_sd"); diff --git a/src/mame/sinclair/specnext_divmmc.cpp b/src/mame/sinclair/specnext_divmmc.cpp index c3741877bb567..71f6c5f88351d 100644 --- a/src/mame/sinclair/specnext_divmmc.cpp +++ b/src/mame/sinclair/specnext_divmmc.cpp @@ -122,6 +122,9 @@ void specnext_divmmc_device::device_reset() m_cpu_mreq_n = 0; m_cpu_m1_n = 0; + m_retn_seen = 0; + m_divmmc_button = 0; + m_automap_instant_on = 0; m_automap_delayed_on = 0; m_automap_delayed_off = 0; diff --git a/src/mame/sinclair/sprinter.cpp b/src/mame/sinclair/sprinter.cpp index 084f40630ac6b..bdb15e893103e 100644 --- a/src/mame/sinclair/sprinter.cpp +++ b/src/mame/sinclair/sprinter.cpp @@ -31,7 +31,6 @@ Following manual configuration adjustments are recommended for better experience - CDROM CDDA Sound is only connected to ata1:1 - Input Settings > Keyboard Selection > Microsoft Natural Keyboard [root:kbd:ms_naturl]: Enabled -- Use '-rs232 microsoft_mouse' - Input Settings > Input Assignments (this system) > Microsoft 2-Button Serial Mouse (HLE) [root:rs232:microsoft_mouse] Mouse X 3 Analog: Mouse X (MOUSECODE_1_XAXIS) Mouse X 3 Analog Inc: Mouse X - (MOUSECODE_1_XAXIS_NEG_SWITCH)