Skip to content

sinclair/tsconf.cpp: Added FPGA 100K variant; implemented Copper for it. #14008

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/mame/mame.lst
Original file line number Diff line number Diff line change
Expand Up @@ -42925,6 +42925,7 @@ uk2086

@source:sinclair/tsconf.cpp
tsconf
tsconf2

@source:sinclair/zx.cpp
lambda
Expand Down
6 changes: 3 additions & 3 deletions src/mame/sinclair/specnext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
}
Expand Down
33 changes: 31 additions & 2 deletions src/mame/sinclair/tsconf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand All @@ -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)
8 changes: 7 additions & 1 deletion src/mame/sinclair/tsconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -239,6 +244,7 @@ class tsconf_state : public spectrum_128_state
std::vector<sprite_data> m_sprites_cache;

required_device<dac_byte_interface> m_dac;
optional_device<tsconf_copper_device> m_copper;
};

/*----------- defined in drivers/tsconf.c -----------*/
Expand Down
217 changes: 217 additions & 0 deletions src/mame/sinclair/tsconf_copper.cpp
Original file line number Diff line number Diff line change
@@ -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;
Comment on lines +122 to +123
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't return and break at same time going to throw a compiler error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither clang nor gcc failed the compilation. I was thinking having break everywhere is more consistent.

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;
}
46 changes: 46 additions & 0 deletions src/mame/sinclair/tsconf_copper.h
Original file line number Diff line number Diff line change
@@ -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 <typename... T> void set_in_until_pos_cb(T &&... args) { return m_in_until_pos_cb.set(std::forward<T>(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<u16> m_cl_data;

devcb_write8 m_out_wreg_cb;
devcb_read_line m_in_dma_ready_cb;
device_delegate<attotime (u16)> 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
Loading
Loading