diff --git a/src/mame/mame.lst b/src/mame/mame.lst index ab79edef28a40..7963f32749d61 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -42925,6 +42925,7 @@ uk2086 @source:sinclair/tsconf.cpp tsconf +tsconf2 @source:sinclair/zx.cpp lambda diff --git a/src/mame/sinclair/specnext.cpp b/src/mame/sinclair/specnext.cpp index 594736f71601e..6c5986b4950de 100644 --- a/src/mame/sinclair/specnext.cpp +++ b/src/mame/sinclair/specnext.cpp @@ -134,7 +134,7 @@ class specnext_state : public spectrum_128_state void turbosound_address_w(u8 data); u8 mf_port_r(offs_t addr); void mf_port_w(offs_t addr, u8 data); - attotime cooper_until_pos_r(u16 pos); + attotime copper_until_pos_r(u16 pos); void bank_update(u8 bank, u8 count); void bank_update(u8 bank); @@ -1098,7 +1098,7 @@ void specnext_state::mf_port_w(offs_t addr, u8 data) m_mf->port_mf_disable_rd_w(0); } -attotime specnext_state::cooper_until_pos_r(u16 pos) +attotime specnext_state::copper_until_pos_r(u16 pos) { const u16 vcount = BIT(pos, 0, 9); const u16 hcount = ((BIT(pos, 9, 6) << 3) + (BIT(pos, 15) ? 12 : 0)) << 1; @@ -3536,7 +3536,7 @@ void specnext_state::tbblue(machine_config &config) SPECNEXT_COPPER(config, m_copper, 28_MHz_XTAL); m_copper->out_nextreg_cb().set(FUNC(specnext_state::reg_w)); - m_copper->set_in_until_pos_cb(FUNC(specnext_state::cooper_until_pos_r)); + m_copper->set_in_until_pos_cb(FUNC(specnext_state::copper_until_pos_r)); config.device_remove("snapshot"); } diff --git a/src/mame/sinclair/tsconf.cpp b/src/mame/sinclair/tsconf.cpp index ebd736d672e90..ae2b78408b5ab 100644 --- a/src/mame/sinclair/tsconf.cpp +++ b/src/mame/sinclair/tsconf.cpp @@ -21,6 +21,10 @@ Features (TS-Configuration): - DRAM-to-Device, Device-to-DRAM and DRAM-to-DRAM DMA Controller +Revisions: + tsconf: Initial release for ZX Evolution baser on Altera's FPGA 50K + tsconf2: Requires 100K FPGA and has extra feature set like 'Copper' + Refs: 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 @@ -332,6 +336,18 @@ void tsconf_state::tsconf(machine_config &config) SOFTWARE_LIST(config, "betadisc_list_tsconf").set_original("tsconf_betadisc_flop"); } + +void tsconf_state::tsconf2(machine_config &config) +{ + tsconf(config); + TSCONF_COPPER(config, m_copper, 28_MHz_XTAL); + m_copper->out_wreg_cb().set(FUNC(tsconf_state::tsconf_port_xxaf_w)); + m_copper->set_in_until_pos_cb(FUNC(tsconf_state::copper_until_pos_r)); + + m_dma->on_ready_callback().append(m_copper, FUNC(tsconf_copper_device::dma_ready_w)); +} + + ROM_START(tsconf) ROM_REGION(0x080000, "maincpu", ROMREGION_ERASEFF) // ROM: 32 * 16KB ROM_DEFAULT_BIOS("v2407") @@ -346,5 +362,18 @@ ROM_START(tsconf) ROM_LOAD( "cram-init.bin", 0, 0x200, CRC(8b96ffb7) SHA1(4dbd22f4312251e922911a01526cbfba77a122fc)) ROM_END -// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 2011, tsconf, spec128, 0, tsconf, tsconf, tsconf_state, empty_init, "NedoPC, TS-Labs", "ZX Evolution: TS-Configuration", MACHINE_SUPPORTS_SAVE) +ROM_START(tsconf2) + ROM_REGION(0x080000, "maincpu", ROMREGION_ERASEFF) // ROM: 32 * 16KB + ROM_DEFAULT_BIOS("v2407") + + ROM_SYSTEM_BIOS(0, "v2407", "Update 24.07.28") + ROMX_LOAD("ts-bios.240728.rom", 0, 0x10000, CRC(19f8ad7b) SHA1(9cee82d4a6212686358a50b0fd5a2981b3323ab6), ROM_BIOS(0)) + + ROM_REGION(0x200, "cram_init", ROMREGION_ERASEFF) + ROM_LOAD( "cram-init.bin", 0, 0x200, CRC(8b96ffb7) SHA1(4dbd22f4312251e922911a01526cbfba77a122fc)) +ROM_END + + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 2011, tsconf, 0, 0, tsconf, tsconf, tsconf_state, empty_init, "NedoPC, TS-Labs", "ZX Evolution: TS-Configuration", MACHINE_SUPPORTS_SAVE) +COMP( 2024, tsconf2, tsconf, 0, tsconf2, tsconf, tsconf_state, empty_init, "TS-Labs", "EvoMAX3: TS-Configuration 2", MACHINE_SUPPORTS_SAVE) diff --git a/src/mame/sinclair/tsconf.h b/src/mame/sinclair/tsconf.h index c9b17644abd63..141509bb942a4 100644 --- a/src/mame/sinclair/tsconf.h +++ b/src/mame/sinclair/tsconf.h @@ -13,8 +13,9 @@ #include "spec128.h" #include "glukrs.h" +#include "tsconf_copper.h" +#include "tsconf_dma.h" #include "tsconf_rs232.h" -#include "tsconfdma.h" #include "beta_m.h" #include "machine/pckeybrd.h" @@ -43,10 +44,12 @@ class tsconf_state : public spectrum_128_state , m_cram(*this, "cram") , m_sfile(*this, "sfile") , m_dac(*this, "dac") + , m_copper(*this, "copper") { } void tsconf(machine_config &config); + void tsconf2(machine_config &config); static constexpr u16 with_hblank(u16 pixclocks) { return 88 + pixclocks; } static constexpr u16 with_vblank(u16 pixclocks) { return 32 + pixclocks; } @@ -100,6 +103,7 @@ class tsconf_state : public spectrum_128_state PAGE2 = 0x12, PAGE3 = 0x13, + COPPER = 0x14, FMAPS = 0x15, T_MAP_PAGE = 0x16, T0_G_PAGE = 0x17, @@ -173,6 +177,7 @@ class tsconf_state : public spectrum_128_state void draw_sprites(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); void tsconf_update_video_mode(); void copy_tiles_to_raw(const u8 *tiles_src, u8 *raw_target); + attotime copper_until_pos_r(u16 pos); u8 tsconf_port_xx1f_r(offs_t offset); void tsconf_port_7ffd_w(u8 data); @@ -239,6 +244,7 @@ class tsconf_state : public spectrum_128_state std::vector m_sprites_cache; required_device m_dac; + optional_device m_copper; }; /*----------- defined in drivers/tsconf.c -----------*/ diff --git a/src/mame/sinclair/tsconf_copper.cpp b/src/mame/sinclair/tsconf_copper.cpp new file mode 100644 index 0000000000000..8f71807d033c7 --- /dev/null +++ b/src/mame/sinclair/tsconf_copper.cpp @@ -0,0 +1,217 @@ +// license:BSD-3-Clause +// copyright-holders:Andrei I. Holub +/********************************************************************** + TS-Configuration Copper +**********************************************************************/ + +#include "emu.h" +#include "tsconf_copper.h" + + +#define LOG_CTRL (1U << 1) +#define LOG_DATA (1U << 2) + +//#define VERBOSE ( LOG_GENERAL /*| LOG_CTRL | LOG_DATA*/ ) +#include "logmacro.h" + +#define LOGCTRL(...) LOGMASKED(LOG_CTRL, __VA_ARGS__) +#define LOGDATA(...) LOGMASKED(LOG_DATA, __VA_ARGS__) + + +// device type definition +DEFINE_DEVICE_TYPE(TSCONF_COPPER, tsconf_copper_device, "tsconf_copper", "TS-Configuration Copper") + + +tsconf_copper_device::tsconf_copper_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, TSCONF_COPPER, tag, owner, clock) + , m_timer(nullptr) + , m_cl_data(*this, "cl_data", 0x100, ENDIANNESS_LITTLE) + , m_out_wreg_cb(*this) + , m_in_dma_ready_cb(*this, 0) + , m_in_until_pos_cb(*this) +{ +} + +void tsconf_copper_device::copper_en_w(u8 data) +{ + m_en = data != 0xff; + m_pc = data; + + if (m_en) + { + LOGCTRL("START\n"); + m_timer->adjust(attotime::zero); + } + else + { + LOGCTRL("STOP\n"); + m_timer->reset(); + } +} + +void tsconf_copper_device::cl_data_w(u16 addr, u8 data) +{ + addr &= 0x1ff; + LOGDATA("data(W) %02x %04x\n", addr, data); + m_cl_data[addr >> 1] = (addr & 1) + ? (m_cl_data[addr >> 1] & 0x00ff) | (data << 8) + : (m_cl_data[addr >> 1] & 0xff00) | data; +} + +void tsconf_copper_device::dma_ready_w(int status) +{ + if(m_en && (status & 1) && (m_cl_data[m_pc] & 0xffff) == 0b1111'1011'1111'0001) + { + ++m_pc; + m_timer->adjust(attotime::from_hz(clock()), 0); + } +} + +TIMER_CALLBACK_MEMBER(tsconf_copper_device::timer_callback) +{ + const u16 data = m_cl_data[m_pc]; + if (BIT(data, 12, 4) == 0b1111) // all instructions except WREG + { + switch (BIT(data, 8, 4)) + { + case 0b0110: //SETA + m_a = data & 0xff; + ++m_pc; + break; + + case 0b1000: //SETB + case 0b1001: + m_b = data & 0x1ff; + ++m_pc; + break; + + case 0b0111: // WAITX + if (param == 0b1111'0111) + ++m_pc; + else + { + const u8 x = data & 0xff; + if (x < 224) + m_timer->adjust(m_in_until_pos_cb(0x8000 | x), 0b1111'0111); + else + m_timer->reset(); + return; + } + break; + + case 0b1011: // WAITY + if (BIT(data, 4, 4) == 0b1111) // WAIT event + { + const u8 event = data & 0x0f; + if (event == param) + ++m_pc; + else + { + switch (event) + { + case 1: // DMA + m_timer->reset(); + return; + break; + case 2: // frame + m_timer->adjust(m_in_until_pos_cb(0b00 << 14), 2); + return; + break; + case 3: // line start + m_timer->adjust(m_in_until_pos_cb(0b11 << 14), 3); + return; + break; + default: + ++m_pc; + break; + + } + } + break; + } + [[fallthrough]]; + case 0b1010: + if (param == 0b1111'1010) + ++m_pc; + else + { + const u16 y = data & 0x1ff; + if (y < 320) + m_timer->adjust(m_in_until_pos_cb(0x4000 | y), 0b1111'1010); + else + m_timer->reset(); + return; + } + break; + + case 0b1100: // DJNZA + --m_a; + m_pc = m_a ? data & 0xff : (m_pc + 1); + break; + + case 0b1101: // DJNZB + --m_b; + m_pc = m_b ? data & 0xff : (m_pc + 1); + break; + + case 0b1110: // CALL + m_ret_pc = m_pc + 1; + m_pc = data & 0xff; + break; + + case 0b1111: // JUMP + { + const u8 to = data & 0xff; + if (to == m_pc) // HALT + { + m_en = false; + m_timer->reset(); + return; + } + + m_pc = (to == 0xff) ? m_ret_pc : to; + } + break; + + case 0b0101: // SIGNAL + ++m_pc; // TODO signal logic + break; + + default: // reserved instructions + ++m_pc; + break; + } + } + else + { + m_out_wreg_cb((data & 0xff00) | 0xaf, data & 0x00ff); + ++m_pc; + } + + m_timer->adjust(attotime::from_hz(clock()), 0); +} + + +void tsconf_copper_device::device_start() +{ + m_timer = timer_alloc(FUNC(tsconf_copper_device::timer_callback), this); + + m_in_until_pos_cb.resolve_safe(attotime::zero); + + save_item(NAME(m_en)); + save_item(NAME(m_pc)); + save_item(NAME(m_ret_pc)); + save_item(NAME(m_a)); + save_item(NAME(m_b)); +} + +void tsconf_copper_device::device_reset() +{ + m_timer->reset(); + + m_en = false; + m_pc = 0; + m_ret_pc = 0; + m_a = 0; + m_b = 0; +} diff --git a/src/mame/sinclair/tsconf_copper.h b/src/mame/sinclair/tsconf_copper.h new file mode 100644 index 0000000000000..e8663ee853c73 --- /dev/null +++ b/src/mame/sinclair/tsconf_copper.h @@ -0,0 +1,46 @@ +// license:BSD-3-Clause +// copyright-holders:Andrei I. Holub +#ifndef MAME_SINCLAIR_TSCONF_COPPER_H +#define MAME_SINCLAIR_TSCONF_COPPER_H + +#pragma once + +class tsconf_copper_device : public device_t +{ + +public: + tsconf_copper_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + auto out_wreg_cb() { return m_out_wreg_cb.bind(); } + template void set_in_until_pos_cb(T &&... args) { return m_in_until_pos_cb.set(std::forward(args)...); } + + void copper_en_w(u8 data); + void cl_data_w(u16 addr, u8 data); + void dma_ready_w(int status); + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + TIMER_CALLBACK_MEMBER(timer_callback); + + emu_timer *m_timer; + +private: + memory_share_creator m_cl_data; + + devcb_write8 m_out_wreg_cb; + devcb_read_line m_in_dma_ready_cb; + device_delegate m_in_until_pos_cb; + + bool m_en; + u8 m_pc; + u8 m_ret_pc; + u8 m_a; + u16 m_b; // u9 +}; + + +DECLARE_DEVICE_TYPE(TSCONF_COPPER, tsconf_copper_device) + +#endif // MAME_SINCLAIR_TSCONF_COPPER_H diff --git a/src/mame/sinclair/tsconfdma.cpp b/src/mame/sinclair/tsconf_dma.cpp similarity index 99% rename from src/mame/sinclair/tsconfdma.cpp rename to src/mame/sinclair/tsconf_dma.cpp index fd95defc34c95..a3625f0d7e9df 100644 --- a/src/mame/sinclair/tsconfdma.cpp +++ b/src/mame/sinclair/tsconf_dma.cpp @@ -10,9 +10,9 @@ **********************************************************************/ #include "emu.h" -#include "tsconfdma.h" +#include "tsconf_dma.h" -#define VERBOSE ( LOG_GENERAL ) +//#define VERBOSE ( LOG_GENERAL ) #include "logmacro.h" enum diff --git a/src/mame/sinclair/tsconfdma.h b/src/mame/sinclair/tsconf_dma.h similarity index 94% rename from src/mame/sinclair/tsconfdma.h rename to src/mame/sinclair/tsconf_dma.h index 138b2a043e78f..15783c37c9cfa 100644 --- a/src/mame/sinclair/tsconfdma.h +++ b/src/mame/sinclair/tsconf_dma.h @@ -6,8 +6,8 @@ ***************************************************************************/ -#ifndef MAME_SINCLAIR_TSCONFDMA_H -#define MAME_SINCLAIR_TSCONFDMA_H +#ifndef MAME_SINCLAIR_TSCONF_DMA_H +#define MAME_SINCLAIR_TSCONF_DMA_H #pragma once @@ -74,4 +74,4 @@ class tsconfdma_device : public device_t }; DECLARE_DEVICE_TYPE(TSCONF_DMA, tsconfdma_device) -#endif // MAME_SINCLAIR_TSCONFDMA_H +#endif // MAME_SINCLAIR_TSCONF_DMA_H diff --git a/src/mame/sinclair/tsconf_m.cpp b/src/mame/sinclair/tsconf_m.cpp index 1d4a5fac35fbc..acd35d36e9922 100644 --- a/src/mame/sinclair/tsconf_m.cpp +++ b/src/mame/sinclair/tsconf_m.cpp @@ -359,6 +359,38 @@ void tsconf_state::draw_sprites(screen_device &screen_d, bitmap_rgb32 &bitmap, c } +attotime tsconf_state::copper_until_pos_r(u16 pos) +{ + const u8 mode = pos >> 14; + switch(mode) + { + case 0b11: // line + case 0b10: // x + { + const int vpos = m_screen->vpos(); + const int x = (mode == 0b11) ? screen_area[3].right() + 1 : ((pos & 0xff) << 1); + if (m_screen->hpos() < x) + return m_screen->time_until_pos(vpos, x); + else + return m_screen->time_until_pos((vpos + 1) % m_screen->height(), x); + } + break; + case 0b01: // y + { + const u8 y = pos & 0x1ff; + if (m_screen->vpos() == y) + return attotime::zero; + else + return m_screen->time_until_pos(y); + } + break; + case 0b00: // frame + default: + return m_screen->time_until_pos(0, 0); + break; + } +} + u8 tsconf_state::ram_bank_read(u8 bank, offs_t offset) { if (!machine().side_effects_disabled() && ((m_regs[SYS_CONFIG] & 3) == 2)) // 14Mhz @@ -384,18 +416,22 @@ void tsconf_state::ram_bank_write(u8 bank, offs_t offset, u8 data) { offs_t machine_addr = PAGE4K(bank) + offset; offs_t fmap_addr = BIT(m_regs[FMAPS], 0, 4) << 12; - if ((machine_addr >= fmap_addr) && (machine_addr < (fmap_addr + 256 * 5))) + if ((machine_addr >= fmap_addr) && (machine_addr < (fmap_addr + 0x800))) { u16 addr_w = machine_addr - fmap_addr; - if (addr_w < 512) + if (addr_w < 0x200) cram_write(addr_w, data); - else if (addr_w < 1024) + else if (addr_w < 0x400) { m_sprites_cache.clear(); - m_sfile->write(addr_w - 512, data); + m_sfile->write(addr_w - 0x200, data); } - else - tsconf_port_xxaf_w((addr_w - 1024) << 8, data); + else if (addr_w < 0x500) + tsconf_port_xxaf_w((addr_w - 0x400) << 8, data); + else if (addr_w < 0x600) + ; // reserved + else if (m_copper != nullptr) + m_copper->cl_data_w(addr_w - 0x600, data); } } @@ -473,6 +509,7 @@ u16 tsconf_state::spi_read16() void tsconf_state::cram_write(u16 offset, u8 data) { + m_screen->update_now(); u16 dest = offset & 0x1ff; m_cram->write(dest, data); u8 pen = dest >> 1; @@ -637,6 +674,11 @@ void tsconf_state::tsconf_port_xxaf_w(offs_t port, u8 data) case PAGE3: m_bank_ram[3]->set_entry(data); break; + + case COPPER: + if (m_copper != nullptr) + m_copper->copper_en_w(data); + break; case DMAS_ADDRESS_L: m_dma->set_saddr_l(data);