Added preliminary TS-Configuration for ZX Evolution driver. (#8989)

New machines marked as not working
-------------------------
NedoPC, TS-Labs ZX Evolution TS-Configuration
This commit is contained in:
holub 2021-12-24 14:58:14 -05:00 committed by GitHub
parent 6101c55c96
commit 1e32a43b50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1561 additions and 38 deletions

View File

@ -4881,3 +4881,25 @@ if (MACHINES["NS32082"]~=null) then
MAME_DIR .. "src/devices/machine/ns32082.h",
}
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

View File

@ -534,6 +534,7 @@ MACHINES["ER2055"] = true
MACHINES["EXORTERM"] = true
MACHINES["F3853"] = true
MACHINES["F4702"] = true
MACHINES["GLUKRS"] = true
MACHINES["GT913"] = true
MACHINES["HD63450"] = true
MACHINES["HD64610"] = true
@ -716,6 +717,7 @@ MACHINES["TMS9901"] = true
MACHINES["TMS9902"] = true
MACHINES["TMS9914"] = true
MACHINES["TPI6525"] = true
MACHINES["TSCONF_DMA"] = true
MACHINES["TTL7400"] = true
MACHINES["TTL7404"] = true
--MACHINES["TSB12LV01A"] = true
@ -3800,6 +3802,9 @@ files {
MAME_DIR .. "src/mame/video/zx8301.h",
MAME_DIR .. "src/mame/machine/zx8302.cpp",
MAME_DIR .. "src/mame/machine/zx8302.h",
MAME_DIR .. "src/mame/drivers/tsconf.cpp",
MAME_DIR .. "src/mame/includes/tsconf.h",
MAME_DIR .. "src/mame/machine/tsconf.cpp",
}
createMESSProjects(_target, _subtarget, "siemens")

View File

@ -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 = machine().scheduler().timer_alloc(timer_expired_delegate(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")

View File

@ -0,0 +1,35 @@
// 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<nvram_device> m_nvram;
emu_timer *m_timer;
};
DECLARE_DEVICE_TYPE(GLUKRS, glukrs_device)
#endif // MAME_MACHINE_GLUKRS_H

View File

@ -0,0 +1,195 @@
// 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)
{
}
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();
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
// 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;
}
// device type definition
DEFINE_DEVICE_TYPE(TSCONF_DMA, tsconfdma_device, "tsconfdma", "TS-Conf DMA Controller")

View File

@ -0,0 +1,58 @@
// 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(); }
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;
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

View File

@ -127,15 +127,15 @@ void atm_state::atm_mem(address_map &map)
void atm_state::atm_io(address_map &map)
{
map.unmap_value_high();
map(0x001f, 0x001f).rw(m_beta, FUNC(beta_disk_device::status_r), FUNC(beta_disk_device::command_w)).mirror(0xff00);
map(0x003f, 0x003f).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w)).mirror(0xff00);
map(0x005f, 0x005f).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)).mirror(0xff00);
map(0x007f, 0x007f).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)).mirror(0xff00);
map(0x00fe, 0x00fe).rw(FUNC(atm_state::spectrum_port_fe_r), FUNC(atm_state::spectrum_port_fe_w)).select(0xff00);
map(0x00ff, 0x00ff).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w)).mirror(0xff00);
map(0x4000, 0x4000).w(FUNC(atm_state::atm_port_7ffd_w)).mirror(0x3ffd);
map(0x8000, 0x8000).w("ay8912", FUNC(ay8910_device::data_w)).mirror(0x3ffd);
map(0xc000, 0xc000).rw("ay8912", FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_w)).mirror(0x3ffd);
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(0x00fe, 0x00fe).select(0xff00).rw(FUNC(atm_state::spectrum_port_fe_r), FUNC(atm_state::spectrum_port_fe_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(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));
}
void atm_state::atm_switch(address_map &map)

View File

@ -205,15 +205,15 @@ void pentagon_state::pentagon_mem(address_map &map)
void pentagon_state::pentagon_io(address_map &map)
{
map.unmap_value_high();
map(0x0000, 0x0000).w(FUNC(pentagon_state::pentagon_port_7ffd_w)).mirror(0x7ffd); // (A15 | A1) == 0
map(0x001f, 0x001f).rw(m_beta, FUNC(beta_disk_device::status_r), FUNC(beta_disk_device::command_w)).mirror(0xff00);
map(0x003f, 0x003f).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w)).mirror(0xff00);
map(0x005f, 0x005f).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)).mirror(0xff00);
map(0x007f, 0x007f).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)).mirror(0xff00);
map(0x00fe, 0x00fe).rw(FUNC(pentagon_state::spectrum_port_fe_r), FUNC(pentagon_state::spectrum_port_fe_w)).select(0xff00);
map(0x00ff, 0x00ff).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w)).mirror(0xff00);
map(0x8000, 0x8000).w("ay8912", FUNC(ay8910_device::data_w)).mirror(0x3ffd);
map(0xc000, 0xc000).rw("ay8912", FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_w)).mirror(0x3ffd);
map(0x0000, 0x0000).mirror(0x7ffd).w(FUNC(pentagon_state::pentagon_port_7ffd_w)); // (A15 | A1) == 0
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(0x00fe, 0x00fe).select(0xff00).rw(FUNC(pentagon_state::spectrum_port_fe_r), FUNC(pentagon_state::spectrum_port_fe_w));
map(0x00ff, 0x00ff).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_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));
}
void pentagon_state::pentagon_switch(address_map &map)

View File

