From c92c0c967fc73a383f3989bb96d38a7b25bd8a9c Mon Sep 17 00:00:00 2001 From: holub Date: Thu, 4 Aug 2022 11:41:30 -0400 Subject: sinclair/atm.cpp: Got ATM Turbo 2 mostly working. (#10149) Implemented memory banking, video modes, palette and COVOX. Machines promoted to working -------------------------- MicroART ATM-Turbo 2 --- scripts/src/machine.lua | 22 -- src/devices/machine/glukrs.cpp | 60 ----- src/devices/machine/glukrs.h | 35 --- src/devices/machine/tsconfdma.cpp | 213 ----------------- src/devices/machine/tsconfdma.h | 62 ----- src/mame/sinclair/atm.cpp | 478 +++++++++++++++++++++++++++++++------- src/mame/sinclair/glukrs.cpp | 60 +++++ src/mame/sinclair/glukrs.h | 35 +++ src/mame/sinclair/tsconf.h | 4 +- src/mame/sinclair/tsconf_m.cpp | 32 +-- src/mame/sinclair/tsconfdma.cpp | 213 +++++++++++++++++ src/mame/sinclair/tsconfdma.h | 62 +++++ 12 files changed, 776 insertions(+), 500 deletions(-) delete mode 100644 src/devices/machine/glukrs.cpp delete mode 100644 src/devices/machine/glukrs.h delete mode 100644 src/devices/machine/tsconfdma.cpp delete mode 100644 src/devices/machine/tsconfdma.h create mode 100644 src/mame/sinclair/glukrs.cpp create mode 100644 src/mame/sinclair/glukrs.h create mode 100644 src/mame/sinclair/tsconfdma.cpp create mode 100644 src/mame/sinclair/tsconfdma.h diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index a36480d2077..fd039000531 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -4942,28 +4942,6 @@ if (MACHINES["NS32082"]~=null) then } end ---------------------------------------------------- --- ---@src/devices/machine/tsconfdma.h,MACHINES["TSCONF_DMA"] = true ---------------------------------------------------- -if (MACHINES["TSCONF_DMA"]~=null) then - files { - MAME_DIR .. "src/devices/machine/tsconfdma.cpp", - MAME_DIR .. "src/devices/machine/tsconfdma.h", - } -end - ---------------------------------------------------- --- ---@src/devices/machine/glukrs.h,MACHINES["GLUKRS"] = true ---------------------------------------------------- -if (MACHINES["GLUKRS"]~=null) then - files { - MAME_DIR .. "src/devices/machine/glukrs.cpp", - MAME_DIR .. "src/devices/machine/glukrs.h", - } -end - --------------------------------------------------- -- --@src/devices/machine/bitmap_printer.h,MACHINES["BITMAP_PRINTER"] = true diff --git a/src/devices/machine/glukrs.cpp b/src/devices/machine/glukrs.cpp deleted file mode 100644 index aee7348b3e0..00000000000 --- a/src/devices/machine/glukrs.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Andrei I. Holub -/*************************************************************************** - - Mr Gluk Reset Service - - 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/ - -****************************************************************************/ - -#include "emu.h" -#include "glukrs.h" - -glukrs_device::glukrs_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, GLUKRS, tag, owner, clock), - device_rtc_interface(mconfig, *this), - m_nvram(*this, "nvram") {} - -void glukrs_device::device_add_mconfig(machine_config &config) -{ - NVRAM(config, m_nvram, nvram_device::DEFAULT_ALL_1); -} - -void glukrs_device::device_start() -{ - m_nvram->set_base(&m_cmos, sizeof(m_cmos)); - - m_timer = timer_alloc(FUNC(glukrs_device::timer_callback), this); - m_timer->adjust(attotime::from_hz(clock() / XTAL(32'768)), 0, attotime::from_hz(clock() / XTAL(32'768))); -} - -u8 glukrs_device::read(offs_t address) -{ - return m_cmos[address]; -} - -void glukrs_device::write(offs_t address, u8 data) -{ - m_cmos[address] = data; -} - -void glukrs_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) -{ - m_cmos[0x00] = convert_to_bcd(second); - m_cmos[0x02] = convert_to_bcd(minute); - m_cmos[0x04] = convert_to_bcd(hour); - m_cmos[0x06] = convert_to_bcd(day_of_week); - m_cmos[0x07] = convert_to_bcd(day); - m_cmos[0x08] = convert_to_bcd(month); - m_cmos[0x09] = convert_to_bcd(year % 100); -} - -TIMER_CALLBACK_MEMBER(glukrs_device::timer_callback) -{ - advance_seconds(); -} - -// device type definition -DEFINE_DEVICE_TYPE(GLUKRS, glukrs_device, "glukrs", "Mr Gluk Reset Service") diff --git a/src/devices/machine/glukrs.h b/src/devices/machine/glukrs.h deleted file mode 100644 index 74c581ff068..00000000000 --- a/src/devices/machine/glukrs.h +++ /dev/null @@ -1,35 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Andrei I. Holub - -#ifndef MAME_MACHINE_GLUKRS_H -#define MAME_MACHINE_GLUKRS_H - -#pragma once - -#include "machine/nvram.h" -#include "dirtc.h" - -class glukrs_device : public device_t, - public device_rtc_interface -{ -public: - glukrs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 32'768); - - u8 read(offs_t address); - void write(offs_t address, u8 data); - - TIMER_CALLBACK_MEMBER(timer_callback); - -protected: - virtual void device_add_mconfig(machine_config &config) override; - virtual void device_start() override; - virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override; - -private: - u8 m_cmos[0x100]; - required_device m_nvram; - emu_timer *m_timer; -}; - -DECLARE_DEVICE_TYPE(GLUKRS, glukrs_device) -#endif // MAME_MACHINE_GLUKRS_H diff --git a/src/devices/machine/tsconfdma.cpp b/src/devices/machine/tsconfdma.cpp deleted file mode 100644 index 79ef8bc2d50..00000000000 --- a/src/devices/machine/tsconfdma.cpp +++ /dev/null @@ -1,213 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Andrei I. Holub -/********************************************************************** - - TS-Conf (ZX-Evolution) DMA Controller - -**********************************************************************/ - -#include "emu.h" -#include "tsconfdma.h" - -tsconfdma_device::tsconfdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, TSCONF_DMA, tag, owner, clock), - m_in_mreq_cb(*this), - m_out_mreq_cb(*this), - m_in_mspi_cb(*this), - m_out_cram_cb(*this), - m_out_sfile_cb(*this), - m_on_ready_cb(*this) -{ -} - -void tsconfdma_device::device_start() -{ - m_in_mreq_cb.resolve_safe(0); - m_out_mreq_cb.resolve_safe(); - m_in_mspi_cb.resolve_safe(0); - m_out_cram_cb.resolve_safe(); - m_out_sfile_cb.resolve_safe(); - m_on_ready_cb.resolve_safe(); - - save_item(NAME(m_ready)); - save_item(NAME(m_address_s)); - save_item(NAME(m_address_d)); - save_item(NAME(m_block_len)); - save_item(NAME(m_block_num)); - save_item(NAME(m_align_s)); - save_item(NAME(m_align_d)); - save_item(NAME(m_align)); -} - -void tsconfdma_device::device_reset() -{ - m_block_num = 0; - m_ready = ASSERT_LINE; -} - -int tsconfdma_device::is_ready() -{ - return m_ready; -} - -void tsconfdma_device::set_saddr_l(u8 addr_l) -{ - m_address_s = (m_address_s & 0xffffff00) | (addr_l & 0xfe); -} - -void tsconfdma_device::set_saddr_h(u8 addr_h) -{ - m_address_s = (m_address_s & 0xffffc0ff) | ((addr_h & 0x3f) << 8); -} - -void tsconfdma_device::set_saddr_x(u8 addr_x) -{ - m_address_s = (m_address_s & 0x0003fff) | (addr_x << 14); -} - -void tsconfdma_device::set_daddr_l(u8 addr_l) -{ - m_address_d = (m_address_d & 0xffffff00) | (addr_l & 0xfe); -} - -void tsconfdma_device::set_daddr_h(u8 addr_h) -{ - m_address_d = (m_address_d & 0xffffc0ff) | ((addr_h & 0x3f) << 8); -} - -void tsconfdma_device::set_daddr_x(u8 addr_x) -{ - m_address_d = (m_address_d & 0x0003fff) | (addr_x << 14); -} - -void tsconfdma_device::set_block_len(u8 len) -{ - // 1..256 - m_block_len = len; -} - -void tsconfdma_device::set_block_num_l(u8 num_l) -{ - m_block_num = (m_block_num & 0xff00) | num_l; -} - -void tsconfdma_device::set_block_num_h(u8 num_h) -{ - // 1..1025 * 2 - m_block_num = (m_block_num & 0x00ff) | ((num_h & 0x03) << 8); -} - -void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_opt) -{ - m_ready = CLEAR_LINE; - m_align = align_opt ? 512 : 256; - - // TODO Transfers 2 byte/cycle at 7MHz - switch (dev) - { - case 0b0001: // Mem -> Mem - for (u16 block = 0; block <= m_block_num; block++) - { - auto s_addr = m_address_s; - auto d_addr = m_address_d; - for (u16 len = 0; len <= m_block_len; len++) - { - m_out_mreq_cb(d_addr, m_in_mreq_cb(s_addr)); - s_addr += 2; - d_addr += 2; - } - m_address_s = s_align ? (m_address_s + m_align) : s_addr; - m_address_d = d_align ? (m_address_d + m_align) : d_addr; - } - break; - - case 0b0010: // SPI -> Mem - for (u16 block = 0; block <= m_block_num; block++) - { - auto d_addr = m_address_d; - for (u16 len = 0; len <= m_block_len; len++) - { - m_out_mreq_cb(d_addr, m_in_mspi_cb()); - d_addr += 2; - } - m_address_d = d_align ? (m_address_d + m_align) : d_addr; - } - break; - - case 0b0100: // Fill - for (u16 block = 0; block <= m_block_num; block++) - { - u16 data = m_in_mreq_cb(m_address_s); - auto d_addr = m_address_d; - for (u16 len = 0; len <= m_block_len; len++) - { - m_out_mreq_cb(d_addr, data); - d_addr += 2; - } - m_address_d = d_align ? (m_address_d + m_align) : d_addr; - } - break; - - case 0b1001: // Blt -> Mem - for (u16 block = 0; block <= m_block_num; block++) - { - auto s_addr = m_address_s; - auto d_addr = m_address_d; - for (u16 len = 0; len <= m_block_len; len++) - { - u16 d_val = m_in_mreq_cb(d_addr); - if (d_val != 0) - { - m_out_mreq_cb(d_addr, m_in_mreq_cb(s_addr)); - } - s_addr += 2; - d_addr += 2; - } - m_address_s = s_align ? (m_address_s + m_align) : s_addr; - m_address_d = d_align ? (m_address_d + m_align) : d_addr; - } - break; - - case 0b1100: // RAM -> CRAM - for (u16 block = 0; block <= m_block_num; block++) - { - auto s_addr = m_address_s; - auto d_addr = m_address_d; - for (u16 len = 0; len <= m_block_len; len++) - { - m_out_cram_cb(d_addr, m_in_mreq_cb(s_addr)); - s_addr += 2; - d_addr += 2; - } - m_address_s = s_align ? (m_address_s + m_align) : s_addr; - m_address_d = d_align ? (m_address_d + m_align) : d_addr; - } - break; - - case 0b1101: // RAM -> SFILE - for (u16 block = 0; block <= m_block_num; block++) - { - auto s_addr = m_address_s; - auto d_addr = m_address_d; - for (u16 len = 0; len <= m_block_len; len++) - { - m_out_sfile_cb(d_addr, m_in_mreq_cb(s_addr)); - s_addr += 2; - d_addr += 2; - } - m_address_s = s_align ? (m_address_s + m_align) : s_addr; - m_address_d = d_align ? (m_address_d + m_align) : d_addr; - } - break; - - default: - logerror("'tsdma': TX %02X: %06X (%02X:%04X) -> %06X\n", dev, m_address_s, m_block_len, m_block_num, m_address_d); - break; - } - - m_ready = ASSERT_LINE; - m_on_ready_cb(0); -} - -// device type definition -DEFINE_DEVICE_TYPE(TSCONF_DMA, tsconfdma_device, "tsconfdma", "TS-Conf DMA Controller") diff --git a/src/devices/machine/tsconfdma.h b/src/devices/machine/tsconfdma.h deleted file mode 100644 index 49929d3c3ae..00000000000 --- a/src/devices/machine/tsconfdma.h +++ /dev/null @@ -1,62 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Andrei I. Holub -/*************************************************************************** - - TS-Conf (ZX-Evolution) DMA - -***************************************************************************/ - -#ifndef MAME_MACHINE_TSCONF_DMA_H -#define MAME_MACHINE_TSCONF_DMA_H - -#pragma once - -class tsconfdma_device : public device_t -{ -public: - tsconfdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - auto in_mreq_callback() { return m_in_mreq_cb.bind(); } - auto out_mreq_callback() { return m_out_mreq_cb.bind(); } - auto in_spireq_callback() { return m_in_mspi_cb.bind(); } - auto out_cram_callback() { return m_out_cram_cb.bind(); } - auto out_sfile_callback() { return m_out_sfile_cb.bind(); } - auto on_ready_callback() { return m_on_ready_cb.bind(); } - - int is_ready(); - - void set_saddr_l(uint8_t addr_l); - void set_saddr_h(uint8_t addr_h); - void set_saddr_x(uint8_t addr_x); - void set_daddr_l(uint8_t addr_l); - void set_daddr_h(uint8_t addr_h); - void set_daddr_x(uint8_t addr_x); - void set_block_len(uint8_t len); - void set_block_num_l(uint8_t num_l); - void set_block_num_h(uint8_t num_h); - void start_tx(uint8_t dev, bool s_align, bool d_align, bool blitting_opt); - -private: - virtual void device_start() override; - virtual void device_reset() override; - - devcb_read16 m_in_mreq_cb; - devcb_write16 m_out_mreq_cb; - devcb_read16 m_in_mspi_cb; - devcb_write16 m_out_cram_cb; - devcb_write16 m_out_sfile_cb; - devcb_write_line m_on_ready_cb; - - u8 m_ready; - - offs_t m_address_s; - offs_t m_address_d; - u8 m_block_len; - u16 m_block_num; - bool m_align_s; - bool m_align_d; - u16 m_align; -}; - -DECLARE_DEVICE_TYPE(TSCONF_DMA, tsconfdma_device) -#endif // MAME_MACHINE_TSCONF_DMA_H diff --git a/src/mame/sinclair/atm.cpp b/src/mame/sinclair/atm.cpp index f4a36e54f36..a1eb960ffa9 100644 --- a/src/mame/sinclair/atm.cpp +++ b/src/mame/sinclair/atm.cpp @@ -4,7 +4,17 @@ MicroART ATM (clone of Spectrum) -Not working because of banking issues. +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, 64K ROM + * CMOS + * better handling of SHADOW ports + * validate screen timings *******************************************************************************************/ @@ -13,118 +23,379 @@ Not working because of banking issues. #include "specpls3.h" #include "beta_m.h" - +#include "bus/centronics/ctronics.h" #include "sound/ay8910.h" - namespace { +#define LOG_MEM (1U << 1) +#define LOG_VIDEO (1U << 2) +#define LOG_WARN (1U << 3) + +#define VERBOSE ( /*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 RAM_MASK = 0x40; +static constexpr u8 DOS7FFD_MASK = 0x80; + 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_bank1(*this, "bank1") - , m_bank2(*this, "bank2") - , m_bank3(*this, "bank3") - , m_bank4(*this, "bank4") + , 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_palette(*this, "palette") { } void atm(machine_config &config); void atmtb2(machine_config &config); protected: - virtual void machine_start() override; - virtual void machine_reset() override; + 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: - void atm_port_7ffd_w(uint8_t data); - uint8_t beta_neutral_r(offs_t offset); - uint8_t beta_enable_r(offs_t offset); - uint8_t beta_disable_r(offs_t offset); + 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_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(); - required_memory_bank m_bank1; - required_memory_bank m_bank2; - required_memory_bank m_bank3; - required_memory_bank m_bank4; + 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_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 - address_space *m_program; - uint8_t *m_p_ram; - uint16_t m_rom_selection; + 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_memory() { - uint8_t *messram = m_ram->pointer(); + 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)); + for (auto bank = 0; bank < 4 ; bank++) + { + u8 page = pen_page(bank); + if (!m_pen) + page = 3; + + if (page & RAM_MASK) + { + if (page & DOS7FFD_MASK) + page = (page & 0xf8) | (m_port_7ffd_data & 0x07); + page = 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); + } + else + { + if ((page & DOS7FFD_MASK) && !BIT(page, 1)) + page = (page & ~1) | is_shadow_active(); + page = page & 0x03; // TODO size dependent + m_bank_rom[bank]->set_entry(page); + views[bank].get().select(0); + LOGMEM(" RO(%X>%X)", m_bank_rom[bank]->entry(), page); + } + } + LOGMEM("\n"); +} - m_screen_location = messram + ((m_port_7ffd_data & 8) ? (7<<14) : (5<<14)); +void atm_state::atm_ula_w(offs_t offset, u8 data) +{ + m_br3 = ~offset & 0x08; + spectrum_128_state::spectrum_ula_w(offset, data); +} - m_bank4->set_base(messram + ((m_port_7ffd_data & 0x07) * 0x4000)); +void atm_state::atm_port_ffff_w(offs_t offset, u8 data) +{ + if(!is_shadow_active()) + return; - if (m_beta->started() && m_beta->is_active() && !( m_port_7ffd_data & 0x10 ) ) - m_rom_selection = 3; + if (m_pen2) + { + m_beta->param_w(data); + } else - /* ROM switching */ - m_rom_selection = BIT(m_port_7ffd_data, 4) ; - - /* rom 0 is 128K rom, rom 1 is 48 BASIC */ - m_bank1->set_base(&m_p_ram[0x10000 + (m_rom_selection<<14)]); + { + // 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->set_pen_color(pen, + (BIT(~data, 1) * 0xaa) | (BIT(~data, 6) * 0x55), + (BIT(~data, 4) * 0xaa) | (BIT(~data, 7) * 0x55), + (BIT(~data, 0) * 0xaa) | (BIT(~data, 5) * 0x55)); + } } -void atm_state::atm_port_7ffd_w(uint8_t data) +void atm_state::atm_port_7ffd_w(offs_t offset, u8 data) { /* disable paging */ - if (m_port_7ffd_data & 0x20) + if (BIT(m_port_7ffd_data, 5)) return; - /* store new state */ m_port_7ffd_data = data; + atm_update_memory(); + + m_screen->update_now(); + 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) +{ + if (!is_shadow_active()) + return; + + m_pen = BIT(offset, 8); + m_cpm = BIT(offset, 9); + 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"); + atm_update_memory(); + + m_maincpu->set_clock(X1_128_SINCLAIR / 10 * (1 << BIT(data, 3))); // 0 - 3.5MHz, 1 - 7MHz + + int rg = data & 0x07; + if ( m_rg ^ rg ) + { + m_rg = rg; + atm_update_video_mode(); + } +} + +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); - /* update memory */ + LOGMEM("PEN%s.%s = %X %s%d: %02X\n", (page | DOS7FFD_MASK) ? "+" : "!", BIT(m_port_7ffd_data, 4), data, (page & RAM_MASK) ? "RAM" : "ROM", bank, page & 0x3f); + pen_page(bank) = page; atm_update_memory(); } -uint8_t atm_state::beta_neutral_r(offs_t offset) +rectangle atm_state::get_screen_area() +{ + switch (m_rg) + { + case 0b110: // 80x25txt + case 0b010: // 640x200 + return rectangle { 208, 208 + 639, 76, 76 + 199 }; + break; + case 0b000: // 320x200 + return rectangle { 104, 104 + 319, 76, 76 + 199 }; + break; + case 0b011: // 256x192 + default: + return rectangle { 136, 136 + 255, 80, 80 + 191 }; + break; + } +} + +u8 atm_state::get_border_color(u16 hpos, u16 vpos) +{ + return m_br3 | (m_port_fe_data & 0x07); +} + +void atm_state::atm_update_video_mode() +{ + bool zx_scale = BIT(m_rg, 0); + 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()); + LOGVIDEO("Video mode: %d\n", m_rg); + + //spectrum_palette(m_palette); +} + +void atm_state::spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + switch (m_rg) + { + case 0b110: // txt + atm_update_screen_tx(screen, bitmap, cliprect); + break; + case 0b010: // 640x200 + atm_update_screen_hi(screen, bitmap, cliprect); + break; + case 0b000: // 320x200 + atm_update_screen_lo(screen, bitmap, cliprect); + break; + case 0b011: // 256x192 + default: // + unsupported + spectrum_128_state::spectrum_update_screen(screen, bitmap, cliprect); + break; + } +} + +void atm_state::atm_update_screen_lo(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + for (u16 vpos = cliprect.top(); vpos <= cliprect.bottom(); vpos++) + { + u16 y = vpos - get_screen_area().top(); + for (u16 hpos = cliprect.left(); hpos <= cliprect.right(); hpos++) + { + u16 x = hpos - get_screen_area().left(); + u8 *scr = m_screen_location; + if (!BIT(x, 1)) scr -= 4 << 14; + if (BIT(x, 2)) scr += 0x2000; + scr += (x >> 3) + y * 40; + u8 pix_pair = *scr; + pix_pair = x & 1 + ? (((pix_pair & 0x80) >> 1) | (pix_pair & 0x38)) >> 3 + : ((pix_pair & 0x40) >> 3) | (pix_pair & 0x07); + bitmap.pix(vpos, hpos) = pix_pair; + } + } +} + +void atm_state::atm_update_screen_hi(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + 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 *scr = m_screen_location + (x >> 4) + y * 40; + if (BIT(x, 3)) scr += 0x2000; + + u8 attr = *(scr - (4 << 14)); + u8 fg = ((attr & 0x40) >> 3) | (attr & 0x07); + u8 bg = (((attr & 0x80) >> 1) | (attr & 0x38)) >> 3; + + u8 chunk = *scr; + for (u8 i = 0x80; i; i >>= 1) + { + bitmap.pix(vpos, hpos++) = (chunk & i) ? fg : bg; + } + } + } +} + +void atm_state::atm_update_screen_tx(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + 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 = m_screen_location + 0x1c0 + (x >> 4) + ((y >> 3) * 64); + u8 *attr_location = symb_location - (4 << 14) + BIT(x, 3); + if (BIT(x, 3)) + symb_location += 0x2000; + else + attr_location += 0x2000; + + u8 attr = *attr_location; + 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)); + for (u8 i = 0x80; i; i >>= 1) + { + bitmap.pix(vpos, hpos++) = (chunk & i) ? fg : bg; + } + } + } +} + +u8 atm_state::beta_neutral_r(offs_t offset) { - return m_program->read_byte(offset); + return m_program.read_byte(offset); } -uint8_t atm_state::beta_enable_r(offs_t offset) +u8 atm_state::beta_enable_r(offs_t offset) { - if (m_rom_selection == 1) { - m_rom_selection = 3; - if (m_beta->started()) { + if (!machine().side_effects_disabled()) { + u8 page = pen_page(0); + if (!(page & RAM_MASK) && !is_shadow_active()) { m_beta->enable(); - m_bank1->set_base(&m_p_ram[0x18000]); + atm_update_memory(); } } - return m_program->read_byte(offset + 0x3d00); + return m_program.read_byte(offset + 0x3d00); } -uint8_t atm_state::beta_disable_r(offs_t offset) +u8 atm_state::beta_disable_r(offs_t offset) { - if (m_beta->started() && m_beta->is_active()) { - m_rom_selection = BIT(m_port_7ffd_data, 4); - m_beta->disable(); - m_bank1->set_base(&m_p_ram[0x10000 + (m_rom_selection<<14)]); + if (!machine().side_effects_disabled()) { + if (is_shadow_active() && m_cpm) { + m_beta->disable(); + atm_update_memory(); + } } - return m_program->read_byte(offset + 0x4000); + return m_program.read_byte(offset + 0x4000); } void atm_state::atm_mem(address_map &map) { - map(0x0000, 0x3fff).bankr("bank1"); - map(0x4000, 0x7fff).bankrw("bank2"); - map(0x8000, 0xbfff).bankrw("bank3"); - map(0xc000, 0xffff).bankrw("bank4"); + map(0x0000, 0x3fff).bankrw(m_bank_ram[0]); + map(0x0000, 0x3fff).view(m_bank_view0); + m_bank_view0[0](0x0000, 0x3fff).bankr(m_bank_rom[0]); + + map(0x4000, 0x7fff).bankrw(m_bank_ram[1]); + map(0x4000, 0x7fff).view(m_bank_view1); + m_bank_view1[0](0x4000, 0x7fff).bankr(m_bank_rom[1]); + + map(0x8000, 0xbfff).bankrw(m_bank_ram[2]); + map(0x8000, 0xbfff).view(m_bank_view2); + m_bank_view2[0](0x8000, 0xbfff).bankr(m_bank_rom[2]); + + map(0xc000, 0xffff).bankrw(m_bank_ram[3]); + map(0xc000, 0xffff).view(m_bank_view3); + m_bank_view3[0](0xc000, 0xffff).bankr(m_bank_rom[3]); } void atm_state::atm_io(address_map &map) @@ -134,9 +405,13 @@ void atm_state::atm_io(address_map &map) 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(0x00fe, 0x00fe).select(0xff00).rw(FUNC(atm_state::spectrum_ula_r), FUNC(atm_state::spectrum_ula_w)); - map(0x00ff, 0x00ff).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w)); - map(0x4000, 0x4000).mirror(0x3ffd).w(FUNC(atm_state::atm_port_7ffd_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)); + 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(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)); } @@ -153,57 +428,72 @@ void atm_state::machine_start() { spectrum_128_state::machine_start(); - m_rom_selection = 0; + save_item(NAME(m_pen)); + save_item(NAME(m_cpm)); + save_item(NAME(m_pages_map)); + save_item(NAME(m_pen2)); + save_item(NAME(m_rg)); + save_item(NAME(m_br3)); + + // reconfigure ROMs + memory_region *rom = memregion("maincpu"); + for (auto i = 0; i < 4; i++) + m_bank_rom[i]->configure_entries(0, 4*8, rom->base() + 0x10000, 0x4000); + m_bank_ram[0]->configure_entries(0, m_ram->size() / 0x4000, m_ram->pointer(), 0x4000); - save_item(NAME(m_rom_selection)); + m_maincpu->space(AS_PROGRAM).specific(m_program); } void atm_state::machine_reset() { - uint8_t *messram = m_ram->pointer(); - m_program = &m_maincpu->space(AS_PROGRAM); - m_p_ram = memregion("maincpu")->base(); - - if (m_beta->started()) - m_beta->enable(); - - memset(messram,0,128*1024); - - /* Bank 5 is always in 0x4000 - 0x7fff */ - m_bank2->set_base(messram + (5<<14)); - - /* Bank 2 is always in 0x8000 - 0xbfff */ - m_bank3->set_base(messram + (2<<14)); + m_beta->enable(); m_port_7ffd_data = 0; m_port_1ffd_data = -1; - atm_update_memory(); + m_br3 = 0; + atm_port_ff77_w(0x4000, 3); // 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_contention_pattern = {}; } /* F4 Character Displayer */ static const gfx_layout spectrum_charlayout = { - 8, 8, /* 8 x 8 characters */ - 96, /* 96 characters */ - 1, /* 1 bits per pixel */ - { 0 }, /* no bitplanes */ - /* x offsets */ - { 0, 1, 2, 3, 4, 5, 6, 7 }, - /* y offsets */ - { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, - 8*8 /* every char takes 8 bytes */ + 8, 8, // 8 x 8 characters + 96, // 96 characters + 1, // 1 bits per pixel + { 0 }, // no bitplanes + { STEP8(0, 1) }, // x offsets + { STEP8(0, 8) }, // y offsets + 8 * 8 // every char takes 8 bytes +}; + +static const gfx_layout atm_charlayout = +{ + 8, 8, // 8 x 8 characters + 256, // 96 characters + 1, // 1 bits per pixel + { 0 }, // no bitplanes + { STEP8(0, 1) }, // x offsets + { STEP8(0, 8) }, // y offsets + 8 * 8 // every char takes 8 bytes }; static GFXDECODE_START( gfx_atm ) - GFXDECODE_ENTRY( "maincpu", 0x1fd00, spectrum_charlayout, 0, 8 ) + GFXDECODE_ENTRY( "maincpu", 0x1fd00, spectrum_charlayout, 7, 1 ) GFXDECODE_END static GFXDECODE_START( gfx_atmtb2 ) - GFXDECODE_ENTRY( "maincpu", 0x13d00, spectrum_charlayout, 0, 8 ) + GFXDECODE_ENTRY( "charrom", 0, atm_charlayout, 7, 1 ) + GFXDECODE_ENTRY( "maincpu", 0x13d00, spectrum_charlayout, 7, 1 ) GFXDECODE_END - void atm_state::atm(machine_config &config) { spectrum_128(config); @@ -211,10 +501,16 @@ 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->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); - subdevice("gfxdecode")->set_info(gfx_atm); + CENTRONICS(config, m_centronics, centronics_devices, "covox"); + output_latch_device ¢_data_out(OUTPUT_LATCH(config, "cent_data_out")); + m_centronics->set_output_latch(cent_data_out); config.device_remove("exp"); } @@ -222,6 +518,9 @@ void atm_state::atm(machine_config &config) 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"); subdevice("gfxdecode")->set_info(gfx_atmtb2); } @@ -272,8 +571,7 @@ 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", MACHINE_NOT_WORKING) -//COMP( 1991, atmtb1, spec128, 0, atm, spec_plus, atm_state, empty_init, "MicroART", "ATM-turbo1", MACHINE_NOT_WORKING) -COMP( 1993, atmtb2, spec128, 0, atmtb2, spec_plus, atm_state, empty_init, "MicroART", "ATM-turbo2", MACHINE_NOT_WORKING) -//COMP( 1994, turbo2, spec128, 0, atm, spec_plus, atm_state, empty_init, "MicroART", "TURBO 2+", MACHINE_NOT_WORKING) +/* 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 diff --git a/src/mame/sinclair/glukrs.cpp b/src/mame/sinclair/glukrs.cpp new file mode 100644 index 00000000000..aee7348b3e0 --- /dev/null +++ b/src/mame/sinclair/glukrs.cpp @@ -0,0 +1,60 @@ +// license:BSD-3-Clause +// copyright-holders:Andrei I. Holub +/*************************************************************************** + + Mr Gluk Reset Service + + 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/ + +****************************************************************************/ + +#include "emu.h" +#include "glukrs.h" + +glukrs_device::glukrs_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, GLUKRS, tag, owner, clock), + device_rtc_interface(mconfig, *this), + m_nvram(*this, "nvram") {} + +void glukrs_device::device_add_mconfig(machine_config &config) +{ + NVRAM(config, m_nvram, nvram_device::DEFAULT_ALL_1); +} + +void glukrs_device::device_start() +{ + m_nvram->set_base(&m_cmos, sizeof(m_cmos)); + + m_timer = timer_alloc(FUNC(glukrs_device::timer_callback), this); + m_timer->adjust(attotime::from_hz(clock() / XTAL(32'768)), 0, attotime::from_hz(clock() / XTAL(32'768))); +} + +u8 glukrs_device::read(offs_t address) +{ + return m_cmos[address]; +} + +void glukrs_device::write(offs_t address, u8 data) +{ + m_cmos[address] = data; +} + +void glukrs_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ + m_cmos[0x00] = convert_to_bcd(second); + m_cmos[0x02] = convert_to_bcd(minute); + m_cmos[0x04] = convert_to_bcd(hour); + m_cmos[0x06] = convert_to_bcd(day_of_week); + m_cmos[0x07] = convert_to_bcd(day); + m_cmos[0x08] = convert_to_bcd(month); + m_cmos[0x09] = convert_to_bcd(year % 100); +} + +TIMER_CALLBACK_MEMBER(glukrs_device::timer_callback) +{ + advance_seconds(); +} + +// device type definition +DEFINE_DEVICE_TYPE(GLUKRS, glukrs_device, "glukrs", "Mr Gluk Reset Service") diff --git a/src/mame/sinclair/glukrs.h b/src/mame/sinclair/glukrs.h new file mode 100644 index 00000000000..7953f0b0a34 --- /dev/null +++ b/src/mame/sinclair/glukrs.h @@ -0,0 +1,35 @@ +// license:BSD-3-Clause +// copyright-holders:Andrei I. Holub + +#ifndef MAME_SINCLAIR_GLUKRS_H +#define MAME_SINCLAIR_GLUKRS_H + +#pragma once + +#include "machine/nvram.h" +#include "dirtc.h" + +class glukrs_device : public device_t, + public device_rtc_interface +{ +public: + glukrs_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 32'768); + + u8 read(offs_t address); + void write(offs_t address, u8 data); + + TIMER_CALLBACK_MEMBER(timer_callback); + +protected: + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second) override; + +private: + u8 m_cmos[0x100]; + required_device m_nvram; + emu_timer *m_timer; +}; + +DECLARE_DEVICE_TYPE(GLUKRS, glukrs_device) +#endif // MAME_SINCLAIR_GLUKRS_H diff --git a/src/mame/sinclair/tsconf.h b/src/mame/sinclair/tsconf.h index 22bcfbfa5b7..13dde4afca1 100644 --- a/src/mame/sinclair/tsconf.h +++ b/src/mame/sinclair/tsconf.h @@ -14,10 +14,10 @@ #include "beta_m.h" -#include "machine/glukrs.h" +#include "glukrs.h" #include "machine/pckeybrd.h" #include "machine/spi_sdcard.h" -#include "machine/tsconfdma.h" +#include "tsconfdma.h" #include "tilemap.h" diff --git a/src/mame/sinclair/tsconf_m.cpp b/src/mame/sinclair/tsconf_m.cpp index fa6e956569e..e02c26abdfd 100644 --- a/src/mame/sinclair/tsconf_m.cpp +++ b/src/mame/sinclair/tsconf_m.cpp @@ -154,27 +154,27 @@ void tsconf_state::spectrum_update_screen(screen_device &screen, bitmap_ind16 &b } } -void tsconf_state::tsconf_UpdateZxScreenBitmap(screen_device &screen_d, bitmap_ind16 &bitmap, const rectangle &screen) +void tsconf_state::tsconf_UpdateZxScreenBitmap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { u8 pal_offset = m_regs[PAL_SEL] << 4; u8 *screen_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]); u8 *attrs_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + 0x1800; - 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(); u16 y = vpos - get_screen_area().top(); u8 *scr = &screen_location[((y & 7) << 8) | ((y & 0x38) << 2) | ((y & 0xc0) << 5) | (x >> 3)]; u8 *attr = &attrs_location[((y & 0xf8) << 2) | (x >> 3)]; u16 *pix = &(bitmap.pix(vpos, hpos)); - while (hpos <= screen.right()) + while (hpos <= cliprect.right()) { u16 ink = pal_offset | ((*attr >> 3) & 0x08) | (*attr & 0x07); u16 pap = pal_offset | ((*attr >> 3) & 0x0f); u8 pix8 = (invert_attrs && (*attr & 0x80)) ? ~*scr : *scr; - for (u8 b = 0x80 >> (x & 0x07); b != 0 && hpos <= screen.right(); b >>= 1, x++, hpos++) + for (u8 b = 0x80 >> (x & 0x07); b != 0 && hpos <= cliprect.right(); b >>= 1, x++, hpos++) *pix++ = (pix8 & b) ? ink : pap; scr++; attr++; @@ -182,13 +182,13 @@ void tsconf_state::tsconf_UpdateZxScreenBitmap(screen_device &screen_d, bitmap_i } } -void tsconf_state::tsconf_UpdateTxtBitmap(bitmap_ind16 &bitmap, const rectangle &screen) +void tsconf_state::tsconf_UpdateTxtBitmap(bitmap_ind16 &bitmap, const rectangle &cliprect) { u8 *font_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE] ^ 0x01); u8 pal_offset = m_regs[PAL_SEL] << 4; - for (u16 vpos = screen.top(); vpos <= screen.bottom(); vpos++) + for (u16 vpos = cliprect.top(); vpos <= cliprect.bottom(); vpos++) { - u16 hpos = screen.left(); + u16 hpos = cliprect.left(); u16 x = hpos - get_screen_area().left(); u16 y = vpos - get_screen_area().top(); u16 y_offset = (OFFS_512(G_Y_OFFS_L) + y) & 0x1ff; @@ -196,28 +196,28 @@ void tsconf_state::tsconf_UpdateTxtBitmap(bitmap_ind16 &bitmap, const rectangle // TODO? u16 x_offset = OFFS_512(G_X_OFFS_L); u8 *text_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + (y_offset / 8 * 256 + x / 8); u16 *pix = &(bitmap.pix(vpos, hpos)); - while (hpos <= screen.right()) + while (hpos <= cliprect.right()) { u8 font_color = *(text_location + 128) & 0x0f; u8 bg_color = (*(text_location + 128) & 0xf0) >> 4; u8 char_x = *(font_location + (*text_location * 8) + (y_offset % 8)); - for (u8 b = 0x80 >> (x & 0x07); b != 0 && hpos <= screen.right(); b >>= 1, x++, hpos++) + for (u8 b = 0x80 >> (x & 0x07); b != 0 && hpos <= cliprect.right(); b >>= 1, x++, hpos++) *pix++ = pal_offset | ((char_x & b) ? font_color : bg_color); text_location++; } } } -void tsconf_state::tsconf_UpdateGfxBitmap(bitmap_ind16 &bitmap, const rectangle &screen) +void tsconf_state::tsconf_UpdateGfxBitmap(bitmap_ind16 &bitmap, const rectangle &cliprect) { u8 pal_offset = m_regs[PAL_SEL] << 4; - for (u16 vpos = screen.top(); vpos <= screen.bottom(); vpos++) + for (u16 vpos = cliprect.top(); vpos <= cliprect.bottom(); vpos++) { u16 y_offset = (0x200 + OFFS_512(G_Y_OFFS_L) + m_gfx_y_frame_offset + vpos) & 0x1ff; - u16 x_offset = (OFFS_512(G_X_OFFS_L) + (screen.left() - get_screen_area().left())) & 0x1ff; + u16 x_offset = (OFFS_512(G_X_OFFS_L) + (cliprect.left() - get_screen_area().left())) & 0x1ff; u8 *video_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + ((y_offset * 512 + x_offset) >> (2 - VM)); - u16 *bm = &(bitmap.pix(vpos, screen.left())); - s16 width = screen.width(); + u16 *bm = &(bitmap.pix(vpos, cliprect.left())); + s16 width = cliprect.width(); if (VM == VM_16C) { if (x_offset & 1) diff --git a/src/mame/sinclair/tsconfdma.cpp b/src/mame/sinclair/tsconfdma.cpp new file mode 100644 index 00000000000..79ef8bc2d50 --- /dev/null +++ b/src/mame/sinclair/tsconfdma.cpp @@ -0,0 +1,213 @@ +// license:BSD-3-Clause +// copyright-holders:Andrei I. Holub +/********************************************************************** + + TS-Conf (ZX-Evolution) DMA Controller + +**********************************************************************/ + +#include "emu.h" +#include "tsconfdma.h" + +tsconfdma_device::tsconfdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, TSCONF_DMA, tag, owner, clock), + m_in_mreq_cb(*this), + m_out_mreq_cb(*this), + m_in_mspi_cb(*this), + m_out_cram_cb(*this), + m_out_sfile_cb(*this), + m_on_ready_cb(*this) +{ +} + +void tsconfdma_device::device_start() +{ + m_in_mreq_cb.resolve_safe(0); + m_out_mreq_cb.resolve_safe(); + m_in_mspi_cb.resolve_safe(0); + m_out_cram_cb.resolve_safe(); + m_out_sfile_cb.resolve_safe(); + m_on_ready_cb.resolve_safe(); + + save_item(NAME(m_ready)); + save_item(NAME(m_address_s)); + save_item(NAME(m_address_d)); + save_item(NAME(m_block_len)); + save_item(NAME(m_block_num)); + save_item(NAME(m_align_s)); + save_item(NAME(m_align_d)); + save_item(NAME(m_align)); +} + +void tsconfdma_device::device_reset() +{ + m_block_num = 0; + m_ready = ASSERT_LINE; +} + +int tsconfdma_device::is_ready() +{ + return m_ready; +} + +void tsconfdma_device::set_saddr_l(u8 addr_l) +{ + m_address_s = (m_address_s & 0xffffff00) | (addr_l & 0xfe); +} + +void tsconfdma_device::set_saddr_h(u8 addr_h) +{ + m_address_s = (m_address_s & 0xffffc0ff) | ((addr_h & 0x3f) << 8); +} + +void tsconfdma_device::set_saddr_x(u8 addr_x) +{ + m_address_s = (m_address_s & 0x0003fff) | (addr_x << 14); +} + +void tsconfdma_device::set_daddr_l(u8 addr_l) +{ + m_address_d = (m_address_d & 0xffffff00) | (addr_l & 0xfe); +} + +void tsconfdma_device::set_daddr_h(u8 addr_h) +{ + m_address_d = (m_address_d & 0xffffc0ff) | ((addr_h & 0x3f) << 8); +} + +void tsconfdma_device::set_daddr_x(u8 addr_x) +{ + m_address_d = (m_address_d & 0x0003fff) | (addr_x << 14); +} + +void tsconfdma_device::set_block_len(u8 len) +{ + // 1..256 + m_block_len = len; +} + +void tsconfdma_device::set_block_num_l(u8 num_l) +{ + m_block_num = (m_block_num & 0xff00) | num_l; +} + +void tsconfdma_device::set_block_num_h(u8 num_h) +{ + // 1..1025 * 2 + m_block_num = (m_block_num & 0x00ff) | ((num_h & 0x03) << 8); +} + +void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_opt) +{ + m_ready = CLEAR_LINE; + m_align = align_opt ? 512 : 256; + + // TODO Transfers 2 byte/cycle at 7MHz + switch (dev) + { + case 0b0001: // Mem -> Mem + for (u16 block = 0; block <= m_block_num; block++) + { + auto s_addr = m_address_s; + auto d_addr = m_address_d; + for (u16 len = 0; len <= m_block_len; len++) + { + m_out_mreq_cb(d_addr, m_in_mreq_cb(s_addr)); + s_addr += 2; + d_addr += 2; + } + m_address_s = s_align ? (m_address_s + m_align) : s_addr; + m_address_d = d_align ? (m_address_d + m_align) : d_addr; + } + break; + + case 0b0010: // SPI -> Mem + for (u16 block = 0; block <= m_block_num; block++) + { + auto d_addr = m_address_d; + for (u16 len = 0; len <= m_block_len; len++) + { + m_out_mreq_cb(d_addr, m_in_mspi_cb()); + d_addr += 2; + } + m_address_d = d_align ? (m_address_d + m_align) : d_addr; + } + break; + + case 0b0100: // Fill + for (u16 block = 0; block <= m_block_num; block++) + { + u16 data = m_in_mreq_cb(m_address_s); + auto d_addr = m_address_d; + for (u16 len = 0; len <= m_block_len; len++) + { + m_out_mreq_cb(d_addr, data); + d_addr += 2; + } + m_address_d = d_align ? (m_address_d + m_align) : d_addr; + } + break; + + case 0b1001: // Blt -> Mem + for (u16 block = 0; block <= m_block_num; block++) + { + auto s_addr = m_address_s; + auto d_addr = m_address_d; + for (u16 len = 0; len <= m_block_len; len++) + { + u16 d_val = m_in_mreq_cb(d_addr); + if (d_val != 0) + { + m_out_mreq_cb(d_addr, m_in_mreq_cb(s_addr)); + } + s_addr += 2; + d_addr += 2; + } + m_address_s = s_align ? (m_address_s + m_align) : s_addr; + m_address_d = d_align ? (m_address_d + m_align) : d_addr; + } + break; + + case 0b1100: // RAM -> CRAM + for (u16 block = 0; block <= m_block_num; block++) + { + auto s_addr = m_address_s; + auto d_addr = m_address_d; + for (u16 len = 0; len <= m_block_len; len++) + { + m_out_cram_cb(d_addr, m_in_mreq_cb(s_addr)); + s_addr += 2; + d_addr += 2; + } + m_address_s = s_align ? (m_address_s + m_align) : s_addr; + m_address_d = d_align ? (m_address_d + m_align) : d_addr; + } + break; + + case 0b1101: // RAM -> SFILE + for (u16 block = 0; block <= m_block_num; block++) + { + auto s_addr = m_address_s; + auto d_addr = m_address_d; + for (u16 len = 0; len <= m_block_len; len++) + { + m_out_sfile_cb(d_addr, m_in_mreq_cb(s_addr)); + s_addr += 2; + d_addr += 2; + } + m_address_s = s_align ? (m_address_s + m_align) : s_addr; + m_address_d = d_align ? (m_address_d + m_align) : d_addr; + } + break; + + default: + logerror("'tsdma': TX %02X: %06X (%02X:%04X) -> %06X\n", dev, m_address_s, m_block_len, m_block_num, m_address_d); + break; + } + + m_ready = ASSERT_LINE; + m_on_ready_cb(0); +} + +// device type definition +DEFINE_DEVICE_TYPE(TSCONF_DMA, tsconfdma_device, "tsconfdma", "TS-Conf DMA Controller") diff --git a/src/mame/sinclair/tsconfdma.h b/src/mame/sinclair/tsconfdma.h new file mode 100644 index 00000000000..582017fdfff --- /dev/null +++ b/src/mame/sinclair/tsconfdma.h @@ -0,0 +1,62 @@ +// license:BSD-3-Clause +// copyright-holders:Andrei I. Holub +/*************************************************************************** + + TS-Conf (ZX-Evolution) DMA + +***************************************************************************/ + +#ifndef MAME_SINCLAIR_TSCONF_DMA_H +#define MAME_SINCLAIR_TSCONF_DMA_H + +#pragma once + +class tsconfdma_device : public device_t +{ +public: + tsconfdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto in_mreq_callback() { return m_in_mreq_cb.bind(); } + auto out_mreq_callback() { return m_out_mreq_cb.bind(); } + auto in_spireq_callback() { return m_in_mspi_cb.bind(); } + auto out_cram_callback() { return m_out_cram_cb.bind(); } + auto out_sfile_callback() { return m_out_sfile_cb.bind(); } + auto on_ready_callback() { return m_on_ready_cb.bind(); } + + int is_ready(); + + void set_saddr_l(uint8_t addr_l); + void set_saddr_h(uint8_t addr_h); + void set_saddr_x(uint8_t addr_x); + void set_daddr_l(uint8_t addr_l); + void set_daddr_h(uint8_t addr_h); + void set_daddr_x(uint8_t addr_x); + void set_block_len(uint8_t len); + void set_block_num_l(uint8_t num_l); + void set_block_num_h(uint8_t num_h); + void start_tx(uint8_t dev, bool s_align, bool d_align, bool blitting_opt); + +private: + virtual void device_start() override; + virtual void device_reset() override; + + devcb_read16 m_in_mreq_cb; + devcb_write16 m_out_mreq_cb; + devcb_read16 m_in_mspi_cb; + devcb_write16 m_out_cram_cb; + devcb_write16 m_out_sfile_cb; + devcb_write_line m_on_ready_cb; + + u8 m_ready; + + offs_t m_address_s; + offs_t m_address_d; + u8 m_block_len; + u16 m_block_num; + bool m_align_s; + bool m_align_d; + u16 m_align; +}; + +DECLARE_DEVICE_TYPE(TSCONF_DMA, tsconfdma_device) +#endif // MAME_SINCLAIR_TSCONF_DMA_H -- cgit v1.2.3