From 1802f087ba49ed7129e8882de32520ff0c1b2f8d Mon Sep 17 00:00:00 2001 From: holub Date: Sun, 9 Oct 2022 09:28:59 -0400 Subject: [PATCH] sinclair/pentevo.cpp: New working clone. (#10337) * sinclar/atm.cpp: Refactored shadow I/O handling. New working clones ------------------ NedoPC ZX Evolution: BASECONF --- src/devices/machine/spi_sdcard.cpp | 16 + src/mame/mame.lst | 4 + src/mame/mess.flt | 1 + src/mame/sinclair/atm.cpp | 410 +++++++-------- src/mame/sinclair/atm.h | 111 +++++ src/mame/sinclair/beta_m.h | 6 +- src/mame/sinclair/glukrs.cpp | 1 + src/mame/sinclair/glukrs.h | 10 +- src/mame/sinclair/pentagon.cpp | 12 +- src/mame/sinclair/pentevo.cpp | 768 +++++++++++++++++++++++++++++ src/mame/sinclair/qimi.h | 6 +- src/mame/sinclair/scorpion.cpp | 12 +- src/mame/sinclair/spec128.h | 6 +- src/mame/sinclair/spec_snqk.h | 6 +- src/mame/sinclair/specpls3.h | 6 +- src/mame/sinclair/spectrum.h | 6 +- src/mame/sinclair/spectrum_v.cpp | 13 +- src/mame/sinclair/timex.h | 6 +- src/mame/sinclair/tsconf.cpp | 23 +- src/mame/sinclair/tsconf.h | 6 +- src/mame/sinclair/tsconf_m.cpp | 16 +- src/mame/sinclair/zx.h | 6 +- src/mame/sinclair/zx8302.h | 6 +- 23 files changed, 1181 insertions(+), 276 deletions(-) create mode 100644 src/mame/sinclair/atm.h create mode 100644 src/mame/sinclair/pentevo.cpp diff --git a/src/devices/machine/spi_sdcard.cpp b/src/devices/machine/spi_sdcard.cpp index fec16cb2ec2..9166cf8be64 100644 --- a/src/devices/machine/spi_sdcard.cpp +++ b/src/devices/machine/spi_sdcard.cpp @@ -261,6 +261,11 @@ void spi_sdcard_device::do_command() send_data(5, SD_STATE_IDLE); break; + case 9: // CMD9 - SEND_CSD + m_data[0] = 0x00; // TODO + send_data(1, SD_STATE_STBY); + break; + case 10: // CMD10 - SEND_CID m_data[0] = 0x00; // initial R1 response m_data[1] = 0xff; // throwaway byte before data transfer @@ -297,6 +302,11 @@ void spi_sdcard_device::do_command() send_data(1, m_state == SD_STATE_RCV ? SD_STATE_PRG : SD_STATE_TRAN); break; + case 13: // CMD13 - SEND_STATUS + m_data[0] = 0; // TODO + send_data(1, SD_STATE_STBY); + break; + case 16: // CMD16 - SET_BLOCKLEN m_blksize = (u16(m_cmd[3]) << 8) | u16(m_cmd[4]); if (m_harddisk && m_harddisk->set_block_size(m_blksize)) @@ -406,6 +416,12 @@ void spi_sdcard_device::do_command() send_data(5, SD_STATE_DATA); break; + case 59: // CMD59 - CRC_ON_OFF + m_data[0] = 0; + // TODO CRC 1-on, 0-off + send_data(1, SD_STATE_STBY); + break; + default: LOGMASKED(LOG_COMMAND, "SDCARD: Unsupported %02x\n", m_cmd[0] & 0x3f); clean_cmd = false; diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 9497ecc326e..c6b3103c25e 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -3167,6 +3167,10 @@ mwskinst // (c) 2000 Midway @source:sinclair/atm.cpp atm // atmtb2 // +atmtb2plus // + +@source:sinclair/pentevo.cpp +pentevo // @source:acorn/atom.cpp atom // 1979 Acorn Atom diff --git a/src/mame/mess.flt b/src/mame/mess.flt index ca97a1e5f69..265f52d722f 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -756,6 +756,7 @@ siemens/pg685.cpp sinclair/atm.cpp sinclair/elwro800.cpp sinclair/pentagon.cpp +sinclair/pentevo.cpp sinclair/ql.cpp sinclair/scorpion.cpp sinclair/spec128.cpp diff --git a/src/mame/sinclair/atm.cpp b/src/mame/sinclair/atm.cpp index 3be353b43ee..8ff87a33212 100644 --- a/src/mame/sinclair/atm.cpp +++ b/src/mame/sinclair/atm.cpp @@ -8,160 +8,86 @@ NOTES: Current implementation based on ATM Turbo 2+. If anybody wants to validate ATM1, existing code must be moved to atmtb2_state not modified. -TODO: - * ports read - * ATM2+ (compare to ATM2) has only 1M RAM vs 512K - * Mem masks are hardcoded to 1M RAM - * better handling of SHADOW ports - * validate screen timings - *******************************************************************************************/ #include "emu.h" -#include "spec128.h" -#include "specpls3.h" +#include "atm.h" -#include "beta_m.h" -#include "glukrs.h" -#include "bus/centronics/ctronics.h" -#include "sound/ay8910.h" - -namespace { +#include "bus/ata/atapicdr.h" +#include "bus/ata/idehd.h" #define LOG_MEM (1U << 1) #define LOG_VIDEO (1U << 2) #define LOG_WARN (1U << 3) -#define VERBOSE ( /*LOG_MEM | LOG_VIDEO |*/ LOG_WARN ) +#define VERBOSE ( /*LOG_GENERAL | LOG_MEM | LOG_VIDEO |*/ LOG_WARN ) #include "logmacro.h" #define LOGMEM(...) LOGMASKED(LOG_MEM, __VA_ARGS__) #define LOGVIDEO(...) LOGMASKED(LOG_VIDEO, __VA_ARGS__) #define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__) -static constexpr u8 ROM_MASK = 0x7; -static constexpr u8 PEN_RAM_MASK = 0x40; -static constexpr u8 PEN_DOS7FFD_MASK = 0x80; - -class atm_state : public spectrum_128_state +void atm_state::atm_update_cpu() { -public: - atm_state(const machine_config &mconfig, device_type type, const char *tag) - : spectrum_128_state(mconfig, type, tag) - , m_bank_view0(*this, "bank_view0") - , m_bank_view1(*this, "bank_view1") - , m_bank_view2(*this, "bank_view2") - , m_bank_view3(*this, "bank_view3") - , m_bank_rom(*this, "bank_rom%u", 0U) - , m_char_rom(*this, "charrom") - , m_beta(*this, BETA_DISK_TAG) - , m_centronics(*this, "centronics") - , m_glukrs(*this, "glukrs") - , m_palette(*this, "palette") - { } + m_maincpu->set_clock(X1_128_SINCLAIR / 10 * (1 << BIT(m_port_77_data, 3))); // 0 - 3.5MHz, 1 - 7MHz +} - void atm(machine_config &config); - void atmtb2(machine_config &config); - -protected: - void machine_start() override; - void machine_reset() override; - void video_start() override; - - rectangle get_screen_area() override; - u8 get_border_color(u16 hpos, u16 vpos) override; - void spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override; - -private: - u8 beta_neutral_r(offs_t offset); - u8 beta_enable_r(offs_t offset); - u8 beta_disable_r(offs_t offset); - - void atm_ula_w(offs_t offset, u8 data); - void atm_port_ffff_w(offs_t offset, u8 data); - void atm_port_ff77_w(offs_t offset, u8 data); - void atm_port_fff7_w(offs_t offset, u8 data); - void atm_port_eff7_w(offs_t offset, u8 data); - void atm_port_7ffd_w(offs_t offset, u8 data); - - void atm_io(address_map &map); - void atm_mem(address_map &map); - void atm_switch(address_map &map); - - void atm_update_video_mode(); - void atm_update_screen_lo(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - void atm_update_screen_hi(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - void atm_update_screen_tx(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - void atm_update_memory(); - - memory_view m_bank_view0; - memory_view m_bank_view1; - memory_view m_bank_view2; - memory_view m_bank_view3; - required_memory_bank_array<4> m_bank_rom; - optional_region_ptr m_char_rom; // required for ATM2, absent in ATM1 - memory_access<16, 0, 0, ENDIANNESS_LITTLE>::specific m_program; - - required_device m_beta; - required_device m_centronics; - required_device m_glukrs; - required_device m_palette; - - bool is_shadow_active() { return m_beta->is_active(); } - u8 &pen_page(u8 bank) { return m_pages_map[BIT(m_port_7ffd_data, 4)][bank]; } - - bool m_pen; // PEN - extended memory manager - bool m_cpm; - u8 m_pages_map[2][4]; // map: 0,1 - - bool m_pen2; // palette selector - u8 m_rg = 0b011; // 0:320x200lo, 2:640:200hi, 3:256x192zx, 6:80x25txt - u8 m_br3; -}; +void atm_state::atm_update_io() +{ + if (is_dos_active()) + m_io_view.select(0); + else + m_io_view.disable(); +} void atm_state::atm_update_memory() { using views_link = std::reference_wrapper; views_link views[] = { m_bank_view0, m_bank_view1, m_bank_view2, m_bank_view3 }; - LOGMEM("7FFD.%d = %X:", BIT(m_port_7ffd_data, 4), (m_port_7ffd_data & 0x07)); + LOGMEM("PEN%d.%X ", BIT(m_port_7ffd_data, 4), (m_port_7ffd_data & 0x07)); for (auto bank = 0; bank < 4 ; bank++) { - u8 page = m_pen ? pen_page(bank) : ROM_MASK; - if (page & PEN_RAM_MASK) + u16 page = atm_update_memory_get_page(bank); + const char* is_dos7ffd = page & PEN_DOS7FFD_MASK ? "+" : " "; + if (page & PEN_RAMNROM_MASK) { if (page & PEN_DOS7FFD_MASK) - page = (page & 0xf8) | (m_port_7ffd_data & 0x07); - page &= 0x3f; // TODO size dependent - m_bank_ram[bank]->set_entry(page); - views[bank].get().disable(); - LOGMEM(" RA(%X>%X)", m_bank_ram[bank]->entry(), page); + page = merge_ram_with_7ffd(page); + LOGMEM("RA%s%X ", is_dos7ffd, page & ram_pages_mask); + m_bank_ram[bank]->set_entry(page & ram_pages_mask); + if (page & PEN_WRDISBL_MASK) + views[bank].get().select(1); + else + views[bank].get().disable(); } else { - if ((page & PEN_DOS7FFD_MASK) && !BIT(page, 1)) - page = (page & ~1) | is_shadow_active(); - page &= ROM_MASK; - m_bank_rom[bank]->set_entry(page); + if (page & PEN_DOS7FFD_MASK) + page = (page & ~1) | is_dos_active(); + LOGMEM("RO%s%X ", is_dos7ffd, page & rom_pages_mask); + m_bank_rom[bank]->set_entry(page & rom_pages_mask); views[bank].get().select(0); - LOGMEM(" RO(%X>%X)", m_bank_rom[bank]->entry(), page); } } LOGMEM("\n"); } +u16 atm_state::atm_update_memory_get_page(u8 bank) +{ + return m_pen ? pen_page(bank) : (~PEN_RAMNROM_MASK & ~PEN_DOS7FFD_MASK); +} + void atm_state::atm_ula_w(offs_t offset, u8 data) { m_br3 = ~offset & 0x08; spectrum_128_state::spectrum_ula_w(offset, data); } -void atm_state::atm_port_ffff_w(offs_t offset, u8 data) +void atm_state::atm_port_ff_w(offs_t offset, u8 data) { - if(!is_shadow_active()) - return; - if (m_pen2) { + m_beta_drive_selected = data; m_beta->param_w(data); } else @@ -169,6 +95,7 @@ void atm_state::atm_port_ffff_w(offs_t offset, u8 data) // Must read current ULA value (which is doesn't work now) from the BUS. // Good enough as non-border case is too complicated and possibly no software uses it. u8 pen = get_border_color(m_screen->hpos(), m_screen->vpos()); + m_palette_data[pen] = data; m_palette->set_pen_color(pen, (BIT(~data, 1) * 0xaa) | (BIT(~data, 6) * 0x55), (BIT(~data, 4) * 0xaa) | (BIT(~data, 7) * 0x55), @@ -178,8 +105,7 @@ void atm_state::atm_port_ffff_w(offs_t offset, u8 data) void atm_state::atm_port_7ffd_w(offs_t offset, u8 data) { - /* disable paging */ - if (BIT(m_port_7ffd_data, 5)) + if (is_port_7ffd_locked()) return; m_port_7ffd_data = data; @@ -189,18 +115,19 @@ void atm_state::atm_port_7ffd_w(offs_t offset, u8 data) m_screen_location = m_ram->pointer() + ((BIT(m_port_7ffd_data, 3) ? 7 : 5) << 14); } -void atm_state::atm_port_ff77_w(offs_t offset, u8 data) +void atm_state::atm_port_77_w(offs_t offset, u8 data) { - if (!is_shadow_active()) - return; + m_port_77_data = data; m_pen = BIT(offset, 8); - m_cpm = BIT(offset, 9); + m_cpm_n = BIT(offset, 9); + atm_update_io(); + m_pen2 = BIT(offset, 14); - LOGMASKED(LOG_VIDEO | LOG_MEM, "PEN %s, CPM %s, PEN2 %s\n", m_pen ? "on" : "off", m_cpm ? "off" : "on", m_pen2 ? "off" : "on"); + LOGMASKED(LOG_VIDEO | LOG_MEM, "PEN %s, CPM %s, PEN2 %s\n", m_pen ? "on" : "off", m_cpm_n ? "off" : "on", m_pen2 ? "off" : "on"); atm_update_memory(); - m_maincpu->set_clock(X1_128_SINCLAIR / 10 * (1 << BIT(data, 3))); // 0 - 3.5MHz, 1 - 7MHz + atm_update_cpu(); int rg = data & 0x07; if ( m_rg ^ rg ) @@ -210,42 +137,38 @@ void atm_state::atm_port_ff77_w(offs_t offset, u8 data) } } -void atm_state::atm_port_eff7_w(offs_t offset, u8 data) +void atm_state::atm_port_f7_w(offs_t offset, u8 data) { - m_maincpu->set_clock(X1_128_SINCLAIR / 10 * (1 << BIT(data, 4))); // 0 - 3.5MHz, 1 - 7MHz - if (BIT(data, 7)) - m_glukrs->enable(); - else - m_glukrs->disable(); -} - -void atm_state::atm_port_fff7_w(offs_t offset, u8 data) -{ - if(!is_shadow_active()) - return; - u8 bank = offset >> 14; - u8 page = (data & 0xc0) | (~data & 0x3f); + u16 page = (u16(data & 0xc0) << 8) | u8(~data & 0x3f); - LOGMEM("PEN%s.%s = %X %s%d: %02X\n", (page | PEN_DOS7FFD_MASK) ? "+" : "!", BIT(m_port_7ffd_data, 4), data, (page & PEN_RAM_MASK) ? "RAM" : "ROM", bank, page & 0x3f); + LOGMEM("ATM%s=%X %s%d%s%02X\n", BIT(m_port_7ffd_data, 4), data, (page & PEN_RAMNROM_MASK) ? "RAM" : "ROM", bank, (page & PEN_DOS7FFD_MASK) ? "+" : " ", page & 0x3f); pen_page(bank) = page; atm_update_memory(); + atm_update_io(); +} + +INTERRUPT_GEN_MEMBER(atm_state::atm_interrupt) +{ + // 14395=64*224+59 z80(3.5Hz) clocks between INT and screen paper begins. Screen clock is 7Hz. + m_irq_on_timer->adjust(m_screen->time_until_pos(80 - 64, 80) - m_screen->clocks_to_attotime(118)); } rectangle atm_state::get_screen_area() { switch (m_rg) { + case 0b111: case 0b110: // 80x25txt case 0b010: // 640x200 - return rectangle { 208, 208 + 639, 76, 76 + 199 }; + return rectangle { 80, 80 + 639, 80, 80 + 199 }; break; case 0b000: // 320x200 - return rectangle { 104, 104 + 319, 76, 76 + 199 }; + return rectangle { 80, 80 + 319, 80, 80 + 199 }; break; - case 0b011: // 256x192 + case 0b011: // 256x192zx default: - return rectangle { 136, 136 + 255, 80, 80 + 191 }; + return rectangle { 80, 80 + 255, 80, 80 + 191 }; break; } } @@ -257,12 +180,12 @@ u8 atm_state::get_border_color(u16 hpos, u16 vpos) void atm_state::atm_update_video_mode() { - bool zx_scale = BIT(m_rg, 0); + bool zx_scale = m_rg == 0b011; bool double_width = BIT(m_rg, 1) && !zx_scale; u8 border_x = (40 - (32 * !zx_scale)) << double_width; u8 border_y = (40 - (4 * !zx_scale)); rectangle scr = get_screen_area(); - m_screen->configure(448 << double_width, 312, {scr.left() - border_x, scr.right() + border_x, scr.top() - border_y, scr.bottom() + border_y}, m_screen->frame_period().as_attoseconds()); + m_screen->configure(448 << double_width, m_screen->height(), {scr.left() - border_x, scr.right() + border_x, scr.top() - border_y, scr.bottom() + border_y}, m_screen->frame_period().as_attoseconds()); LOGVIDEO("Video mode: %d\n", m_rg); //spectrum_palette(m_palette); @@ -352,7 +275,7 @@ void atm_state::atm_update_screen_tx(screen_device &screen, bitmap_ind16 &bitmap u8 fg = ((attr & 0x40) >> 3) | (attr & 0x07); u8 bg = (((attr & 0x80) >> 1) | (attr & 0x38)) >> 3; - u8 chunk = *(m_char_rom + (*symb_location << 3) + (y & 0x07)); + u8 chunk = *(m_char_location + (*symb_location << 3) + (y & 0x07)); for (u8 i = 0x80; i; i >>= 1) { bitmap.pix(vpos, hpos++) = (chunk & i) ? fg : bg; @@ -368,67 +291,114 @@ u8 atm_state::beta_neutral_r(offs_t offset) u8 atm_state::beta_enable_r(offs_t offset) { - if (!machine().side_effects_disabled()) { - u8 page = pen_page(0); - if (!(page & PEN_RAM_MASK) && !is_shadow_active()) { + if (!machine().side_effects_disabled() && !m_beta->is_active()) + { + bool is_rom0 = !(atm_update_memory_get_page(0) & PEN_RAMNROM_MASK); + if (is_rom0 || !m_cpm_n) + { m_beta->enable(); atm_update_memory(); + atm_update_io(); } } - return m_program.read_byte(offset + 0x3d00); + return beta_neutral_r(offset + 0x3d00); } u8 atm_state::beta_disable_r(offs_t offset) { - if (!machine().side_effects_disabled()) { - if (is_shadow_active() && m_cpm) { + if (!machine().side_effects_disabled() && m_beta->is_active()) + { + if (m_cpm_n) + { m_beta->disable(); atm_update_memory(); + atm_update_io(); } } - return m_program.read_byte(offset + 0x4000); + return beta_neutral_r(offset + 0x4000); +} + +u8 atm_state::ata_r(offs_t offset) +{ + u8 ata_offset = BIT(offset, 5, 3); + u16 data = m_ata->cs0_r(ata_offset); + + if (!machine().side_effects_disabled() && !ata_offset) + m_ata_data_latch = data >> 8; + + return data & 0xff; +} + +void atm_state::ata_w(offs_t offset, u8 data) +{ + u8 ata_offset = BIT(offset, 5, 3); + u16 ata_data = data; + if (!ata_offset) + ata_data |= m_ata_data_latch << 8; + + m_ata->cs0_w(ata_offset, ata_data); +} + +template void atm_state::atm_ram_w(offs_t offset, u8 data) +{ + if (m_rg == 0b011 && (m_bank_ram[Bank]->entry() == (BIT(m_port_7ffd_data, 3) ? 7 : 5)) && offset < 0x1b00) + m_screen->update_now(); + + ((u8*)m_bank_ram[Bank]->base())[offset] = data; } void atm_state::atm_mem(address_map &map) { - map(0x0000, 0x3fff).bankrw(m_bank_ram[0]); + map(0x0000, 0x3fff).bankr(m_bank_ram[0]).w(FUNC(atm_state::atm_ram_w<0>)); map(0x0000, 0x3fff).view(m_bank_view0); m_bank_view0[0](0x0000, 0x3fff).bankr(m_bank_rom[0]).nopw(); + m_bank_view0[1](0x0000, 0x3fff).nopw(); // RO RAM - map(0x4000, 0x7fff).bankrw(m_bank_ram[1]); + map(0x4000, 0x7fff).bankr(m_bank_ram[1]).w(FUNC(atm_state::atm_ram_w<1>)); map(0x4000, 0x7fff).view(m_bank_view1); m_bank_view1[0](0x4000, 0x7fff).bankr(m_bank_rom[1]).nopw(); + m_bank_view1[1](0x4000, 0x7fff).nopw(); - map(0x8000, 0xbfff).bankrw(m_bank_ram[2]); + map(0x8000, 0xbfff).bankr(m_bank_ram[2]).w(FUNC(atm_state::atm_ram_w<2>)); map(0x8000, 0xbfff).view(m_bank_view2); m_bank_view2[0](0x8000, 0xbfff).bankr(m_bank_rom[2]).nopw(); + m_bank_view2[1](0x8000, 0xbfff).nopw(); - map(0xc000, 0xffff).bankrw(m_bank_ram[3]); + map(0xc000, 0xffff).bankr(m_bank_ram[3]).w(FUNC(atm_state::atm_ram_w<3>)); map(0xc000, 0xffff).view(m_bank_view3); m_bank_view3[0](0xc000, 0xffff).bankr(m_bank_rom[3]).nopw(); + m_bank_view3[1](0xc000, 0xffff).nopw(); } void atm_state::atm_io(address_map &map) { map.unmap_value_high(); - map(0x001f, 0x001f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::status_r), FUNC(beta_disk_device::command_w)); - map(0x003f, 0x003f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w)); - map(0x005f, 0x005f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)); - map(0x007f, 0x007f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)); - map(0x00ff, 0x00ff).mirror(0xff00).r(m_beta, FUNC(beta_disk_device::state_r)); - map(0x00ff, 0x00ff).mirror(0xff00).w(FUNC(atm_state::atm_port_ffff_w)); + + // PORTS: Always map(0x00f6, 0x00f6).select(0xff08).rw(FUNC(atm_state::spectrum_ula_r), FUNC(atm_state::atm_ula_w)); map(0x00fb, 0x00fb).mirror(0xff00).w("cent_data_out", FUNC(output_latch_device::write)); map(0x00fd, 0x00fd).mirror(0xff00).w(FUNC(atm_state::atm_port_7ffd_w)); - map(0x0077, 0x0077).select(0xff00).w(FUNC(atm_state::atm_port_ff77_w)); - map(0x00f7, 0x00f7).select(0xff00).w(FUNC(atm_state::atm_port_fff7_w)); - map(0xeff7, 0xeff7).w(FUNC(atm_state::atm_port_eff7_w)); - map(0xdef7, 0xdef7).mirror(0x0100).w(m_glukrs, FUNC(glukrs_device::address_w)); - map(0xbff7, 0xbff7).r(m_glukrs, FUNC(glukrs_device::data_r)); - map(0xbef7, 0xbef7).rw(m_glukrs, FUNC(glukrs_device::data_r), FUNC(glukrs_device::data_w)); + map(0xfadf, 0xfadf).mirror(0x0500).nopr(); // TODO 0xfadf, 0xfbdf, 0xffdf Kempston Mouse map(0x8000, 0x8000).mirror(0x3ffd).w("ay8912", FUNC(ay8910_device::data_w)); map(0xc000, 0xc000).mirror(0x3ffd).rw("ay8912", FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_w)); + + // PORTS: Shadow + map(0x0000, 0xffff).view(m_io_view); + m_io_view[0](0x001f, 0x001f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::status_r), FUNC(beta_disk_device::command_w)); + m_io_view[0](0x003f, 0x003f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w)); + m_io_view[0](0x005f, 0x005f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)); + m_io_view[0](0x007f, 0x007f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)); + m_io_view[0](0x00ff, 0x00ff).mirror(0xff00).r(m_beta, FUNC(beta_disk_device::state_r)).w(FUNC(atm_state::atm_port_ff_w)); + + m_io_view[0](0x0077, 0x0077).select(0xff00).w(FUNC(atm_state::atm_port_77_w)); + m_io_view[0](0x00f7, 0x00f7).select(0xff00).w(FUNC(atm_state::atm_port_f7_w)); + + // A: .... .... nnn0 1111 + m_io_view[0](0x000f, 0x000f).select(0xffe0).rw(FUNC(atm_state::ata_r), FUNC(atm_state::ata_w)); + // A: .... ...1 0000 1111 + m_io_view[0](0x010f, 0x010f).mirror(0xfe00).lrw8(NAME([this](offs_t offset) { return m_ata_data_latch; }) + , NAME([this](offs_t offset, u8 data) { m_ata_data_latch = data; })); } void atm_state::atm_switch(address_map &map) @@ -443,18 +413,23 @@ void atm_state::machine_start() { spectrum_128_state::machine_start(); + save_item(NAME(m_port_77_data)); save_item(NAME(m_pen)); - save_item(NAME(m_cpm)); + save_item(NAME(m_cpm_n)); save_item(NAME(m_pages_map)); save_item(NAME(m_pen2)); save_item(NAME(m_rg)); save_item(NAME(m_br3)); + save_item(NAME(m_beta_drive_selected)); // reconfigure ROMs memory_region *rom = memregion("maincpu"); + rom_pages_mask = (rom->bytes() - 0x10001) / 0x4000; for (auto i = 0; i < 4; i++) - m_bank_rom[i]->configure_entries(0, 8, rom->base() + 0x10000, 0x4000); - m_bank_ram[0]->configure_entries(0, m_ram->size() / 0x4000, m_ram->pointer(), 0x4000); + m_bank_rom[i]->configure_entries(0, rom_pages_mask + 1, rom->base() + 0x10000, 0x4000); // todo dyn + + ram_pages_mask = (m_ram->size() - 1) / 0x4000; + m_bank_ram[0]->configure_entries(0, ram_pages_mask + 1, m_ram->pointer(), 0x4000); m_maincpu->space(AS_PROGRAM).specific(m_program); } @@ -462,19 +437,23 @@ void atm_state::machine_start() void atm_state::machine_reset() { m_beta->enable(); - m_glukrs->disable(); + m_beta_drive_selected = 0; m_port_7ffd_data = 0; m_port_1ffd_data = -1; + m_port_77_data = 0; m_br3 = 0; - atm_port_ff77_w(0x4000, 3); // CPM=0(on), PEN=0(off), PEN2=1(off); vmode: zx + m_palette_data = { 0xff }; + atm_port_77_w(0x4000, 3); // m_port_77_data: CPM=0(on), PEN=0(off), PEN2=1(off); vmode: zx } void atm_state::video_start() { spectrum_state::video_start(); m_screen_location = m_ram->pointer() + (5 << 14); + m_char_location = m_char_rom; + subdevice("gfxdecode")->gfx(0)->set_source(m_char_location); m_contention_pattern = {}; } @@ -493,7 +472,7 @@ static const gfx_layout spectrum_charlayout = static const gfx_layout atm_charlayout = { 8, 8, // 8 x 8 characters - 256, // 96 characters + 256, // 256 characters 1, // 1 bits per pixel { 0 }, // no bitplanes { STEP8(0, 1) }, // x offsets @@ -502,14 +481,21 @@ static const gfx_layout atm_charlayout = }; static GFXDECODE_START( gfx_atm ) + GFXDECODE_ENTRY( "maincpu", 0, atm_charlayout, 7, 1 ) // charrom GFXDECODE_ENTRY( "maincpu", 0x1fd00, spectrum_charlayout, 7, 1 ) GFXDECODE_END static GFXDECODE_START( gfx_atmtb2 ) - GFXDECODE_ENTRY( "charrom", 0, atm_charlayout, 7, 1 ) + GFXDECODE_ENTRY( "maincpu", 0, atm_charlayout, 7, 1 ) // charrom GFXDECODE_ENTRY( "maincpu", 0x13d00, spectrum_charlayout, 7, 1 ) GFXDECODE_END +static void atm_ata_devices(device_slot_interface &device) +{ + device.option_add("hdd", IDE_HARDDISK); + device.option_add("cdrom", ATAPI_CDROM); +} + void atm_state::atm(machine_config &config) { spectrum_128(config); @@ -517,13 +503,14 @@ void atm_state::atm(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &atm_state::atm_mem); m_maincpu->set_addrmap(AS_IO, &atm_state::atm_io); m_maincpu->set_addrmap(AS_OPCODES, &atm_state::atm_switch); + m_maincpu->set_vblank_int("screen", FUNC(atm_state::atm_interrupt)); m_maincpu->nomreq_cb().set_nop(); m_screen->set_raw(X1_128_SINCLAIR / 5, 448, 312, {get_screen_area().left() - 40, get_screen_area().right() + 40, get_screen_area().top() - 40, get_screen_area().bottom() + 40}); subdevice("gfxdecode")->set_info(gfx_atm); BETA_DISK(config, m_beta, 0); - GLUKRS(config, m_glukrs); + ATA_INTERFACE(config, m_ata).options(atm_ata_devices, nullptr, nullptr, false);; CENTRONICS(config, m_centronics, centronics_devices, "covox"); output_latch_device ¢_data_out(OUTPUT_LATCH(config, "cent_data_out")); @@ -532,40 +519,63 @@ void atm_state::atm(machine_config &config) config.device_remove("exp"); } + +/****************************************************************************** + * ATM Turbo 2 + * ***************************************************************************/ void atm_state::atmtb2(machine_config &config) { atm(config); - // 1M in ATM2+ only. TODO mem masks for custom size - m_ram->set_default_size("1M");//.set_extra_options("128K,256K,512K,1M"); + m_ram->set_default_size("512K").set_extra_options("128K,256K"); + subdevice("gfxdecode")->set_info(gfx_atmtb2); } +/****************************************************************************** + * ATM Turbo 2+ + * ***************************************************************************/ +void atm_state::atmtb2plus(machine_config &config) +{ + atmtb2(config); + + m_ram->set_default_size("1M").set_extra_options("128K,256K,512K"); +} + + /*************************************************************************** - - Game driver(s) - -***************************************************************************/ - + * Game driver(s) + * ************************************************************************/ ROM_START( atm ) - ROM_REGION(0x030000, "maincpu", ROMREGION_ERASEFF) + ROM_REGION(0x020000, "maincpu", ROMREGION_ERASEFF) ROM_SYSTEM_BIOS(0, "v1", "v.1.03") - ROMX_LOAD( "atm103.rom", 0x020000, 0x10000, CRC(4912e249) SHA1(a4adff05bb215dd126c47201b36956115b8fed76), ROM_BIOS(0)) - ROM_SYSTEM_BIOS(1, "v2", "v.1.06 joined") - ROMX_LOAD( "atm106.rom", 0x020000, 0x10000, CRC(75350b37) SHA1(2afc9994f026645c74b6c4b35bcee2e0bc0d6edc), ROM_BIOS(1)) - ROM_SYSTEM_BIOS(2, "v3", "v.1.06") - ROMX_LOAD( "atm106-1.rom", 0x020000, 0x4000, CRC(658c98f1) SHA1(1ec694795aa6cac10147e58f38a9db0bdf7ed89b), ROM_BIOS(2)) - ROMX_LOAD( "atm106-2.rom", 0x024000, 0x4000, CRC(8fe367f9) SHA1(56de8fd39061663b9c315b74fd3c31acddae279c), ROM_BIOS(2)) - ROMX_LOAD( "atm106-3.rom", 0x028000, 0x4000, CRC(124ad9e0) SHA1(d07fcdeca892ee80494d286ea9ea5bf3928a1aca), ROM_BIOS(2)) - ROMX_LOAD( "atm106-4.rom", 0x02c000, 0x4000, CRC(f352f2ab) SHA1(6045500ab01be708cef62327e9821b4a358a4673), ROM_BIOS(2)) - ROM_SYSTEM_BIOS(3, "v4", "v.1.03rs") - ROMX_LOAD( "atm103rs.rom", 0x020000, 0x10000, CRC(cdec1dfb) SHA1(08190807c6b110cb2e657d8e7d0ad18668915375), ROM_BIOS(3)) + ROMX_LOAD( "atm103.rom", 0x010000, 0x10000, CRC(4912e249) SHA1(a4adff05bb215dd126c47201b36956115b8fed76), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "v2", "v.1.03rs") + ROMX_LOAD( "atm103rs.rom", 0x010000, 0x10000, CRC(cdec1dfb) SHA1(08190807c6b110cb2e657d8e7d0ad18668915375), ROM_BIOS(1)) ROM_END ROM_START( atmtb2 ) + ROM_REGION(0x020000, "maincpu", ROMREGION_ERASEFF) + ROM_SYSTEM_BIOS(0, "v1.06", "BIOS v1.06") // joined dump + ROMX_LOAD( "atm106.rom", 0x010000, 0x10000, CRC(75350b37) SHA1(2afc9994f026645c74b6c4b35bcee2e0bc0d6edc), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "v1.06a", "BIOS v1.06 (split)") + ROMX_LOAD( "atm106-1.rom", 0x010000, 0x4000, CRC(658c98f1) SHA1(1ec694795aa6cac10147e58f38a9db0bdf7ed89b), ROM_BIOS(1)) + ROMX_LOAD( "atm106-2.rom", 0x014000, 0x4000, CRC(8fe367f9) SHA1(56de8fd39061663b9c315b74fd3c31acddae279c), ROM_BIOS(1)) + ROMX_LOAD( "atm106-3.rom", 0x018000, 0x4000, CRC(124ad9e0) SHA1(d07fcdeca892ee80494d286ea9ea5bf3928a1aca), ROM_BIOS(1)) + ROMX_LOAD( "atm106-4.rom", 0x01c000, 0x4000, CRC(f352f2ab) SHA1(6045500ab01be708cef62327e9821b4a358a4673), ROM_BIOS(1)) + + ROM_REGION(0x01000, "keyboard", ROMREGION_ERASEFF) + ROM_LOAD( "rf2ve3.rom", 0x0000, 0x0580, CRC(35e0f9ec) SHA1(adcf14758fab8472cfa0167af7e8326c66416416)) // XT Keyboard + ROM_LOAD( "rfat710.rom", 0x0600, 0x0680, CRC(03734365) SHA1(6cb6311727fad9bc4ccb18919c3c39b37529b8e6)) // AT Keyboard + + ROM_REGION(0x08000, "charrom", ROMREGION_ERASEFF) // Char gen rom + ROM_LOAD( "sgen.rom", 0x0000, 0x0800, CRC(1f4387d6) SHA1(93b3774dc8a486643a1bdd48c606b0c84fa0e22b)) +ROM_END + +ROM_START( atmtb2plus ) ROM_REGION(0x030000, "maincpu", ROMREGION_ERASEFF) - ROM_DEFAULT_BIOS("v1.07.13") + ROM_DEFAULT_BIOS("v1.37") ROM_SYSTEM_BIOS(0, "v1.07.12", "BIOS v1.07.12, CP/M v2.2, TR-DOS v5.03") // joined dump ROMX_LOAD( "atmtb2.rom", 0x020000, 0x10000,CRC(05218c26) SHA1(71ed9864e7aa85131de97cf1e53dc152e7c79488), ROM_BIOS(0)) ROM_SYSTEM_BIOS(1, "v1.07.12a", "BIOS v1.07.12, CP/M v2.2, TR-DOS v5.03 (split)") @@ -579,20 +589,14 @@ ROM_START( atmtb2 ) ROMX_LOAD( "atmtb2x37xt.rom", 0x010000, 0x20000, CRC(e5ef44d9) SHA1(3fbb9ace7cb031e7365c19e4f8b67ed366e24064), ROM_BIOS(3)) ROM_REGION(0x01000, "keyboard", ROMREGION_ERASEFF) - // XT Keyboard - ROM_LOAD( "rf2ve3.rom", 0x0000, 0x0580, CRC(35e0f9ec) SHA1(adcf14758fab8472cfa0167af7e8326c66416416)) - // AT Keyboard - ROM_LOAD( "rfat710.rom", 0x0600, 0x0680, CRC(03734365) SHA1(6cb6311727fad9bc4ccb18919c3c39b37529b8e6)) + ROM_LOAD( "rf2ve3.rom", 0x0000, 0x0580, CRC(35e0f9ec) SHA1(adcf14758fab8472cfa0167af7e8326c66416416)) // XT Keyboard + ROM_LOAD( "rfat710.rom", 0x0600, 0x0680, CRC(03734365) SHA1(6cb6311727fad9bc4ccb18919c3c39b37529b8e6)) // AT Keyboard - ROM_REGION(0x08000, "charrom", ROMREGION_ERASEFF) - // Char gen rom + ROM_REGION(0x08000, "charrom", ROMREGION_ERASEFF) // Char gen rom ROM_LOAD( "sgen.rom", 0x0000, 0x0800, CRC(1f4387d6) SHA1(93b3774dc8a486643a1bdd48c606b0c84fa0e22b)) ROM_END -} // Anonymous namespace - - -/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -COMP( 1991, atm, spec128, 0, atm, spec_plus, atm_state, empty_init, "MicroART", "ATM-Turbo (ATM-CP)", MACHINE_NOT_WORKING) -COMP( 1992, atmtb2, spec128, 0, atmtb2, spec_plus, atm_state, empty_init, "MicroART", "ATM-Turbo 2", MACHINE_SUPPORTS_SAVE) -//COMP( 1993, atmtb2p, spec128, 0, atmtb2p, spec_plus, atm_state, empty_init, "MicroART", "ATM-Turbo 2+", MACHINE_NOT_WORKING) // only supports 1M RAM vs. 512K in atmtb2 +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP( 1991, atm, spec128, 0, atm, spec_plus, atm_state, empty_init, "MicroART", "ATM-Turbo (ATM-CP)", MACHINE_NOT_WORKING) +COMP( 1992, atmtb2, spec128, 0, atmtb2, spec_plus, atm_state, empty_init, "MicroART", "ATM-Turbo 2", MACHINE_SUPPORTS_SAVE) +COMP( 1993, atmtb2plus, spec128, 0, atmtb2plus, spec_plus, atm_state, empty_init, "MicroART", "ATM-Turbo 2+", MACHINE_SUPPORTS_SAVE) diff --git a/src/mame/sinclair/atm.h b/src/mame/sinclair/atm.h new file mode 100644 index 00000000000..d68f8c929a7 --- /dev/null +++ b/src/mame/sinclair/atm.h @@ -0,0 +1,111 @@ +// license:BSD-3-Clause +#ifndef MAME_SINCLAIR_ATM_H +#define MAME_SINCLAIR_ATM_H + +#pragma once + +#include "spec128.h" + +#include "beta_m.h" +#include "bus/ata/ataintf.h" +#include "bus/centronics/ctronics.h" +#include "sound/ay8910.h" + +class atm_state : public spectrum_128_state +{ +public: + atm_state(const machine_config &mconfig, device_type type, const char *tag) + : spectrum_128_state(mconfig, type, tag) + , m_bank_view0(*this, "bank_view0") + , m_bank_view1(*this, "bank_view1") + , m_bank_view2(*this, "bank_view2") + , m_bank_view3(*this, "bank_view3") + , m_io_view(*this, "io_view") + , m_bank_rom(*this, "bank_rom%u", 0U) + , m_char_rom(*this, "charrom") + , m_beta(*this, BETA_DISK_TAG) + , m_ata(*this, "ata") + , m_centronics(*this, "centronics") + , m_palette(*this, "palette") + { } + + void atm(machine_config &config); + void atmtb2(machine_config &config); + void atmtb2plus(machine_config &config); + +protected: + static constexpr u16 PEN_WRDISBL_MASK = 1 << 13; + static constexpr u16 PEN_RAMNROM_MASK = 1 << 14; // 1-RAM, 0-ROM + static constexpr u16 PEN_DOS7FFD_MASK = 1 << 15; + + virtual void machine_start() override; + virtual void machine_reset() override; + virtual void video_start() override; + + void atm_io(address_map &map); + void atm_mem(address_map &map); + void atm_switch(address_map &map); + template void atm_ram_w(offs_t offset, u8 data); + + u8 beta_neutral_r(offs_t offset); + u8 beta_enable_r(offs_t offset); + u8 beta_disable_r(offs_t offset); + u8 ata_r(offs_t offset); + void ata_w(offs_t offset, u8 data); + + void atm_ula_w(offs_t offset, u8 data); + virtual void atm_port_ff_w(offs_t offset, u8 data); + void atm_port_77_w(offs_t offset, u8 data); + void atm_port_f7_w(offs_t offset, u8 data); + void atm_port_7ffd_w(offs_t offset, u8 data); + + virtual void atm_update_cpu(); + virtual void atm_update_io(); + u16 &pen_page(u8 bank) { return m_pages_map[BIT(m_port_7ffd_data, 4)][bank]; } + void atm_update_memory(); + virtual u8 merge_ram_with_7ffd(u8 ram_page) { return (ram_page & ~0x07) | (m_port_7ffd_data & 0x07); } + virtual bool is_port_7ffd_locked() { return BIT(m_port_7ffd_data, 5); }; + bool is_dos_active() { return !m_cpm_n || m_beta->is_active(); } + + virtual void spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override; + void atm_update_video_mode(); + void atm_update_screen_lo(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + void atm_update_screen_hi(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + void atm_update_screen_tx(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + virtual u16 atm_update_memory_get_page(u8 bank); + virtual u8 get_border_color(u16 hpos, u16 vpos) override; + rectangle get_screen_area() override; + INTERRUPT_GEN_MEMBER(atm_interrupt); + + memory_view m_bank_view0; + memory_view m_bank_view1; + memory_view m_bank_view2; + memory_view m_bank_view3; + memory_view m_io_view; + required_memory_bank_array<4> m_bank_rom; + optional_region_ptr m_char_rom; // required for ATM2, absent in ATM1 + memory_access<16, 0, 0, ENDIANNESS_LITTLE>::specific m_program; + + required_device m_beta; + required_device m_ata; + required_device m_centronics; + required_device m_palette; + + u8 *m_char_location; + u8 rom_pages_mask; + u8 ram_pages_mask; + + u8 m_port_77_data; + bool m_pen; // PEN - extended memory manager + bool m_cpm_n; + u16 m_pages_map[2][4]; // map: 0,1 + + bool m_pen2; // palette selector + u8 m_rg = 0b011; // 0:320x200lo, 2:640:200hi, 3:256x192zx, 6:80x25txt + u8 m_br3; + std::vector m_palette_data; + u8 m_ata_data_latch; + u8 m_beta_drive_selected; +}; + +#endif // MAME_SINCLAIR_ATM_H diff --git a/src/mame/sinclair/beta_m.h b/src/mame/sinclair/beta_m.h index 43fd8323b16..72ed4353cd0 100644 --- a/src/mame/sinclair/beta_m.h +++ b/src/mame/sinclair/beta_m.h @@ -9,8 +9,8 @@ 04/05/2008 Created by Miodrag Milanovic *********************************************************************/ -#ifndef MAME_MACHINE_BETA_H -#define MAME_MACHINE_BETA_H +#ifndef MAME_SINCLAIR_BETA_H +#define MAME_SINCLAIR_BETA_H #pragma once @@ -67,4 +67,4 @@ private: DECLARE_DEVICE_TYPE(BETA_DISK, beta_disk_device) -#endif // MAME_MACHINE_BETA_H +#endif // MAME_SINCLAIR_BETA_H diff --git a/src/mame/sinclair/glukrs.cpp b/src/mame/sinclair/glukrs.cpp index e8345a1657c..9c6f33f2453 100644 --- a/src/mame/sinclair/glukrs.cpp +++ b/src/mame/sinclair/glukrs.cpp @@ -3,6 +3,7 @@ /*************************************************************************** Mr Gluk Reset Service + TODO implementation must be based on KR512VI1 clone MC146818 Refs: https://zxart.ee/spa/software/prikladnoe-po/electronics/pzu/mr-gluk-reset-service-663/mr-gluk-reset-service-663/action:viewFile/id:250389/fileId:814961/ diff --git a/src/mame/sinclair/glukrs.h b/src/mame/sinclair/glukrs.h index 68c953e4374..44b2e300e65 100644 --- a/src/mame/sinclair/glukrs.h +++ b/src/mame/sinclair/glukrs.h @@ -15,12 +15,12 @@ class glukrs_device : public device_t, public: glukrs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 32'768); - void enable() { m_glukrs_active = true; }; - void disable() { m_glukrs_active = false; }; - bool is_active() { return m_glukrs_active; }; + void enable() { m_glukrs_active = true; } + void disable() { m_glukrs_active = false; } + bool is_active() { return m_glukrs_active; } u8 address_r() { return m_glukrs_active ? m_address : 0xff; } - void address_w(u8 address) { if (m_glukrs_active) m_address = address; }; - u8 data_r() { return m_glukrs_active ? m_cmos[m_address] : 0xff; }; + void address_w(u8 address) { if (m_glukrs_active) m_address = address; } + u8 data_r() { return m_glukrs_active ? m_cmos[m_address] : 0xff; } void data_w(u8 data) { if (m_glukrs_active) { m_cmos[m_address] = data; } } TIMER_CALLBACK_MEMBER(timer_callback); diff --git a/src/mame/sinclair/pentagon.cpp b/src/mame/sinclair/pentagon.cpp index 1281f59cf09..e8ed652d65a 100644 --- a/src/mame/sinclair/pentagon.cpp +++ b/src/mame/sinclair/pentagon.cpp @@ -101,8 +101,10 @@ u8 pentagon_state::beta_neutral_r(offs_t offset) u8 pentagon_state::beta_enable_r(offs_t offset) { - if (!(machine().side_effects_disabled())) { - if (m_bank_rom[0]->entry() == 1) { + if (!machine().side_effects_disabled()) + { + if (m_bank_rom[0]->entry() == 1) + { m_beta->enable(); m_bank_rom[0]->set_entry(3); } @@ -112,8 +114,10 @@ u8 pentagon_state::beta_enable_r(offs_t offset) u8 pentagon_state::beta_disable_r(offs_t offset) { - if (!(machine().side_effects_disabled())) { - if (m_beta->is_active()) { + if (!machine().side_effects_disabled()) + { + if (m_beta->is_active()) + { m_beta->disable(); m_bank_rom[0]->set_entry(BIT(m_port_7ffd_data, 4)); } diff --git a/src/mame/sinclair/pentevo.cpp b/src/mame/sinclair/pentevo.cpp new file mode 100644 index 00000000000..4b5a157e9de --- /dev/null +++ b/src/mame/sinclair/pentevo.cpp @@ -0,0 +1,768 @@ +// license:BSD-3-Clause +// copyright-holders:Andrei I. Holub +/*************************************************************************** + +ZX Evolution: BASECONF machine driver. +Implementation: Revision C + +Hobby computer ZX Evolution is Spectrum-compatible with extensions. + +Hardware (ZX Evolution): +- Z80 3.5 MHz (classic mode)/ 7 MHz (turbo mode without CPU wait cycles)/ 14 MHz (mega turbo with CPU wait cycles); +- 4 Mb RAM, 512Kb ROM; +- MiniITX board (172x170mm), 2 ZXBUS slots, power ATX or +5,+12V; +- Based on fpga (Altera EP1K50); +- Peripheral MCU ATMEGA128; +- PS/2 keyboard and mouse support; +- Floppy (WDC1793) Beta-disk compatible interface, IDE (one channel, up to 2 devices on master/slave mode), SD(HC) card, RS232; +- Sound: AY, Beeper, Covox (PWM); +- Real-time clock. + +Refs: +ZxEvo: http://nedopc.com/zxevo/zxevo_eng.php + Principal scheme (rev. C) :: http://nedopc.com/zxevo/zxevo_sch_revc.pdf + Montage scheme (rev. C) :: http://nedopc.com/zxevo/zxevo_mon_revc.pdf + +TODO: + * Keyboard enabled + * zx 16c + +*******************************************************************************************/ + +#include "emu.h" +#include "atm.h" + +#include "glukrs.h" +#include "machine/pckeybrd.h" +#include "machine/spi_sdcard.h" +#include "machine/timer.h" + +#define LOG_MEM (1U << 1) +#define LOG_VIDEO (1U << 2) +#define LOG_WARN (1U << 3) + +#define VERBOSE ( /*LOG_GENERAL | LOG_MEM | LOG_VIDEO |*/ LOG_WARN ) +#include "logmacro.h" + +#define LOGMEM(...) LOGMASKED(LOG_MEM, __VA_ARGS__) +#define LOGVIDEO(...) LOGMASKED(LOG_VIDEO, __VA_ARGS__) +#define LOGWARN(...) LOGMASKED(LOG_WARN, __VA_ARGS__) + +namespace { + +class pentevo_state : public atm_state +{ +public: + pentevo_state(const machine_config &mconfig, device_type type, const char *tag) + : atm_state(mconfig, type, tag) + , m_gfxdecode(*this, "gfxdecode") + , m_char_ram(*this, "char_ram") + , m_io_dos_view(*this, "io_dos_view") + , m_glukrs(*this, "glukrs") + , m_sdcard(*this, "sdcard") + , m_keyboard(*this, "pc_keyboard") + , m_io_mouse(*this, "mouse_input%u", 1U) + { } + + void pentevo(machine_config &config); + +protected: + void machine_start() override; + void machine_reset() override; + void video_start() override; + +private: + void init_mem_write(); + void pentevo_io(address_map &map); + + void atm_port_ff_w(offs_t offset, u8 data) override; + void pentevo_port_7f7_w(offs_t offset, u8 data); + void pentevo_port_bf7_w(offs_t offset, u8 data); + void pentevo_port_eff7_w(offs_t offset, u8 data); + u8 pentevo_port_bf_r(offs_t offset); + void pentevo_port_bf_w(offs_t offset, u8 data); + u8 pentevo_port_0nbd_r(offs_t offset); + u8 pentevo_port_1nbd_r(offs_t offset); + void pentevo_port_1nbd_w(offs_t offset, u8 data); + + void spi_port_77_w(offs_t offset, u8 data); + u8 spi_port_57_r(offs_t offset); + void spi_port_57_w(offs_t offset, u8 data); + void spi_miso_w(u8 data); + u8 nemo_ata_r(u8 cmd); + void nemo_ata_w(u8 cmd, u8 data); + u8 gluk_data_r(offs_t offset); + void gluk_data_w(offs_t offset, u8 data); + + TIMER_DEVICE_CALLBACK_MEMBER(nmi_check_callback); + void nmi_on(); + + void atm_update_cpu() override; + void atm_update_io() override; + u8 merge_ram_with_7ffd(u8 ram_page) override; + bool is_port_7ffd_locked() override { return !is_pent1024() && BIT(m_port_7ffd_data, 5); } + bool is_pent1024() { return !BIT(m_port_eff7_data, 2); } + + void spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override; + void pentevo_update_screen_zxhw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + void pentevo_update_screen_zx16(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + void pentevo_update_screen_tx(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + u16 atm_update_memory_get_page(u8 bank) override; + INTERRUPT_GEN_MEMBER(pentevo_interrupt); + + required_device m_gfxdecode; + required_device m_char_ram; + memory_view m_io_dos_view; + + required_device m_glukrs; + required_device m_sdcard; + required_device m_keyboard; + required_ioport_array<3> m_io_mouse; + + u8 m_port_bf_data; + u8 m_port_eff7_data; + u8 m_beta_drive_virtual; + + u8 m_gluk_ext; + bool m_ata_data_hi_ready; + u16 m_nmi_trap_offset; + bool m_nmi_active; + u8 m_nmi_active_flip_countdown; + + u8 m_zctl_di = 0; + u8 m_zctl_cs = 0; +}; + + +/****************************************************************************** + * ZX Evolution: BASECONF + * ***************************************************************************/ + +void pentevo_state::atm_update_cpu() +{ + u8 multiplier = BIT(m_port_77_data, 3) ? 4 : (2 - BIT(m_port_eff7_data, 4)); + m_maincpu->set_clock(X1_128_SINCLAIR / 10 * multiplier); +} + +void pentevo_state::atm_update_io() +{ + if (BIT(m_port_bf_data, 0) || is_dos_active()) + { + m_io_view.select(0); + if (m_beta_drive_selected && m_beta_drive_virtual == m_beta_drive_selected) + m_io_dos_view.disable(); + else + m_io_dos_view.select(0); + + m_glukrs->enable(); + } + else + { + m_io_view.disable(); + if (BIT(m_port_eff7_data, 7)) + m_glukrs->enable(); + else + m_glukrs->disable(); + } +} + +u16 pentevo_state::atm_update_memory_get_page(u8 bank) +{ + if (bank == 0) + { + if (BIT(m_port_eff7_data, 3)) + return ~PEN_RAMNROM_MASK & 0x00; + else if (m_nmi_active) + return PEN_RAMNROM_MASK | 0xff; + else if (m_beta_drive_selected && m_beta_drive_virtual == m_beta_drive_selected) + return PEN_RAMNROM_MASK | 0xfe; + } + return atm_state::atm_update_memory_get_page(bank); +} + +void pentevo_state::atm_port_ff_w(offs_t offset, u8 data) +{ + if (BIT(m_port_bf_data, 5) && !m_pen2) + { + u8 pen = get_border_color(m_screen->hpos(), m_screen->vpos()); + m_palette_data[pen] = data; + m_palette->set_pen_color(pen, + (BIT(~data, 1) * 0x88) | (BIT(~data, 6) * 0x44) | (BIT(~offset, 9) * 0x22) | (BIT(~offset, 14) * 0x11), + (BIT(~data, 4) * 0x88) | (BIT(~data, 7) * 0x44) | (BIT(~offset, 12) * 0x22) | (BIT(~offset, 15) * 0x11), + (BIT(~data, 0) * 0x88) | (BIT(~data, 5) * 0x44) | (BIT(~offset, 8) * 0x22) | (BIT(~offset, 13) * 0x11)); + } + else + { + atm_state::atm_port_ff_w(offset, data); + } +} + +TIMER_DEVICE_CALLBACK_MEMBER(pentevo_state::nmi_check_callback) +{ + if ((m_io_nmi->read() & 0x01) && !m_nmi_active) + nmi_on(); +} + +void pentevo_state::nmi_on() +{ + m_nmi_active = true; + m_nmi_active_flip_countdown = 0; + atm_update_memory(); + m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero); +} + +u8 pentevo_state::merge_ram_with_7ffd(u8 ram_page) +{ + u8 page = atm_state::merge_ram_with_7ffd(ram_page); + if (is_pent1024()) + page = (page & ~0x38) | ((m_port_7ffd_data & 0xe0) >> 2); + + return page; +} + +void pentevo_state::pentevo_port_eff7_w(offs_t offset, u8 data) +{ + u8 changed = m_port_eff7_data ^ data; + m_port_eff7_data = data; + + if (BIT(changed, 3)) atm_update_memory(); + if (BIT(changed, 4)) atm_update_cpu(); + if (BIT(changed, 7)) atm_update_io(); +} + +void pentevo_state::pentevo_port_7f7_w(offs_t offset, u8 data) +{ + u8 bank = offset >> 14; + u16 page = (pen_page(bank) & PEN_DOS7FFD_MASK) | PEN_RAMNROM_MASK | u8(~data); + + LOGMEM("EVO%s=%X RAM%d%s%02X\n", BIT(m_port_7ffd_data, 4), data, bank, (page & PEN_DOS7FFD_MASK) ? "+" : " ", page & ram_pages_mask); + pen_page(bank) = page; + atm_update_memory(); +} + +void pentevo_state::pentevo_port_bf7_w(offs_t offset, u8 data) +{ + u8 bank = offset >> 14; + if (BIT(data, 0)) + pen_page(bank) |= PEN_WRDISBL_MASK; + else + pen_page(bank) &= ~PEN_WRDISBL_MASK; +} + +void pentevo_state::pentevo_port_bf_w(offs_t offset, u8 data) +{ + if (BIT(m_port_bf_data, 3) && !BIT(data, 3)) // 1>0 + // Due to the fact current z80 handles NMI detection before (not after) instruction OUT(#BF),0:HALT freezes driver. + // With fixed z80 this must be replaced with: + // nmi_on() + m_nmi_active_flip_countdown = 1; + + m_port_bf_data = data; + atm_update_io(); +} + +u8 pentevo_state::pentevo_port_bf_r(offs_t offset) +{ + return m_port_bf_data & 0x1f; +} + +u8 pentevo_state::pentevo_port_0nbd_r(offs_t offset) +{ + u8 opt = (offset >> 8) & 0x0f; + if (opt <= 0x07) + return ~(m_pages_map[BIT(opt, 2)][opt & 0x03] & 0xff); + else if (opt == 0x08 || opt == 0x09) + { + u8 data = 0; + for (s8 i = 7; i >= 0; i--) + data = (data << 1) | bool(m_pages_map[BIT(i, 2)][i & 0x03] & (opt == 0x08 ? PEN_RAMNROM_MASK : PEN_DOS7FFD_MASK)); + return data; + } + else if (opt == 0x0a) + return m_port_7ffd_data; + else if (opt == 0x0b) + return m_port_eff7_data; + else if (opt == 0x0c) + return (m_pen2 << 7) | (m_cpm_n << 6) | (m_pen << 5) | ((m_nmi_active && m_beta->is_active()) << 4) | (m_port_77_data & 0x0f); + else if (opt == 0x0d) + return m_palette_data[get_border_color(m_screen->hpos(), m_screen->vpos())]; + else if (opt == 0x0e) + { + u8* screen_location = m_ram->pointer() + ((BIT(m_port_7ffd_data, 3) ? 10 : 8) << 14); + u16 y = m_screen->vpos() - get_screen_area().top(); + u16 x = m_screen->hpos() - get_screen_area().left(); + u8 *symb_location = screen_location + 0x1c0 + (x >> 4) + ((y >> 3) * 64); + if (BIT(x, 3)) symb_location += 0x1000; + return m_char_ram->read((*symb_location << 3) + (y & 0x07)); + } + else //if (opt == 0x0f) + return get_border_color(m_screen->hpos(), m_screen->vpos()); +} + +u8 pentevo_state::pentevo_port_1nbd_r(offs_t offset) +{ + u8 opt = (offset >> 8) & 0x03; + if (opt == 0x00) + return m_nmi_trap_offset & 0x0f; + else if (opt == 0x01) + return (m_nmi_trap_offset & 0xf0) >> 8; + else if (opt == 0x02) + { + u8 data = 0; + for (s8 i = 7; i >= 0; i--) + data = (data << 1) | bool(m_pages_map[BIT(i, 2)][i & 0x03] & PEN_WRDISBL_MASK); + return data; + } + else //if (opt == 0x03) + return m_beta_drive_virtual; +} + +void pentevo_state::pentevo_port_1nbd_w(offs_t offset, u8 data) +{ + u8 opt = (offset >> 8) & 0x03; + if (opt == 0x00) + m_nmi_trap_offset = (m_nmi_trap_offset & 0xf0) | data; + else if (opt == 0x01) + m_nmi_trap_offset = (m_nmi_trap_offset & 0x0f) | (data << 8); + else if (opt == 0x02) + { + u8 data = 0; + for (s8 i = 7; i >= 0; i--) + { + m_pages_map[BIT(i, 2)][i & 0x03] &= ~PEN_WRDISBL_MASK; + if (BIT(data, i)) m_pages_map[BIT(i, 2)][i & 0x03] |= PEN_WRDISBL_MASK; + } + } + else if (opt == 0x03) + m_beta_drive_virtual = data & 0x0f; +} + +INTERRUPT_GEN_MEMBER(pentevo_state::pentevo_interrupt) +{ + // 17989=80*224+69 z80(3.5Hz) clocks between INT and screen paper begins. Screen clock is 7Hz. + m_irq_on_timer->adjust(m_screen->time_until_pos(80 - 80, 80) - m_screen->clocks_to_attotime(128)); +} + +void pentevo_state::spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + if (m_rg == 0b011 && (BIT(m_port_eff7_data, 0) || BIT(m_port_eff7_data, 5))) + { + if (BIT(m_port_eff7_data, 5)) + pentevo_update_screen_zxhw(screen, bitmap, cliprect); + else + pentevo_update_screen_zx16(screen, bitmap, cliprect); + } + else if (m_rg == 0b111) + pentevo_update_screen_tx(screen, bitmap, cliprect); + else + atm_state::spectrum_update_screen(screen, bitmap, cliprect); +} + +void pentevo_state::pentevo_update_screen_zxhw(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + bool invert_attrs = u64(screen.frame_number() / m_frame_invert_count) & 1; + for (u16 vpos = cliprect.top(); vpos <= cliprect.bottom(); vpos++) + { + u16 hpos = cliprect.left(); + u16 x = hpos - get_screen_area().left(); + u16 y = vpos - get_screen_area().top(); + u8 *scr = &m_screen_location[((y & 7) << 8) | ((y & 0x38) << 2) | ((y & 0xc0) << 5) | (x >> 3)]; + u8 *attr = &scr[0x2000]; + u16 *pix = &(bitmap.pix(vpos, hpos)); + + while (hpos <= cliprect.right()) + { + u16 ink = ((*attr >> 3) & 0x08) | (*attr & 0x07); + u16 pap = (*attr >> 3) & 0x0f; + u8 pix8 = (invert_attrs && (*attr & 0x80)) ? ~*scr : *scr; + + for (u8 b = (0x80 >> (x % 8)); b; b >>= 1, x++, hpos++) + *pix++ = (pix8 & b) ? ink : pap; + scr++; + attr++; + } + } +} + +void pentevo_state::pentevo_update_screen_zx16(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + // TODO attrs not decoded + for (u16 vpos = cliprect.top(); vpos <= cliprect.bottom(); vpos++) + { + u16 hpos = cliprect.left(); + u16 x = hpos - get_screen_area().left(); + u16 y = vpos - get_screen_area().top(); + u8 *scr = &m_screen_location[((y & 7) << 8) | ((y & 0x38) << 2) | ((y & 0xc0) << 5) | (x >> 3)]; + u16 *pix = &(bitmap.pix(vpos, hpos)); + + while (hpos <= cliprect.right()) + { + u16 ink = 0; + u16 pap = 7; + u8 pix8 = *scr; + + for (u8 b = (0x80 >> (x % 8)); b; b >>= 1, x++, hpos++) + *pix++ = (pix8 & b) ? ink : pap; + scr++; + } + } +} + +void pentevo_state::pentevo_update_screen_tx(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + u8* screen_location = m_ram->pointer() + ((BIT(m_port_7ffd_data, 3) ? 10 : 8) << 14); + for (u16 vpos = cliprect.top(); vpos <= cliprect.bottom(); vpos++) + { + u16 y = vpos - get_screen_area().top(); + for (u16 hpos = cliprect.left() & 0xfff8; hpos <= cliprect.right();) + { + u16 x = hpos - get_screen_area().left(); + u8 *symb_location = screen_location + 0x1c0 + (x >> 4) + ((y >> 3) * 64); + u8 *attr_location = symb_location + 0x2000 + BIT(x, 3); + if (BIT(x, 3)) + symb_location += 0x1000; + else + attr_location += 0x1000; + + u8 attr = *attr_location; + u8 fg = ((attr & 0x40) >> 3) | (attr & 0x07); + u8 bg = (((attr & 0x80) >> 1) | (attr & 0x38)) >> 3; + + u8 chunk = m_char_ram->read((*symb_location << 3) + (y & 0x07)); + for (u8 i = 0x80; i; i >>= 1) + { + bitmap.pix(vpos, hpos++) = (chunk & i) ? fg : bg; + } + } + } +} + +u8 pentevo_state::nemo_ata_r(u8 cmd) +{ + if (machine().side_effects_disabled()) + return 0xff; + + bool data_read = (cmd & 0x7) == 0; + u8 data; + if (data_read && m_ata_data_hi_ready) + { + data = m_ata_data_latch; + m_ata_data_hi_ready = false; + } + else + { + data = atm_state::ata_r(cmd << 5); + m_ata_data_hi_ready = data_read; + } + + return data; +} + +void pentevo_state::nemo_ata_w(u8 cmd, u8 data) +{ + bool data_write = (cmd & 0x7) == 0; + if (data_write && !m_ata_data_hi_ready) + { + m_ata_data_latch = data; + m_ata_data_hi_ready = true; + } + else + { + atm_state::ata_w(cmd << 5, data); + m_ata_data_hi_ready = false; + } +} + +void pentevo_state::spi_port_77_w(offs_t offset, u8 data) +{ + m_sdcard->spi_ss_w(BIT(data, 0)); + m_zctl_cs = BIT(data, 1); +} + +u8 pentevo_state::spi_port_57_r(offs_t offset) +{ + if (m_zctl_cs) + return 0xff; + + u8 din = m_zctl_di; + if (!machine().side_effects_disabled()) + spi_port_57_w(0, 0xff); + + return din; +} + +void pentevo_state::spi_port_57_w(offs_t offset, u8 data) +{ + if (!m_zctl_cs) + { + for (u8 m = 0x80; m; m >>= 1) + { + m_sdcard->spi_clock_w(CLEAR_LINE); // 0-S R + m_sdcard->spi_mosi_w(data & m ? 1 : 0); + m_sdcard->spi_clock_w(ASSERT_LINE); // 1-L W + } + } +} + +void pentevo_state::spi_miso_w(u8 data) +{ + m_zctl_di <<= 1; + m_zctl_di |= data; +} + +u8 pentevo_state::gluk_data_r(offs_t offset) +{ + if (m_glukrs->is_active()) + { + if (m_gluk_ext == 2) + return m_keyboard->read(); + else if (m_glukrs->address_r() == 0x0a) + return 0x20 | (m_glukrs->data_r() & 0x0f); + else if (m_glukrs->address_r() == 0x0b) + return 0x02 | (m_glukrs->data_r() & 0x04); + else if (m_glukrs->address_r() == 0x0c) + return 0x10; + else if (m_glukrs->address_r() == 0x0d) + return 0x80; + } + return m_glukrs->data_r(); // returns 0xff if inactive +} + +void pentevo_state::gluk_data_w(offs_t offset, u8 data) +{ + if (!m_glukrs->is_active()) + return; + + u8 addr = m_glukrs->address_r(); + if (addr >= 0xf0 && addr <= 0xf0) + { + m_gluk_ext = data; + u8 m_fx[0xf] = {0x00}; + if (data == 0 || data == 1) // BASECONF_VERSION + BOOTLOADER_VERSION + { + strcpy((char *)m_fx, "M.A.M.E."); + PAIR16 m_ver; + m_ver.w = ((22 << 9) | (9 << 5) | 3); // y.m.d + m_fx[0x0c] = m_ver.b.l; + m_fx[0x0d] = m_ver.b.h; + } + + for (u8 i = 0; i < 0xf; i++) + { + m_glukrs->address_w(0xf0 + i); + m_glukrs->data_w(m_fx[i]); + } + m_glukrs->address_w(addr); + } + else + { + m_glukrs->data_w(data); + } +} + +void pentevo_state::pentevo_io(address_map &map) +{ + map.unmap_value_high(); + + // PORTS: Always + map(0x00f6, 0x00f6).select(0xff08).rw(FUNC(pentevo_state::spectrum_ula_r), FUNC(pentevo_state::atm_ula_w)); + map(0x00fb, 0x00fb).mirror(0xff00).w("cent_data_out", FUNC(output_latch_device::write)); + map(0x00fd, 0x00fd).mirror(0xff00).w(FUNC(pentevo_state::atm_port_7ffd_w)); + + // Gluk + map(0xdff7, 0xdff7).lw8(NAME([this](offs_t offset, u8 data) { m_glukrs->address_w(data); } )); + map(0xbff7, 0xbff7).rw(FUNC(pentevo_state::gluk_data_r), FUNC(pentevo_state::gluk_data_w)); + + // Configuration + map(0xeff7, 0xeff7).w(FUNC(pentevo_state::pentevo_port_eff7_w)); + map(0x00bf, 0x00bf).select(0xff00).rw(FUNC(pentevo_state::pentevo_port_bf_r), FUNC(pentevo_state::pentevo_port_bf_w)); + map(0x00be, 0x00be).select(0x0f00).r(FUNC(pentevo_state::pentevo_port_0nbd_r)); + map(0x00bd, 0x00bd).select(0x0f00).r(FUNC(pentevo_state::pentevo_port_0nbd_r)); + map(0x10be, 0x10be).select(0x0f00).r(FUNC(pentevo_state::pentevo_port_1nbd_r)); + map(0x10bd, 0x10bd).select(0x0f00).rw(FUNC(pentevo_state::pentevo_port_1nbd_r), FUNC(pentevo_state::pentevo_port_1nbd_w)); + map(0x00be, 0x00be).select(0xff00).lw8(NAME([this](offs_t offset) { m_nmi_active_flip_countdown = 2; })); + + // AY + map(0x8000, 0x8000).mirror(0x3ffd).w("ay8912", FUNC(ay8910_device::data_w)); + map(0xc000, 0xc000).mirror(0x3ffd).rw("ay8912", FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_w)); + + // HDD: NEMO + map(0x0010, 0x0010).select(0xffe0).lrw8(NAME([this](offs_t offset) { return nemo_ata_r(offset >> 5); }) + , NAME([this](offs_t offset, u8 data) { nemo_ata_w(offset >> 5, data); })); + map(0x0011, 0x0011).mirror(0xff00).lrw8(NAME([this]() { m_ata_data_hi_ready = false; return m_ata_data_latch; }) + , NAME([this](offs_t offset, u8 data) { m_ata_data_hi_ready = true; m_ata_data_latch = data; })); + map(0x00c8, 0x00c8).mirror(0xff00).lrw8(NAME([this]() { return m_ata->cs1_r(6 /* ? */); }) + , NAME([this](offs_t offset, u8 data) { m_ata->cs1_w(6, data); })); + + // SPI + map(0x0077, 0x0077).select(0xff00).lr8(NAME([]() { return 0x00; })).w(FUNC(pentevo_state::spi_port_77_w)); + map(0x0057, 0x0057).select(0xff00).rw(FUNC(pentevo_state::spi_port_57_r), FUNC(pentevo_state::spi_port_57_w)); + + // Mouse + map(0xfadf, 0xfadf).lr8(NAME([this]() { return 0x80 | (m_io_mouse[2]->read() & 0x07); })); + map(0xfbdf, 0xfbdf).lr8(NAME([this]() { return m_io_mouse[0]->read(); })); + map(0xffdf, 0xffdf).lr8(NAME([this]() { return ~m_io_mouse[1]->read(); })); + map(0x001f, 0x001f).mirror(0xff00).lr8(NAME([]() { return 0x00; })); // TODO Kepmston Joystick + + // PORTS: Shadow + map(0x0000, 0xffff).view(m_io_view); + m_io_view[0](0x0000, 0xffff).view(m_io_dos_view); + m_io_dos_view[0](0x001f, 0x001f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::status_r), FUNC(beta_disk_device::command_w)); + m_io_dos_view[0](0x003f, 0x003f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w)); + m_io_dos_view[0](0x005f, 0x005f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)); + m_io_dos_view[0](0x007f, 0x007f).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)); + m_io_dos_view[0](0x00ff, 0x00ff).select(0xff00).r(m_beta, FUNC(beta_disk_device::state_r)); + + m_io_view[0](0x00ff, 0x00ff).select(0xff00).w(FUNC(pentevo_state::atm_port_ff_w)); + m_io_view[0](0x0077, 0x0077).select(0xff00).lr8(NAME([]() { return 0xff; })).w(FUNC(pentevo_state::atm_port_77_w)); + m_io_view[0](0x3ff7, 0x3ff7).select(0xc000).w(FUNC(pentevo_state::atm_port_f7_w)); // ATM + m_io_view[0](0x37f7, 0x37f7).select(0xc000).w(FUNC(pentevo_state::pentevo_port_7f7_w)); // PENTEVO + m_io_view[0](0x3bf7, 0x3bf7).select(0xc000).w(FUNC(pentevo_state::pentevo_port_bf7_w)); // RO + + // SPI + m_io_view[0](0x0057, 0x0057).select(0xff00) + .lw8(NAME([this](offs_t offset, u8 data) { if (BIT(offset, 15)) spi_port_77_w(offset, data); else spi_port_57_w(offset, data); })); + + // Gluk + m_io_view[0](0xdef7, 0xdef7).lw8(NAME([this](offs_t offset, u8 data) { m_glukrs->address_w(data); } )); + m_io_view[0](0xbef7, 0xbef7).rw(FUNC(pentevo_state::gluk_data_r), FUNC(pentevo_state::gluk_data_w)); +} + +void pentevo_state::init_mem_write() +{ + address_space &mem = m_maincpu->space(AS_PROGRAM); + mem.install_write_tap(0x0000, 0xffff, "charrom_w", [this](offs_t offset, u8 &data, u8 mem_mask) + { + if (!machine().side_effects_disabled()) + { + if (BIT(m_port_bf_data, 2)) + { + m_char_ram->write(offset & 0x7ff, data); + m_gfxdecode->gfx(0)->mark_dirty((offset & 0x7ff) / 8); + } + } + return data; + }); + + address_space &opc = m_maincpu->space(AS_OPCODES); + opc.install_read_tap(0x0000, 0xffff, "nmi_exit", [this](offs_t offset, u8 &data, u8 mem_mask) + { + if (!machine().side_effects_disabled()) + { + if (m_nmi_active_flip_countdown) + { + if(--m_nmi_active_flip_countdown == 0) + { + if (m_nmi_active) + { + m_nmi_active = false; + atm_update_memory(); + } + else + nmi_on(); // see: pentevo_port_bf_w() + } + } + } + }); +} + +void pentevo_state::machine_start() +{ + atm_state::machine_start(); + + save_item(NAME(m_port_bf_data)); + save_item(NAME(m_port_eff7_data)); + save_item(NAME(m_beta_drive_virtual)); + save_item(NAME(m_gluk_ext)); + save_item(NAME(m_ata_data_hi_ready)); + save_item(NAME(m_nmi_trap_offset)); + save_item(NAME(m_nmi_active)); + save_item(NAME(m_nmi_active_flip_countdown)); + save_item(NAME(m_zctl_di)); + save_item(NAME(m_zctl_cs)); + + init_mem_write(); +} + +void pentevo_state::machine_reset() +{ + m_nmi_active = false; + m_port_eff7_data = 0; + atm_state::machine_reset(); + + m_port_bf_data = 0; + m_nmi_active_flip_countdown = 0; + m_beta_drive_virtual = 0; + + m_ata_data_hi_ready = false; + m_gluk_ext = 0xff; + m_zctl_cs = 1; + m_zctl_di = 0xff; + + m_keyboard->write(0xff); + while (m_keyboard->read() != 0) { /* invalidate buffer */ } +} + +void pentevo_state::video_start() +{ + atm_state::video_start(); + m_char_location = m_char_ram->pointer(); + m_gfxdecode->gfx(0)->set_source(m_char_location); +} + +INPUT_PORTS_START( pentevo ) + PORT_INCLUDE( spec_plus ) + + PORT_START("mouse_input1") + PORT_BIT(0xff, 0, IPT_MOUSE_X) PORT_SENSITIVITY(30) + + PORT_START("mouse_input2") + PORT_BIT(0xff, 0, IPT_MOUSE_Y) PORT_SENSITIVITY(30) + + PORT_START("mouse_input3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_NAME("Left mouse button") PORT_CODE(MOUSECODE_BUTTON1) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("Right mouse button") PORT_CODE(MOUSECODE_BUTTON2) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON6) PORT_NAME("Middle mouse button") PORT_CODE(MOUSECODE_BUTTON3) + +INPUT_PORTS_END + +void pentevo_state::pentevo(machine_config &config) +{ + atmtb2(config); + m_maincpu->set_addrmap(AS_IO, &pentevo_state::pentevo_io); + m_maincpu->set_vblank_int("screen", FUNC(pentevo_state::pentevo_interrupt)); + TIMER(config, "nmi_timer").configure_periodic(FUNC(pentevo_state::nmi_check_callback), attotime::from_hz(50)); + + m_screen->set_raw(X1_128_SINCLAIR / 5, 448, 320, {get_screen_area().left() - 40, get_screen_area().right() + 40, get_screen_area().top() - 40, get_screen_area().bottom() + 40}); + + m_ram->set_default_size("4M"); + RAM(config, m_char_ram).set_default_size("2048").set_default_value(0); + + GLUKRS(config, m_glukrs); + SPI_SDCARD(config, m_sdcard, 0); + m_sdcard->spi_miso_callback().set(FUNC(pentevo_state::spi_miso_w)); + + AT_KEYB(config, m_keyboard, pc_keyboard_device::KEYBOARD_TYPE::AT, 3); +} + + +ROM_START( pentevo ) + ROM_REGION(0x090000, "maincpu", ROMREGION_ERASEFF) + ROM_DEFAULT_BIOS("v0.59.02fe_tr503") + + // http://svn.zxevo.ru/revision.php?repname=pentevo&path=%2From%2Fzxevo_fe.rom&rev=1012&peg=1021 + ROM_SYSTEM_BIOS(0, "v0.59.02fe_tr503", "Reset Service v0.59.02 (FE), TR-DOS v5.03") + ROMX_LOAD( "zxevo_05902fe_trd503.rom", 0x010000, 0x80000, CRC(f7f29dd8) SHA1(dfbcce980cf6244a9491aedf68ebb372677b0593), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "v0.59.02fe", "Reset Service v0.59.02 (FE), NEO-DOS v0.53") + ROMX_LOAD( "zxevo_05902fe.rom", 0x010000, 0x80000, CRC(df144c82) SHA1(e48b8a95576e0123764ff8cc34d9373dc95159bf), ROM_BIOS(1)) + + // http://svn.zxevo.ru/revision.php?repname=pentevo&path=%2Fcfgs%2Fstandalone_base_trdemu%2Ftrunk%2Fzxevo_fw.bin&rev=994&peg=1021 + ROM_REGION(0x0C280, "fw", ROMREGION_ERASEFF) + ROM_LOAD( "zxevo_fw.bin", 0x0000, 0xC280, CRC(aefbd8e5) SHA1(ac9a551ba15eeead76b5527fd5d23d824ae5176f)) +ROM_END + +} // Anonymous namespace + + +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP( 2009, pentevo, spec128, 0, pentevo, pentevo, pentevo_state, empty_init, "NedoPC", "ZX Evolution: BASECONF", 0) diff --git a/src/mame/sinclair/qimi.h b/src/mame/sinclair/qimi.h index 033d8d7bc7a..777eea916f2 100644 --- a/src/mame/sinclair/qimi.h +++ b/src/mame/sinclair/qimi.h @@ -6,8 +6,8 @@ **********************************************************************/ -#ifndef MAME_MACHINE_QIMI_H -#define MAME_MACHINE_QIMI_H +#ifndef MAME_SINCLAIR_QIMI_H +#define MAME_SINCLAIR_QIMI_H #pragma once @@ -62,4 +62,4 @@ private: DECLARE_DEVICE_TYPE(QIMI, qimi_device) -#endif // MAME_MACHINE_QIMI_H +#endif // MAME_SINCLAIR_QIMI_H diff --git a/src/mame/sinclair/scorpion.cpp b/src/mame/sinclair/scorpion.cpp index 75c3db47bf2..2f423c80c81 100644 --- a/src/mame/sinclair/scorpion.cpp +++ b/src/mame/sinclair/scorpion.cpp @@ -135,10 +135,12 @@ u8 scorpion_state::beta_neutral_r(offs_t offset) u8 scorpion_state::beta_enable_r(offs_t offset) { - if (!(machine().side_effects_disabled())) { + if (!machine().side_effects_disabled()) + { if (m_maincpu->total_cycles() & 1) m_maincpu->eat_cycles(1); - if (m_beta->started() && m_bank_rom[0]->entry() == 1) { + if (m_beta->started() && m_bank_rom[0]->entry() == 1) + { m_beta->enable(); m_bank_rom[0]->set_entry(3); } @@ -148,10 +150,12 @@ u8 scorpion_state::beta_enable_r(offs_t offset) u8 scorpion_state::beta_disable_r(offs_t offset) { - if (!(machine().side_effects_disabled())) { + if (!machine().side_effects_disabled()) + { if (m_maincpu->total_cycles() & 1) m_maincpu->eat_cycles(1); - if (m_beta->started() && m_beta->is_active()) { + if (m_beta->started() && m_beta->is_active()) + { m_beta->disable(); m_bank_rom[0]->set_entry(BIT(m_port_7ffd_data, 4)); } diff --git a/src/mame/sinclair/spec128.h b/src/mame/sinclair/spec128.h index 382d1b895dd..44451e727e9 100644 --- a/src/mame/sinclair/spec128.h +++ b/src/mame/sinclair/spec128.h @@ -6,8 +6,8 @@ * ****************************************************************************/ -#ifndef MAME_INCLUDES_SPEC128_H -#define MAME_INCLUDES_SPEC128_H +#ifndef MAME_SINCLAIR_SPEC128_H +#define MAME_SINCLAIR_SPEC128_H #pragma once @@ -65,4 +65,4 @@ private: #define SPEC128_RETRACE_CYCLES 52 #define SPEC128_CYCLES_PER_LINE 228 -#endif // MAME_INCLUDES_SPEC128_H +#endif // MAME_SINCLAIR_SPEC128_H diff --git a/src/mame/sinclair/spec_snqk.h b/src/mame/sinclair/spec_snqk.h index be6bb6e080d..419820aba0d 100644 --- a/src/mame/sinclair/spec_snqk.h +++ b/src/mame/sinclair/spec_snqk.h @@ -6,8 +6,8 @@ * ****************************************************************************/ -#ifndef MAME_MACHINE_SPEC_SNQK_H -#define MAME_MACHINE_SPEC_SNQK_H +#ifndef MAME_SINCLAIR_SPEC_SNQK_H +#define MAME_SINCLAIR_SPEC_SNQK_H #pragma once @@ -164,4 +164,4 @@ enum SPECTRUM_Z80_SNAPSHOT_TYPE { #define RAW_HDR 9 #define RAW_SIZE (RAW_HDR + 3*SPECTRUM_BANK) -#endif // MAME_MACHINE_SPEC_SNQK_H +#endif // MAME_SINCLAIR_SPEC_SNQK_H diff --git a/src/mame/sinclair/specpls3.h b/src/mame/sinclair/specpls3.h index 986880fa6fd..adbd88a2ef0 100644 --- a/src/mame/sinclair/specpls3.h +++ b/src/mame/sinclair/specpls3.h @@ -6,8 +6,8 @@ * ****************************************************************************/ -#ifndef MAME_INCLUDES_SPECPLS3_H -#define MAME_INCLUDES_SPECPLS3_H +#ifndef MAME_SINCLAIR_SPECPLS3_H +#define MAME_SINCLAIR_SPECPLS3_H #include "spectrum.h" #include "spec128.h" @@ -55,4 +55,4 @@ private: optional_device_array m_flop; }; -#endif // MAME_INCLUDES_SPECPLS3_H +#endif // MAME_SINCLAIR_SPECPLS3_H diff --git a/src/mame/sinclair/spectrum.h b/src/mame/sinclair/spectrum.h index 8ab83852296..58256cccf10 100644 --- a/src/mame/sinclair/spectrum.h +++ b/src/mame/sinclair/spectrum.h @@ -6,8 +6,8 @@ * ****************************************************************************/ -#ifndef MAME_INCLUDES_SPECTRUM_H -#define MAME_INCLUDES_SPECTRUM_H +#ifndef MAME_SINCLAIR_SPECTRUM_H +#define MAME_SINCLAIR_SPECTRUM_H #pragma once @@ -220,4 +220,4 @@ INPUT_PORTS_EXTERN( spectrum ); INPUT_PORTS_EXTERN( spec128 ); INPUT_PORTS_EXTERN( spec_plus ); -#endif // MAME_INCLUDES_SPECTRUM_H +#endif // MAME_SINCLAIR_SPECTRUM_H diff --git a/src/mame/sinclair/spectrum_v.cpp b/src/mame/sinclair/spectrum_v.cpp index c7919956136..3bd4bb713dc 100644 --- a/src/mame/sinclair/spectrum_v.cpp +++ b/src/mame/sinclair/spectrum_v.cpp @@ -116,7 +116,8 @@ u32 spectrum_state::screen_update_spectrum(screen_device &screen, bitmap_ind16 & { rectangle scr = get_screen_area(); rectangle vis = screen.visible_area(); - if (vis != scr) { + if (vis != scr) + { rectangle bsides[4] = { rectangle(vis.left(), vis.right(), vis.top(), scr.top() - 1), rectangle(vis.left(), scr.left() - 1, scr.top(), scr.bottom()), @@ -171,12 +172,12 @@ px: | 0 | 1 | 2 | 3 |*4*| 5 | 6 | 7 |*0*| 1 | 2 | 3 | 4 | 5 | 6 | 7 | TODO Curren implementation only tracks char switch position. In order to track both (char and attr) we need to share some state between screen->update() events. */ -void spectrum_state::spectrum_update_screen(screen_device &screen_d, bitmap_ind16 &bitmap, const rectangle &screen) +void spectrum_state::spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { - bool invert_attrs = u64(screen_d.frame_number() / m_frame_invert_count) & 1; - for (u16 vpos = screen.top(); vpos <= screen.bottom(); vpos++) + bool invert_attrs = u64(screen.frame_number() / m_frame_invert_count) & 1; + for (u16 vpos = cliprect.top(); vpos <= cliprect.bottom(); vpos++) { - u16 hpos = screen.left(); + u16 hpos = cliprect.left(); u16 x = hpos - get_screen_area().left(); bool chunk_right = x & 8; if (x % 8 <= (chunk_right ? 0 : 4)) @@ -197,7 +198,7 @@ void spectrum_state::spectrum_update_screen(screen_device &screen_d, bitmap_ind1 u8 *attr = &m_screen_location[0x1800 + (((y & 0xf8) << 2) | (x >> 3))]; u16 *pix = &(bitmap.pix(vpos, hpos)); - while ((hpos + (chunk_right ? 0 : 4)) <= screen.right()) + while ((hpos + (chunk_right ? 0 : 4)) <= cliprect.right()) { u16 ink = ((*attr >> 3) & 0x08) | (*attr & 0x07); u16 pap = (*attr >> 3) & 0x0f; diff --git a/src/mame/sinclair/timex.h b/src/mame/sinclair/timex.h index 6a050db23a6..f01b3ece50a 100644 --- a/src/mame/sinclair/timex.h +++ b/src/mame/sinclair/timex.h @@ -6,8 +6,8 @@ * ****************************************************************************/ -#ifndef MAME_INCLUDES_TIMEX_H -#define MAME_INCLUDES_TIMEX_H +#ifndef MAME_SINCLAIR_TIMEX_H +#define MAME_SINCLAIR_TIMEX_H #pragma once @@ -100,4 +100,4 @@ private: }; -#endif // MAME_INCLUDES_TIMEX_H +#endif // MAME_SINCLAIR_TIMEX_H diff --git a/src/mame/sinclair/tsconf.cpp b/src/mame/sinclair/tsconf.cpp index c5a8348f0d7..7b96902865e 100644 --- a/src/mame/sinclair/tsconf.cpp +++ b/src/mame/sinclair/tsconf.cpp @@ -2,21 +2,7 @@ // copyright-holders:Andrei I. Holub /*************************************************************************** -TS-Configuration (ZX Evolution) machine driver. -Implementation: Revision C / 5-bit VDAC - -Hobby computer ZX Evolution is Spectrum-compatible with extensions. - -Hardware (ZX Evolution): -- Z80 3.5 MHz (classic mode)/ 7 MHz (turbo mode without CPU wait circles)/ 14 MHz (mega turbo with CPU wait circles); -- 4 Mb RAM, 512Kb ROM; -- MiniITX board (172x170mm), 2 ZXBUS slots, power ATX or +5,+12V; -- Based on fpga (Altera EP1K50); -- Peripheral MCU ATMEGA128; -- PS/2 keyboard and mouse support; -- Floppy (WDC1793) Beta-disk compatible interface, IDE (one channel, up to 2 devices on master/slave mode), SD(HC) card, RS232; -- Sound: AY, Beeper, Covox (PWM); -- Real-time clock. +see: pentevo.cpp Features (TS-Configuration): - Resolutions: 360x288, 320x240, 320x200, 256x192 @@ -36,16 +22,12 @@ Features (TS-Configuration): - DRAM-to-Device, Device-to-DRAM and DRAM-to-DRAM DMA Controller Refs: -ZxEvo: http://nedopc.com/zxevo/zxevo_eng.php - Principal scheme (rev. C) :: http://nedopc.com/zxevo/zxevo_sch_revc.pdf - Montage scheme (rev. C) :: http://nedopc.com/zxevo/zxevo_mon_revc.pdf TsConf: https://github.com/tslabs/zx-evo/blob/master/pentevo/docs/TSconf/tsconf_en.md https://github.com/tslabs/zx-evo/raw/master/pentevo/docs/TSconf/TSconf.xls FAQ-RUS: https://forum.tslabs.info/viewtopic.php?f=35&t=157 ROM: https://github.com/tslabs/zx-evo/blob/master/pentevo/rom/bin/ts-bios.rom (validated on: 2021-12-14) HowTo: -# Use ts-bios.rom above. You also need tr-dos roms which simpliest(?) to get from pentagon. # Create SD image "wc.img" # Copy WC files from archive https://github.com/tslabs/zx-evo/blob/master/pentevo/soft/WC/wc.zip # Tech Demos (currently *.spg only): http://prods.tslabs.info/index.php?t=4 @@ -66,6 +48,7 @@ TODO: #include "emu.h" #include "tsconf.h" + #include "cpu/z80/z80.h" #include "sound/ay8910.h" #include "speaker.h" @@ -310,4 +293,4 @@ ROM_START(tsconf) ROM_END // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 2011, tsconf, spec128, 0, tsconf, spec_plus, tsconf_state, empty_init, "NedoPC, TS-Labs", "ZX Evolution TS-Configuration", 0) +COMP( 2011, tsconf, spec128, 0, tsconf, spec_plus, tsconf_state, empty_init, "NedoPC, TS-Labs", "ZX Evolution: TS-Configuration", 0) diff --git a/src/mame/sinclair/tsconf.h b/src/mame/sinclair/tsconf.h index 9fd7e79c637..e39c8491792 100644 --- a/src/mame/sinclair/tsconf.h +++ b/src/mame/sinclair/tsconf.h @@ -5,8 +5,8 @@ * includes/tsconfig.h * ****************************************************************************/ -#ifndef MAME_INCLUDES_TSCONF_H -#define MAME_INCLUDES_TSCONF_H +#ifndef MAME_SINCLAIR_TSCONF_H +#define MAME_SINCLAIR_TSCONF_H #pragma once @@ -214,4 +214,4 @@ private: INPUT_PORTS_EXTERN(tsconf); -#endif // MAME_INCLUDES_TSCONF_H +#endif // MAME_SINCLAIR_TSCONF_H diff --git a/src/mame/sinclair/tsconf_m.cpp b/src/mame/sinclair/tsconf_m.cpp index 896075aee24..28ee3c952b3 100644 --- a/src/mame/sinclair/tsconf_m.cpp +++ b/src/mame/sinclair/tsconf_m.cpp @@ -729,8 +729,14 @@ void tsconf_state::tsconf_port_57_zctr_w(offs_t port, u8 data) u8 tsconf_state::tsconf_port_57_zctr_r(offs_t port) { - tsconf_port_57_zctr_w(0, 0xff); - return m_zctl_cs ? 0xff : m_zctl_di; + if (m_zctl_cs) + return 0xff; + + u8 data = m_zctl_di; + if (!machine().side_effects_disabled()) + tsconf_port_57_zctr_w(0, 0xff); + + return data; } void tsconf_state::tsconf_spi_miso_w(u8 data) @@ -819,7 +825,8 @@ u8 tsconf_state::beta_neutral_r(offs_t offset) u8 tsconf_state::beta_enable_r(offs_t offset) { - if (!(machine().side_effects_disabled())) { + if (!machine().side_effects_disabled()) + { if (!W0_RAM && m_bank_rom[0]->entry() == 3) { if (m_beta->started() && !m_beta->is_active()) @@ -834,7 +841,8 @@ u8 tsconf_state::beta_enable_r(offs_t offset) u8 tsconf_state::beta_disable_r(offs_t offset) { - if (!(machine().side_effects_disabled())) { + if (!machine().side_effects_disabled()) + { if (m_beta->started() && m_beta->is_active()) { m_beta->disable(); diff --git a/src/mame/sinclair/zx.h b/src/mame/sinclair/zx.h index 7385ee3bf84..2993bab875e 100644 --- a/src/mame/sinclair/zx.h +++ b/src/mame/sinclair/zx.h @@ -6,8 +6,8 @@ * ****************************************************************************/ -#ifndef MAME_INCLUDES_ZX_H -#define MAME_INCLUDES_ZX_H +#ifndef MAME_SINCLAIR_ZX_H +#define MAME_SINCLAIR_ZX_H #pragma once @@ -112,4 +112,4 @@ private: void recalc_hsync(); }; -#endif // MAME_INCLUDES_ZX_H +#endif // MAME_SINCLAIR_ZX_H diff --git a/src/mame/sinclair/zx8302.h b/src/mame/sinclair/zx8302.h index 5ec95729d17..372bf475dd6 100644 --- a/src/mame/sinclair/zx8302.h +++ b/src/mame/sinclair/zx8302.h @@ -29,8 +29,8 @@ **********************************************************************/ -#ifndef MAME_MACHINE_ZX8302_H -#define MAME_MACHINE_ZX8302_H +#ifndef MAME_SINCLAIR_ZX8302_H +#define MAME_SINCLAIR_ZX8302_H #pragma once @@ -207,4 +207,4 @@ DECLARE_DEVICE_TYPE(ZX8302, zx8302_device) -#endif // MAME_MACHINE_ZX8302_H +#endif // MAME_SINCLAIR_ZX8302_H