@ -193,16 +193,16 @@ void scorpion_state::scorpion_mem(address_map &map)
void scorpion_state::scorpion_io(address_map &map)
{
map.unmap_value_high();
map(0x001f, 0x001f).rw(m_beta, FUNC(beta_disk_device::status_r), FUNC(beta_disk_device::command_w)).mirror(0xff00);
map(0x003f, 0x003f).rw(m_beta, FUNC(beta_disk_device::track_r), FUNC(beta_disk_device::track_w)).mirror(0xff00);
map(0x005f, 0x005f).rw(m_beta, FUNC(beta_disk_device::sector_r), FUNC(beta_disk_device::sector_w)).mirror(0xff00);
map(0x007f, 0x007f).rw(m_beta, FUNC(beta_disk_device::data_r), FUNC(beta_disk_device::data_w)).mirror(0xff00);
map(0x00fe, 0x00fe).rw(FUNC(scorpion_state::spectrum_port_fe_r), FUNC(scorpion_state::spectrum_port_fe_w)).select(0xff00);
map(0x00ff, 0x00ff).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w)).mirror(0xff00);
map(0x4021, 0x4021).w(FUNC(scorpion_state::scorpion_port_7ffd_w)).mirror(0x3fdc);
map(0x8021, 0x8021).w("ay8912", FUNC(ay8910_device::data_w)).mirror(0x3fdc);
map(0xc021, 0xc021).rw("ay8912", FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_w)).mirror(0x3fdc);
map(0x0021, 0x0021).w(FUNC(scorpion_state::scorpion_port_1ffd_w)).mirror(0x3fdc);
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(0x00fe, 0x00fe).select(0xff00).rw(FUNC(scorpion_state::spectrum_port_fe_r), FUNC(scorpion_state::spectrum_port_fe_w));
map(0x00ff, 0x00ff).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w));
map(0x4021, 0x4021).mirror(0x3fdc).w(FUNC(scorpion_state::scorpion_port_7ffd_w));
map(0x8021, 0x8021).mirror(0x3fdc).w("ay8912", FUNC(ay8910_device::data_w));
map(0xc021, 0xc021).mirror(0x3fdc).rw("ay8912", FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_w));
map(0x0021, 0x0021).mirror(0x3fdc).w(FUNC(scorpion_state::scorpion_port_1ffd_w));
}
void scorpion_state::scorpion_switch(address_map &map)

View File

@ -249,10 +249,10 @@ uint8_t spectrum_128_state::spectrum_128_ula_r()
void spectrum_128_state::spectrum_128_io(address_map &map)
{
map(0x0000, 0xffff).rw(m_exp, FUNC(spectrum_expansion_slot_device::iorq_r), FUNC(spectrum_expansion_slot_device::iorq_w));
map(0x0000, 0x0000).rw(FUNC(spectrum_128_state::spectrum_port_fe_r), FUNC(spectrum_128_state::spectrum_port_fe_w)).select(0xfffe);
map(0x0001, 0x0001).w(FUNC(spectrum_128_state::spectrum_128_port_7ffd_w)).select(0x7ffc); // (A15 | A1) == 0, note: reading from this port does write to it by value from data bus
map(0x8000, 0x8000).w("ay8912", FUNC(ay8910_device::data_w)).mirror(0x3ffd);
map(0xc000, 0xc000).rw("ay8912", FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_w)).mirror(0x3ffd);
map(0x0000, 0x0000).select(0xfffe).rw(FUNC(spectrum_128_state::spectrum_port_fe_r), FUNC(spectrum_128_state::spectrum_port_fe_w));
map(0x0001, 0x0001).select(0x7ffc).w(FUNC(spectrum_128_state::spectrum_128_port_7ffd_w)); // (A15 | A1) == 0, note: reading from this port does write to it by value from data bus
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));
map(0x0001, 0x0001).r(FUNC(spectrum_128_state::spectrum_128_ula_r)); // .mirror(0xfffe);
}

View File

@ -509,14 +509,14 @@ The function decodes the ports appropriately */
void spectrum_state::spectrum_io(address_map &map)
{
map(0x0000, 0xffff).w(m_exp, FUNC(spectrum_expansion_slot_device::iorq_w));
map(0x00, 0x00).rw(FUNC(spectrum_state::spectrum_port_fe_r), FUNC(spectrum_state::spectrum_port_fe_w)).select(0xfffe);
map(0x01, 0x01).r(FUNC(spectrum_state::spectrum_port_ula_r)).select(0xfffe);
map(0x00, 0x00).select(0xfffe).rw(FUNC(spectrum_state::spectrum_port_fe_r), FUNC(spectrum_state::spectrum_port_fe_w));
map(0x01, 0x01).select(0xfffe).r(FUNC(spectrum_state::spectrum_port_ula_r));
}
void spectrum_state::spectrum_clone_io(address_map &map)
{
map(0x0000, 0xffff).rw(m_exp, FUNC(spectrum_expansion_slot_device::iorq_r), FUNC(spectrum_expansion_slot_device::iorq_w));
map(0x00, 0x00).rw(FUNC(spectrum_state::spectrum_port_fe_r), FUNC(spectrum_state::spectrum_port_fe_w)).select(0xfffe);
map(0x00, 0x00).select(0xfffe).rw(FUNC(spectrum_state::spectrum_port_fe_r), FUNC(spectrum_state::spectrum_port_fe_w));
map(0x01, 0x01).r(FUNC(spectrum_state::spectrum_clone_port_ula_r)); // .mirror(0xfffe);
}

296
src/mame/drivers/tsconf.cpp Normal file
View File

@ -0,0 +1,296 @@
// license:BSD-3-Clause
// 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.
Features (TS-Configuration):
- Resolutions: 360x288, 320x240, 320x200, 256x192
- Hardware scrolled graphic planes
- 256 and 16 indexed colors per pixel
- Programmable color RAM with RGB555 color space and 256 cells
- Text mode with loadable font and hardware vertical scroll
- Up to 256 graphic screens
- Up to 85 sprites per line
- Sprites sized from 8x8 to 64x64 pixels
- Up to 3 sprite planes
- Up to 2 tile planes with 8x8 pixels tiles
- Up to 16 palettes for sprites per line
- Up to 4 palettes for tiles per line for each tile plane
- 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
$ chdman createhd -i wc.img -o wc.chd -c none
$ mame tsconf -hard wc.chd
# BIOS Setup loads on fresh setup (return to BIOS: RShift+F3)
# Change "Reset To: BD boot.$c"
# Reset (F3)
# Enable keyboard: MAME Setup (Tab) > Keyboard Mode > AT Keyboard: Enabled
TODO:
- Interrupts
- Sprites
- Sound
- ZX-Mode locks
- CPU frequency
- Timings
- Ram cache
- VDos
- Many more...
****************************************************************************/
#include "emu.h"
#include "includes/tsconf.h"
TILE_GET_INFO_MEMBER(tsconf_state::get_tile_info_txt)
{
u8 *m_row_location = &m_ram->pointer()[(m_regs[V_PAGE] << 14) + (tile_index / tilemap.cols() * 256)];
u8 col = tile_index % tilemap.cols();
u8 symbol = m_row_location[col];
tileinfo.set(1, symbol, 0, 0);
}
template <u8 Layer>
TILE_GET_INFO_MEMBER(tsconf_state::get_tile_info_16c)
{
u8 col_offset = (tile_index % tilemap.cols()) << 1;
u16 row_offset = (((tile_index / tilemap.cols()) << 1) + Layer) * 64 * 2;
u8 *tile_info_addr = &m_ram->pointer()[(m_regs[T_MAP_PAGE] << 14) + row_offset + col_offset];
u8 hi = tile_info_addr[1];
u16 tile = ((u16(hi) & 0x0f) << 8) | tile_info_addr[0];
tile = tile / tilemap.cols() * 64 * 8 + (tile % tilemap.cols());
u8 pal = (BIT(m_regs[PAL_SEL], 4 + Layer * 2, 2) << 2) | BIT(hi, 4, 2);
if (BIT(hi, 6, 2))
{
logerror("FIXME - FLIP Case\n");
}
tileinfo.set(2 + Layer, tile, pal, 0);
}
TILE_GET_INFO_MEMBER(tsconf_state::get_sprite_info_16c)
{
tileinfo.set(4, tile_index, 0, 0);
}
void tsconf_state::tsconf_mem(address_map &map)
{
map(0x0000, 0x3fff).bankr("bank1").w(FUNC(tsconf_state::tsconf_bank_w<0>));
map(0x4000, 0x7fff).bankr("bank2").w(FUNC(tsconf_state::tsconf_bank_w<1>));
map(0x8000, 0xbfff).bankr("bank3").w(FUNC(tsconf_state::tsconf_bank_w<2>));
map(0xc000, 0xffff).bankr("bank4").w(FUNC(tsconf_state::tsconf_bank_w<3>));
}
void tsconf_state::tsconf_io(address_map &map)
{
map.unmap_value_high();
map(0x0000, 0x0000).mirror(0x7ffd).w(FUNC(tsconf_state::tsconf_port_7ffd_w));
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(0x0057, 0x0057).mirror(0xff00).rw(FUNC(tsconf_state::tsconf_port_57_zctr_r), FUNC(tsconf_state::tsconf_port_57_zctr_w)); // spi config
map(0x0077, 0x0077).mirror(0xff00).rw(FUNC(tsconf_state::tsconf_port_77_zctr_r), FUNC(tsconf_state::tsconf_port_77_zctr_w)); // spi data
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(tsconf_state::spectrum_port_fe_r), FUNC(tsconf_state::tsconf_port_fe_w));
map(0x00ff, 0x00ff).mirror(0xff00).rw(m_beta, FUNC(beta_disk_device::state_r), FUNC(beta_disk_device::param_w));
map(0x00af, 0x00af).select(0xff00).rw(FUNC(tsconf_state::tsconf_port_xxaf_r), FUNC(tsconf_state::tsconf_port_xxaf_w));
map(0x8ff7, 0x8ff7).select(0x7000).w(FUNC(tsconf_state::tsconf_port_f7_w)); // 3:bff7 5:dff7 6:eff7
map(0xbff7, 0xbff7).r(FUNC(tsconf_state::tsconf_port_f7_r));
}
void tsconf_state::tsconf_switch(address_map &map)
{
map(0x0000, 0x3fff).r(FUNC(tsconf_state::beta_neutral_r)); // Overlap with next because we want real addresses on the 3e00-3fff range
map(0x3d00, 0x3dff).r(FUNC(tsconf_state::beta_enable_r));
map(0x4000, 0xffff).r(FUNC(tsconf_state::beta_disable_r));
}
template <unsigned Bank>
void tsconf_state::tsconf_bank_w(offs_t offset, u8 data)
{
tsconf_state::ram_bank_write(Bank, offset, data);
}
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 */
{STEP8(0, 1)},
/* y offsets */
{STEP8(0, 8)},
8 * 8 /* every char takes 8 bytes */
};
static const gfx_layout tsconf_charlayout =
{
8,
8,
256,
1,
{0},
{STEP8(0, 1)},
{STEP8(0, 8)},
8 * 8
};
static const gfx_layout tsconf_tile_16cpp_layout =
{
8,
8,
64 * 64 * 8,
4,
{STEP4(0, 1)},
{STEP8(0, 4)},
{STEP8(0, 256 * 8)},
// Much more tiles when needed. Because tiles are in RAW formut but we don't know region properties.
8 * 4
};
static GFXDECODE_START(gfx_tsconf)
GFXDECODE_ENTRY("maincpu", 0x1fd00, spectrum_charlayout, 0xf7, 1)
GFXDECODE_ENTRY("maincpu", 0, tsconf_charlayout, 0xf7, 1) // TXT
GFXDECODE_ENTRY("maincpu", 0, tsconf_tile_16cpp_layout, 0, 255) // T0 16cpp
GFXDECODE_ENTRY("maincpu", 0, tsconf_tile_16cpp_layout, 0, 255) // T1 16cpp
GFXDECODE_ENTRY("maincpu", 0, tsconf_tile_16cpp_layout, 0, 255) // Sprites 16cpp
GFXDECODE_END
void tsconf_state::video_start()
{
spectrum_128_state::video_start();
m_ts_tilemap[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tsconf_state::get_tile_info_txt)), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
m_ts_tilemap[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tsconf_state::get_tile_info_16c<0>)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
m_ts_tilemap[1]->set_transparent_pen(0);
m_ts_tilemap[2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tsconf_state::get_tile_info_16c<1>)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
m_ts_tilemap[2]->set_transparent_pen(0);
m_ts_tilemap[3] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(tsconf_state::get_sprite_info_16c)), TILEMAP_SCAN_ROWS, 8, 8, 64, 64);
m_ts_tilemap[3]->set_transparent_pen(0);
}
void tsconf_state::machine_start()
{
save_item(NAME(m_regs));
// TODO save'm'all!
}
void tsconf_state::machine_reset()
{
u8 *messram = m_ram->pointer();
m_program = &m_maincpu->space(AS_PROGRAM);
m_ram_0000 = nullptr;
m_port_f7_ext = DISABLED;
m_regs[V_CONFIG] = 0x00;
m_regs[V_PAGE] = 0x05;
m_regs[G_X_OFFS_L] = 0x00;
m_regs[G_X_OFFS_H] &= 0xfe; // xxxxxxx0
m_regs[G_Y_OFFS_L] = 0x00;
m_regs[G_Y_OFFS_H] &= 0xfe; // xxxxxxx0
m_regs[TS_CONFIG] &= 0x03; // 000000xx
m_regs[PAL_SEL] = 0x0f;
m_regs[PAGE0] = 0x00;
m_regs[PAGE1] = 0x05;
m_regs[PAGE2] = 0x02;
m_regs[PAGE3] = 0x00;
m_regs[FMAPS] &= 0xef; // xxx0xxxx
m_regs[SYS_CONFIG] = 0x00;
m_regs[MEM_CONFIG] = 0x04;
m_regs[HS_INT] = 0x01; // 00000001
m_regs[VS_INT_L] = 0x00; // 00000001
m_regs[VS_INT_H] = 0x00; // 0000xxx0
// FDDVirt = 0x00; // 0000xxx0
m_regs[INT_MASK] = 0x01; // xxxxx001
// CacheConfig = 0x01; // xxxxx001
if (m_beta->started())
m_beta->enable();
memset(messram, 0, 4096 * 1024);
m_port_7ffd_data = 0;
m_zctl_cs = 1;
m_zctl_di = 0xff;
tsconf_update_bank1();
m_keyboard->write(0xff);
while (m_keyboard->read() != 0) { /* invalidate buffer */ }
}
void tsconf_state::tsconf(machine_config &config)
{
spectrum_128(config);
config.device_remove("exp");
config.device_remove("palette");
//m_maincpu->set_clock(XTAL(14'000'000));
m_maincpu->set_addrmap(AS_PROGRAM, &tsconf_state::tsconf_mem);
m_maincpu->set_addrmap(AS_IO, &tsconf_state::tsconf_io);
m_maincpu->set_addrmap(AS_OPCODES, &tsconf_state::tsconf_switch);
m_ram->set_default_size("4096K");
GLUKRS(config, m_glukrs);
TSCONF_DMA(config, m_dma, XTAL(14'000'000) / 2);
m_dma->in_mreq_callback().set(FUNC(tsconf_state::ram_read16));
m_dma->out_mreq_callback().set(FUNC(tsconf_state::ram_write16));
m_dma->in_spireq_callback().set(FUNC(tsconf_state::spi_read16));
m_dma->out_cram_callback().set(FUNC(tsconf_state::cram_write16));
BETA_DISK(config, m_beta, 0);
SPI_SDCARD(config, m_sdcard, 0);
m_sdcard->spi_miso_callback().set(FUNC(tsconf_state::tsconf_spi_miso_w));
PALETTE(config, "palette", FUNC(tsconf_state::tsconf_palette), 256);
m_screen->set_raw(X1_128_SINCLAIR / 2.5, 448, 0, 360, 320, 0, 288);
subdevice<gfxdecode_device>("gfxdecode")->set_info(gfx_tsconf);
RAM(config, m_cram).set_default_size("512").set_default_value(0);
AT_KEYB(config, m_keyboard, pc_keyboard_device::KEYBOARD_TYPE::AT, 3);
}
ROM_START(tsconf)
ROM_REGION(0x090000, "maincpu", ROMREGION_ERASEFF) // 16KB ROM
ROM_LOAD("ts-bios.rom", 0x010000, 0x10000, CRC(b060b0d9) SHA1(820d3539de115141daff220a3cb733fc880d1bab))
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", MACHINE_NO_SOUND | MACHINE_WRONG_COLORS | MACHINE_IMPERFECT_TIMING )

View File

@ -159,7 +159,7 @@ protected:
uint8_t spectrum_clone_port_ula_r();
void spectrum_palette(palette_device &palette) const;
uint32_t screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
virtual uint32_t screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(screen_vblank_spectrum);
INTERRUPT_GEN_MEMBER(spec_interrupt);
@ -210,7 +210,8 @@ protected:
optional_ioport m_io_joy2;
void spectrum_UpdateBorderBitmap();
void spectrum_UpdateScreenBitmap(bool eof = false);
virtual u16 get_border_color();
virtual void spectrum_UpdateScreenBitmap(bool eof = false);
inline unsigned char get_display_color(unsigned char color, int invert);
inline void spectrum_plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color);

191
src/mame/includes/tsconf.h Normal file
View File

@ -0,0 +1,191 @@
// license:BSD-3-Clause
// copyright-holders:Andrei I. Holub
/*****************************************************************************
*
* includes/tsconfig.h
*
****************************************************************************/
#ifndef MAME_INCLUDES_TSCONF_H
#define MAME_INCLUDES_TSCONF_H
#pragma once
#include "machine/beta.h"
#include "machine/glukrs.h"
#include "machine/pckeybrd.h"
#include "machine/spi_sdcard.h"
#include "machine/tsconfdma.h"
#include "spectrum.h"
#include "tilemap.h"
class tsconf_state : public spectrum_128_state
{
public:
tsconf_state(const machine_config &mconfig, device_type type, const char *tag)
: spectrum_128_state(mconfig, type, tag),
m_p_rom(*this, "maincpu"),
m_bank1(*this, "bank1"), m_bank2(*this, "bank2"), m_bank3(*this, "bank3"), m_bank4(*this, "bank4"),
m_keyboard(*this, "pc_keyboard"),
m_beta(*this, BETA_DISK_TAG),
m_dma(*this, "dma"),
m_sdcard(*this, "sdcard"),
m_glukrs(*this, "glukrs"),
m_palette(*this, "palette"),
m_gfxdecode(*this, "gfxdecode"),
m_cram(*this, "cram")
{
}
void tsconf(machine_config &config);
protected:
virtual void video_start() override;
virtual void machine_start() override;
virtual void machine_reset() override;
private:
enum gluk_ext : u8
{
CONF_VERSION = 0x00,
BOOTLOADER_VERSION = 0x01,
PS2KEYBOARDS_LOG = 0x02,
RDCFG = 0x03,
CONFIG = 0x0e,
SPIFL = 0x10,
DISABLED = 0xff
};
enum tsconf_regs : u8
{
V_CONFIG = 0x00,
V_PAGE = 0x01,
G_X_OFFS_L = 0x02,
G_X_OFFS_H = 0x03,
G_Y_OFFS_L = 0x04,
G_Y_OFFS_H = 0x05,
TS_CONFIG = 0x06,
PAL_SEL = 0x07,
BORDER = 0x0f,
PAGE0 = 0x10,
PAGE1 = 0x11,
PAGE2 = 0x12,
PAGE3 = 0x13,
FMAPS = 0x15,
T_MAP_PAGE = 0x16,
T0_G_PAGE = 0x17,
T1_G_PAGE = 0x18,
SG_PAGE = 0x19,
DMAS_ADDRESS_L = 0x1a,
DMAS_ADDRESS_H = 0x1b,
DMAS_ADDRESS_X = 0x1c,
DMAD_ADDRESS_L = 0x1d,
DMAD_ADDRESS_H = 0x1e,
DMAD_ADDRESS_X = 0x1f,
SYS_CONFIG = 0x20,
MEM_CONFIG = 0x21,
HS_INT = 0x22,
VS_INT_L = 0x23,
VS_INT_H = 0x24,
DMA_WAIT_PORT_DEV = 0x25,
DMA_LEN = 0x26,
DMA_CTRL = 0x27,
DMA_NUM_L = 0x28,
INT_MASK = 0x2a,
DMA_NUM_H = 0x2c,
T0_X_OFFSER_L = 0x40,
T0_X_OFFSER_H = 0x41,
T0_Y_OFFSER_L = 0x42,
T0_Y_OFFSER_H = 0x43,
T1_X_OFFSER_L = 0x44,
T1_X_OFFSER_H = 0x45,
T1_Y_OFFSER_L = 0x46,
T1_Y_OFFSER_H = 0x47
};
DECLARE_VIDEO_START(tsconf);
TILE_GET_INFO_MEMBER(get_tile_info_txt);
template <u8 Layer>
TILE_GET_INFO_MEMBER(get_tile_info_16c);
TILE_GET_INFO_MEMBER(get_sprite_info_16c);
// Changing this consider to revert 'virtual' in spectrum.h
u32 screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override;
void spectrum_UpdateScreenBitmap(bool eof = false) override;
void tsconf_palette(palette_device &palette) const;
u16 get_border_color() override;
void draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void tsconf_update_video_mode();
rectangle get_resolution_info();
void tsconf_port_7ffd_w(u8 data);
void tsconf_port_fe_w(offs_t offset, u8 data);
u8 tsconf_port_xxaf_r(offs_t reg);
void tsconf_port_xxaf_w(offs_t reg, u8 data);
u8 tsconf_port_77_zctr_r(offs_t reg);
void tsconf_port_77_zctr_w(offs_t reg, u8 data);
u8 tsconf_port_57_zctr_r(offs_t reg);
void tsconf_port_57_zctr_w(offs_t reg, u8 data);
void tsconf_spi_miso_w(u8 data);
u8 tsconf_port_f7_r(offs_t offset);
void tsconf_port_f7_w(offs_t offset, u8 data);
void tsconf_update_bank1();
u8 beta_neutral_r(offs_t offset);
u8 beta_enable_r(offs_t offset);
u8 beta_disable_r(offs_t offset);
void tsconf_io(address_map &map);
void tsconf_mem(address_map &map);
void tsconf_switch(address_map &map);
template <unsigned Bank>
void tsconf_bank_w(offs_t offset, u8 data);
void ram_bank_write(u8 bank, offs_t offset, u8 data);
void ram_page_write(u8 page, offs_t offset, u8 data);
void cram_write(u16 offset, u8 data);
void cram_write16(offs_t offset, u16 data);
void ram_write16(offs_t offset, u16 data);
u16 ram_read16(offs_t offset);
u16 spi_read16();
u8 m_regs[0x100];
address_space *m_program;
required_region_ptr<u8> m_p_rom;
required_memory_bank m_bank1;
required_memory_bank m_bank2;
required_memory_bank m_bank3;
required_memory_bank m_bank4;
required_device<at_keyboard_device> m_keyboard;
required_device<beta_disk_device> m_beta;
required_device<tsconfdma_device> m_dma;
required_device<spi_sdcard_sdhc_device> m_sdcard;
u8 m_zctl_di;
u8 m_zctl_cs;
required_device<glukrs_device> m_glukrs;
gluk_ext m_port_f7_ext;
u8 m_port_f7_gluk_reg;
optional_device<device_palette_interface> m_palette;
required_device<gfxdecode_device> m_gfxdecode;
tilemap_t *m_ts_tilemap[4];
required_device<ram_device> m_cram;
};
/*----------- defined in drivers/tsconf.c -----------*/
INPUT_PORTS_EXTERN(tsconf);
#endif // MAME_INCLUDES_TSCONF_H

653
src/mame/machine/tsconf.cpp Normal file
View File

@ -0,0 +1,653 @@
// license:BSD-3-Clause
// copyright-holders:Andrei I. Holub
#include "emu.h"
#include "includes/tsconf.h"
#define PAGE4K(_r) ((_r) << 14)
#define W0_RAM (BIT(m_regs[MEM_CONFIG], 3))
#define NW0_MAP (BIT(m_regs[MEM_CONFIG], 2))
#define W0_WE (BIT(m_regs[MEM_CONFIG], 1))
#define ROM128 (BIT(m_regs[MEM_CONFIG], 0))
#define VM static_cast<v_mode>(BIT(m_regs[V_CONFIG], 0, 2))
static constexpr rectangle resolution_info[4] = {
rectangle(52, 256 + 51, 48, 192 + 47), // 52|256|52 x 48-192-48
rectangle(20, 320 + 19, 44, 200 + 43), // 20|320|20 x 44-200-44
rectangle(20, 320 + 19, 24, 240 + 23), // 20|320|20 x 24-240-24
rectangle(0, 360 - 1, 0, 288 - 1) // 0|360|0 x 0-288-0
};
enum v_mode : u8
{
VM_ZX = 0,
VM_16C,
VM_256C,
VM_TXT
};
// https://github.com/tslabs/zx-evo/blob/master/pentevo/vdac/vdac1/cpld/top.v
static constexpr u8 pwm_to_rgb[32] = {
0, 10, 21, 31, 42, 53, 63, 74,
85, 95, 106, 117, 127, 138, 149, 159,
170, 181, 191, 202, 213, 223, 234, 245,
255, 255, 255, 255, 255, 255, 255, 255};
static constexpr rgb_t from_pwm(u16 pwm15)
{
return rgb_t(pwm_to_rgb[BIT(pwm15, 10, 5)], pwm_to_rgb[BIT(pwm15, 5, 5)], pwm_to_rgb[BIT(pwm15, 0, 5)]);
}
rectangle tsconf_state::get_resolution_info()
{
rectangle info = resolution_info[BIT(m_regs[V_CONFIG], 6, 2)];
if (VM == VM_TXT)
{
info.set_origin(0, 0);
info.set_width(info.width() << 1);
}
return info;
}
void tsconf_state::tsconf_palette(palette_device &palette) const
{
rgb_t colors[256] = {0};
palette.set_pen_colors(0, colors);
}
void tsconf_state::tsconf_update_bank1()
{
//W0_WE
if (NW0_MAP)
{
m_ROMSelection = m_regs[PAGE0];
}
else
{
/* ROM: 0-SYS, 1-DOS, 2-128, 3-48 */
m_ROMSelection = m_beta->started() && m_beta->is_active() ? ROM128 : (0x02 | ROM128);
m_ROMSelection |= (m_regs[PAGE0] & 0xfc);
}
uint8_t *rom0;
if (W0_RAM)
{
rom0 = m_ram->pointer() + PAGE4K(m_ROMSelection);
m_bank1->set_base(rom0);
}
else
{
rom0 = &m_p_rom[0x10000 + PAGE4K(m_ROMSelection & 0x1f)];
m_bank1->set_base(rom0);
}
m_ram_0000 = W0_WE ? rom0 : nullptr;
}
void tsconf_state::tsconf_update_video_mode()
{
rectangle resolution = resolution_info[3];
u8 *messram = m_ram->pointer();
switch (VM)
{
case VM_TXT: // Text Mode
resolution = get_resolution_info();
m_gfxdecode->gfx(1)->set_source(messram + PAGE4K(m_regs[V_PAGE] ^ 0x01));
break;
case VM_ZX: // Zx
{
m_screen_location = messram + ((m_port_7ffd_data & 8) ? PAGE4K(7) : PAGE4K(5));
break;
}
default:
break;
}
m_screen->configure(resolution.width(), resolution.height(), resolution, HZ_TO_ATTOSECONDS(50));
}
uint32_t tsconf_state::screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
if (m_screen_bitmap.valid())
{
// Border
if (m_border_bitmap.valid())
{
if (BIT(m_regs[V_CONFIG], 5) || VM != VM_ZX)
{
copyscrollbitmap(bitmap, m_border_bitmap, 0, nullptr, 0, nullptr, cliprect);
}
}
// Main Graphics
rectangle resolution = get_resolution_info();
if (!BIT(m_regs[V_CONFIG], 5))
{
if (VM == VM_ZX)
{
// Zx palette is stored at 0xf0. Adjust bitmaps colors.
for (auto y = cliprect.top(); y <= cliprect.bottom(); y++)
{
u16 *bm = &m_screen_bitmap.pix(y, 0);
for (auto x = cliprect.left(); x <= cliprect.right(); x++)
{
*bm++ |= 0xf0;
}
}
spectrum_state::screen_update_spectrum(screen, bitmap, cliprect);
}
else
{
copyscrollbitmap(bitmap, m_screen_bitmap, 0, nullptr, 0, nullptr, resolution);
}
}
// Tiles & Sprites
// TODO layers
if (!BIT(m_regs[V_CONFIG], 4))
{
if (BIT(m_regs[TS_CONFIG], 5))
{
m_ts_tilemap[1]->draw(screen, bitmap, resolution, 0);
}
if (BIT(m_regs[TS_CONFIG], 6))
{
m_ts_tilemap[2]->draw(screen, bitmap, resolution, 0);
}
if (BIT(m_regs[TS_CONFIG], 7))
{
draw_sprites(screen, bitmap, resolution);
}
}
}
return 0;
}
void tsconf_state::spectrum_UpdateScreenBitmap(bool eof)
{
if (!BIT(m_regs[V_CONFIG], 5))
{
if (VM == VM_ZX)
{
spectrum_state::spectrum_UpdateScreenBitmap(eof);
}
else if (!eof)
{
u8 pal_offset = m_regs[PAL_SEL] << 4;
rectangle resolution = get_resolution_info();
if (VM == VM_TXT)
{
u8 *messram = m_ram->pointer();
u16 y = m_screen->vpos();
u8 *font_location = messram + PAGE4K(m_regs[V_PAGE] ^ 0x01);
u8 *text_location = messram + PAGE4K(m_regs[V_PAGE]) + (y / 8 * 256); // OFFSETs
u16 *bm = &m_screen_bitmap.pix(y, 0);
for (auto x = 0; x < resolution.width() / 8; x++)
{
u8 char_x = *(font_location + (*text_location * 8) + (y % 8));
u8 font_color = *(text_location + 128) & 0x0f;
u8 bg_color = (*(text_location + 128) & 0xf0) >> 4;
for (auto i = 7; i >= 0; i--)
{
*bm++ = (BIT(char_x, i) ? font_color : bg_color) + pal_offset;
}
text_location++;
}
}
else
{
if (m_screen->vpos() >= resolution.top())
{
u16 y = m_screen->vpos() - resolution.top();
u32 offset = ((y + ((m_regs[G_Y_OFFS_H] & 1) << 8) + m_regs[G_Y_OFFS_L]) * 512) +
((m_regs[G_X_OFFS_H] & 1) << 8) + m_regs[G_X_OFFS_L];
if (VM == VM_16C)
{
// FIXME wouldn't work for odd offsets
offset >>= 1;
}
u8 *video_location = &m_ram->pointer()[PAGE4K(m_regs[V_PAGE]) + offset];
u16 *bm = &m_screen_bitmap.pix(m_screen->vpos(), resolution.left());
for (auto x = resolution.left(); x <= resolution.right(); x++)
{
u8 pix = *video_location;
if (VM == VM_16C)
{
*bm++ = (pix >> 4) + pal_offset;
*bm++ = (pix & 0x0f) + pal_offset;
x++;
}
else
{
*bm++ = pix;
}
video_location++;
}
}
}
}
}
}
u16 tsconf_state::get_border_color()
{
return m_regs[BORDER];
}
void tsconf_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
//u8 *messram = m_ram->pointer();
//u8 *sprites_location = messram + PAGE4K(m_regs[SG_PAGE]);
for (u8 i = 0; i < 85; i++)
{
logerror("Draw Sprites ... TODO\n");
}
}
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 (BIT(m_regs[FMAPS], 4) && (machine_addr >= fmap_addr) && (machine_addr < (fmap_addr + 512)))
{
cram_write(machine_addr - fmap_addr, data);
}
else if (bank > 0 || (W0_WE && W0_RAM))
{
ram_page_write(m_regs[PAGE0 + bank], offset, data);
}
}
void tsconf_state::ram_page_write(u8 page, offs_t offset, u8 data)
{
u32 ram_addr = PAGE4K(page) + offset;
if (ram_addr >= PAGE4K(m_regs[T_MAP_PAGE]) && ram_addr < (PAGE4K(m_regs[T_MAP_PAGE] + 1)))
{
//TODO invalidate sprites, not entire map
m_ts_tilemap[1]->mark_all_dirty();
m_ts_tilemap[2]->mark_all_dirty();
}
else
{
if (ram_addr >= PAGE4K(m_regs[T0_G_PAGE]) && ram_addr < PAGE4K(m_regs[T0_G_PAGE] + 8))
{
m_ts_tilemap[1]->mark_all_dirty();
}
if (ram_addr >= PAGE4K(m_regs[T1_G_PAGE]) && ram_addr < PAGE4K(m_regs[T1_G_PAGE] + 8))
{
m_ts_tilemap[2]->mark_all_dirty();
}
if (ram_addr >= PAGE4K(m_regs[SG_PAGE]) && ram_addr < PAGE4K(m_regs[SG_PAGE] + 8))
{
m_ts_tilemap[3]->mark_all_dirty();
}
}
m_ram->write(ram_addr, data);
}
u16 tsconf_state::ram_read16(offs_t offset)
{
return ((m_ram->read(offset & 0xfffffffe)) << 8) | m_ram->read(offset | 1);
}
void tsconf_state::ram_write16(offs_t offset, u16 data)
{
m_ram->write(offset & 0xfffffffe, data >> 8);
m_ram->write(offset | 1, data & 0xff);
}
u16 tsconf_state::spi_read16()
{
return (tsconf_port_57_zctr_r(0) << 8) | tsconf_port_57_zctr_r(0);
}
void tsconf_state::cram_write(u16 offset, u8 data)
{
m_cram->write(offset, data);
u8 pen = offset >> 1;
rgb_t rgb = from_pwm((m_cram->read(offset | 1) << 8 | m_cram->read(offset & 0xfffe)));
m_palette->set_pen_color(pen, rgb);
};
void tsconf_state::cram_write16(offs_t offset, u16 data)
{
cram_write(offset & 0xfffe, data >> 8);
cram_write(offset | 1, data & 0xff);
};
void tsconf_state::tsconf_port_7ffd_w(u8 data)
{
/* disable paging */
if (m_port_7ffd_data & 0x20)
return;
/* store new state */
m_port_7ffd_data = data;
m_regs[MEM_CONFIG] = (m_regs[MEM_CONFIG] & 0xfe) | BIT(data, 4); // ROM128
m_regs[V_PAGE] = BIT(data, 3) ? 7 : 5;
/* update memory */
tsconf_update_bank1();
tsconf_update_video_mode();
}
void tsconf_state::tsconf_port_fe_w(offs_t offset, u8 data)
{
m_regs[BORDER] = (data & 0x07) | 0xf0;
spectrum_port_fe_w(offset, data);
}
u8 tsconf_state::tsconf_port_xxaf_r(offs_t port)
{
u8 nreg = port >> 8;
u8 data = 0xff;
switch (nreg)
{
case V_CONFIG:
data = 0b01000011; // PWR_UP, !FDRVER, 5bit VDAC
break;
case PAGE2:
case PAGE3:
data = m_regs[nreg];
break;
case DMA_CTRL: // DMAStatus
data = m_dma->is_ready() ? 0x00 : 0x80;
break;
case 0x30: // FRCnt0
case 0x31: // FRCnt1
case 0x32: // FRCnt2
default:
logerror("'tsconf': unmapped reg read %02X\n", nreg);
break;
}
//LOGWARN("'tsconf': reg read %02X = %02x\n", nreg, data);
return data;
}
void tsconf_state::tsconf_port_xxaf_w(offs_t port, u8 data)
{
u8 nreg = port >> 8;
m_regs[nreg] = data;
switch (nreg)
{
case V_CONFIG:
case V_PAGE:
case PAL_SEL:
tsconf_update_video_mode();
break;
case T_MAP_PAGE:
m_ts_tilemap[1]->mark_all_dirty();
m_ts_tilemap[2]->mark_all_dirty();
break;
case T0_G_PAGE:
m_gfxdecode->gfx(2)->set_source(m_ram->pointer() + PAGE4K(data));
m_ts_tilemap[1]->mark_all_dirty();
break;
case T0_X_OFFSER_L:
case T0_X_OFFSER_H:
case T0_Y_OFFSER_L:
case T0_Y_OFFSER_H:
m_ts_tilemap[1]->set_scrollx((m_regs[T0_X_OFFSER_H] << 8) | m_regs[T0_X_OFFSER_L]);
m_ts_tilemap[1]->set_scrolly((m_regs[T0_Y_OFFSER_H] << 8) | m_regs[T0_Y_OFFSER_L]);
break;
case T1_G_PAGE:
m_gfxdecode->gfx(3)->set_source(m_ram->pointer() + PAGE4K(data));
m_ts_tilemap[2]->mark_all_dirty();
break;
case T1_X_OFFSER_L:
case T1_X_OFFSER_H:
case T1_Y_OFFSER_L:
case T1_Y_OFFSER_H:
m_ts_tilemap[2]->set_scrollx((m_regs[T1_X_OFFSER_H] << 8) | m_regs[T1_X_OFFSER_L]);
m_ts_tilemap[2]->set_scrolly((m_regs[T1_Y_OFFSER_H] << 8) | m_regs[T1_Y_OFFSER_L]);
break;
case SG_PAGE:
m_gfxdecode->gfx(4)->set_source(m_ram->pointer() + PAGE4K(data));
m_ts_tilemap[3]->mark_all_dirty();
break;
case MEM_CONFIG:
m_port_7ffd_data = (m_port_7ffd_data & 0xef) | (ROM128 << 4);
tsconf_update_bank1();
break;
case PAGE0:
tsconf_update_bank1();
break;
case PAGE1:
m_bank2->set_base(m_ram->pointer() + PAGE4K(data));
break;
case PAGE2:
m_bank3->set_base(m_ram->pointer() + PAGE4K(data));
break;
case PAGE3:
m_bank4->set_base(m_ram->pointer() + PAGE4K(data));
break;
case BORDER:
spectrum_UpdateBorderBitmap();
break;
case DMAS_ADDRESS_L:
m_dma->set_saddr_l(data);
break;
case DMAS_ADDRESS_H:
m_dma->set_saddr_h(data);
break;
case DMAS_ADDRESS_X:
m_dma->set_saddr_x(data);
break;
case DMAD_ADDRESS_L:
m_dma->set_daddr_l(data);
break;
case DMAD_ADDRESS_H:
m_dma->set_daddr_h(data);
break;
case DMAD_ADDRESS_X:
m_dma->set_daddr_x(data);
break;
case DMA_LEN:
m_dma->set_block_len(data);
break;
case DMA_NUM_L:
m_dma->set_block_num_l(data);
break;
case DMA_NUM_H:
m_dma->set_block_num_h(data);
break;
case DMA_CTRL:
m_dma->start_tx(((BIT(data, 7) << 3) | (data & 0x07)), BIT(data, 5), BIT(data, 4), BIT(data, 3));
break;
case SYS_CONFIG:
// 0 - 3.5MHz, 1 - 7MHz, 2 - 14MHz, 3 - reserved
switch (data & 0x03)
{
case 2:
m_maincpu->set_clock(X1);
break;
case 1:
m_maincpu->set_clock(X1 / 2);
break;
case 0:
default:
m_maincpu->set_clock(X1 / 4);
break;
}
break;
case FMAPS:
case TS_CONFIG:
case G_X_OFFS_L:
case G_X_OFFS_H:
case G_Y_OFFS_L:
case G_Y_OFFS_H:
case HS_INT:
case VS_INT_L:
case VS_INT_H:
case INT_MASK:
break;
default:
logerror("Unsupported reg write: %02X = %02x\n", nreg, data);
break;
}
}
u8 tsconf_state::tsconf_port_f7_r(offs_t offset)
{
// BFF7
u8 data = 0xff;
if (m_port_f7_ext == PS2KEYBOARDS_LOG && m_port_f7_gluk_reg == 0xf0)
{
data = m_keyboard->read();
}
else if (m_port_f7_ext != DISABLED)
{
data = m_glukrs->read(m_port_f7_gluk_reg);
}
return data;
}
void tsconf_state::tsconf_port_f7_w(offs_t offset, u8 data)
{
auto m_l = offset >> 12;
if (m_l == 6) // EF
{
m_port_f7_ext = (data & 0x80) ? CONF_VERSION : DISABLED;
}
else if (m_port_f7_ext != DISABLED)
{
if (m_l == 5) // DF
{
// 0x0E..0xEF
m_port_f7_gluk_reg = data;
}
else if (m_l == 3) // BF
{
if (m_port_f7_gluk_reg == 0xf0)
{
u8 m_fx[0xf] = {0xff};
m_port_f7_ext = static_cast<gluk_ext>(data);
switch (m_port_f7_ext)
{
case CONF_VERSION:
{
strcpy((char *)m_fx, "M.A.M.E.");
PAIR16 m_ver;
m_ver.w = ((21 << 9) | (12 << 5) | 15);
m_fx[0x0c] = m_ver.b.l;
m_fx[0x0d] = m_ver.b.h;
break;
}
case BOOTLOADER_VERSION:
case PS2KEYBOARDS_LOG:
break;
default:
logerror("Gluk extention not supported %x\n", m_port_f7_gluk_reg);
break;
}
for (u8 i = 0; i < 0xf; i++)
{
m_glukrs->write(0xf0 + i, m_fx[i]);
}
}
else
{
m_glukrs->write(m_port_f7_gluk_reg, data);
}
}
}
}
void tsconf_state::tsconf_port_77_zctr_w(offs_t port, u8 data)
{
m_sdcard->spi_ss_w(BIT(data, 0));
m_zctl_cs = BIT(data, 1);
}
u8 tsconf_state::tsconf_port_77_zctr_r(offs_t port)
{
return 0x02 | !m_sdcard->get_card_present();
}
void tsconf_state::tsconf_port_57_zctr_w(offs_t port, 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
}
}
}
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;
}
void tsconf_state::tsconf_spi_miso_w(u8 data)
{
m_zctl_di <<= 1;
m_zctl_di |= data;
}
u8 tsconf_state::beta_neutral_r(offs_t offset)
{
return m_program->read_byte(offset);
}
u8 tsconf_state::beta_enable_r(offs_t offset)
{
if (m_ROMSelection == 3)
{
if (m_beta->started() /*&& !m_beta->is_active()*/)
{
m_beta->enable();
tsconf_update_bank1();
}
}
return m_program->read_byte(offset + 0x3d00);
}
u8 tsconf_state::beta_disable_r(offs_t offset)
{
if (m_beta->started() && m_beta->is_active())
{
m_beta->disable();
tsconf_update_bank1();
}
return m_program->read_byte(offset + 0x4000);
}

View File

@ -44078,6 +44078,9 @@ zx80 // 1980 Sinclair ZX-80
zx81 // 1981 Sinclair ZX-81
zx97 //
@source:tsconf.cpp
tsconf // ZX Evolution - TS-Configuration
@source:testpat.cpp
tp1983
tp1985

View File

@ -266,6 +266,10 @@ void spectrum_state::spectrum_UpdateScreenBitmap(bool eof)
}
}
u16 spectrum_state::get_border_color() {
return m_port_fe_data & 0x07;
}
/* The code below is just a per-pixel 'partial update' for the border */
void spectrum_state::spectrum_UpdateBorderBitmap()
@ -278,7 +282,7 @@ void spectrum_state::spectrum_UpdateBorderBitmap()
if (m_border_bitmap.valid())
{
uint16_t border = m_port_fe_data & 0x07;
uint16_t border = get_border_color();
//printf("update border from %d,%d to %d,%d\n", m_previous_border_x, m_previous_border_y, x, y);