-sinclair/tsconf.cpp: Replaced Centronics port and COVOX device with a DAC. (#12785)

-sinclair/tsconfdma.cpp: Refactored code.
This commit is contained in:
holub 2024-09-21 14:04:47 -04:00 committed by GitHub
parent ba265bb899
commit 68fd92d30b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 105 additions and 140 deletions

View file

@ -30,8 +30,6 @@ FAQ-RUS: https://forum.tslabs.info/viewtopic.php?f=35&t=157
TODO:
- Ram cache
- VDos
- INTs not perfect. Currently all signals are invalidated after 32t(3.5MHz). Must only do so for frame, not scanline/DMA
- Palette change in the middle of the frame e.g. zapili-c0
****************************************************************************/
@ -96,9 +94,9 @@ void tsconf_state::tsconf_io(address_map &map)
map(0xffdf, 0xffdf).lr8(NAME([this]() -> u8 { return ~m_io_mouse[1]->read(); }));
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));
map(0x00fb, 0x00fb).mirror(0xff00).w("cent_data_out", FUNC(output_latch_device::write));
map(0x8000, 0x8000).mirror(0x3ffd).lw8(NAME([this](u8 data) { return m_ay[m_ay_selected]->data_w(data); }));
map(0xc000, 0xc000).mirror(0x3ffd).lr8(NAME([this]() { return m_ay[m_ay_selected]->data_r(); }))
map(0x00fb, 0x00fb).mirror(0xff00).w(m_dac, FUNC(dac_byte_interface::data_w));
map(0x80fd, 0x80fd).mirror(0x3f00).lw8(NAME([this](u8 data) { return m_ay[m_ay_selected]->data_w(data); }));
map(0xc0fd, 0xc0fd).mirror(0x3f00).lr8(NAME([this]() { return m_ay[m_ay_selected]->data_r(); }))
.w(FUNC(tsconf_state::tsconf_ay_address_w));
}
@ -117,9 +115,9 @@ void tsconf_state::tsconf_bank_w(offs_t offset, u8 data)
static const gfx_layout spectrum_charlayout =
{
8, 8, // 8 x 8 characters */
96, // 96 characters */
1, // 1 bits per pixel */
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
@ -145,8 +143,7 @@ static const gfx_layout tsconf_tile_16cpp_layout =
4,
{STEP4(0, 1)},
{STEP8(0, 4)},
{STEP8(0, 256 * 8)},
// Much more tiles when needed. Because tiles are in RAW format but we don't know region properties.
{STEP8(0, 256 * 8)}, // Much more tiles when needed. Because tiles are in RAW format but we don't know region properties.
8 * 4
};
@ -287,7 +284,7 @@ void tsconf_state::tsconf(machine_config &config)
GLUKRS(config, m_glukrs);
TSCONF_DMA(config, m_dma, 14_MHz_XTAL / 2);
TSCONF_DMA(config, m_dma, 14_MHz_XTAL * 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));
@ -314,9 +311,7 @@ void tsconf_state::tsconf(machine_config &config)
.add_route(1, "rspeaker", 0.25)
.add_route(2, "rspeaker", 0.50);
CENTRONICS(config, m_centronics, centronics_devices, "covox");
output_latch_device &cent_data_out(OUTPUT_LATCH(config, "cent_data_out"));
m_centronics->set_output_latch(cent_data_out);
DAC_8BIT_R2R(config, m_dac, 0).add_route(ALL_OUTPUTS, "mono", 0.75);;
PALETTE(config, "palette", FUNC(tsconf_state::tsconf_palette), 256);
m_screen->set_raw(14_MHz_XTAL / 2, 448, with_hblank(0), 448, 320, with_vblank(0), 320);

View file

@ -16,10 +16,10 @@
#include "tsconfdma.h"
#include "beta_m.h"
#include "bus/centronics/ctronics.h"
#include "machine/pckeybrd.h"
#include "machine/spi_sdcard.h"
#include "sound/ay8910.h"
#include "sound/dac.h"
#include "tilemap.h"
@ -39,7 +39,7 @@ public:
, m_gfxdecode(*this, "gfxdecode")
, m_cram(*this, "cram")
, m_sfile(*this, "sfile")
, m_centronics(*this, "centronics")
, m_dac(*this, "dac")
, m_ay(*this, "ay%u", 0U)
, m_mod_ay(*this, "MOD_AY")
{
@ -233,9 +233,9 @@ private:
tilemap_t *m_ts_tilemap[3]{};
required_device<ram_device> m_cram;
required_device<ram_device> m_sfile;
required_device<centronics_device> m_centronics;
std::vector<sprite_data> m_sprites_cache;
required_device<dac_byte_interface> m_dac;
required_device_array<ym2149_device, 2> m_ay;
u8 m_ay_selected;
required_ioport m_mod_ay;

View file

@ -163,7 +163,6 @@ void tsconf_state::tsconf_update_screen(screen_device &screen, bitmap_rgb32 &bit
}
else
{
bitmap.fill(m_palette->pen_color(get_border_color()), cliprect);
tsconf_draw_gfx(bitmap, cliprect);
}
}
@ -253,7 +252,6 @@ void tsconf_state::tsconf_draw_txt(bitmap_rgb32 &bitmap, const rectangle &clipre
void tsconf_state::tsconf_draw_gfx(bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
u8 pal_offset = m_regs[PAL_SEL] << 4;
const rgb_t transparent = m_palette->pen_color(0);
for (u16 vpos = cliprect.top(); vpos <= cliprect.bottom(); vpos++)
{
u16 y_offset = (OFFS_512(G_Y_OFFS_L) + m_gfx_y_frame_offset + vpos) & 0x1ff;
@ -275,19 +273,11 @@ void tsconf_state::tsconf_draw_gfx(bitmap_rgb32 &bitmap, const rectangle &clipre
video_location -= 256;
u8 pix = *video_location++;
rgb_t pen = m_palette->pen_color(pal_offset | (pix >> 4));
if (pen != transparent)
{
*bm = pen;
}
bm++;
*bm++ = pen;
if (width != 1)
{
pen = m_palette->pen_color(pal_offset | (pix & 0x0f));
if (pen != transparent)
{
*bm = pen;
}
bm++;
*bm++ = pen;
}
}
}
@ -298,11 +288,7 @@ void tsconf_state::tsconf_draw_gfx(bitmap_rgb32 &bitmap, const rectangle &clipre
if (x_offset == 512)
video_location -= 512;
rgb_t pen = m_palette->pen_color(*video_location++);
if (pen != transparent)
{
*bm = pen;
}
bm++;
*bm++ = pen;
}
}
}
@ -441,18 +427,18 @@ void tsconf_state::ram_page_write(u8 page, offs_t offset, u8 data)
if (ram_addr >= PAGE4K(m_regs[SG_PAGE] & 0xf8) && ram_addr < PAGE4K((m_regs[SG_PAGE] & 0xf8) + 8))
m_gfxdecode->gfx(TM_SPRITES)->mark_all_dirty();
m_ram->write(ram_addr, data);
m_ram->pointer()[ram_addr] = data;
}
u16 tsconf_state::ram_read16(offs_t offset)
{
return (m_ram->read(offset & ~offs_t(1)) << 8) | m_ram->read(offset | 1);
return (m_ram->pointer()[offset & ~offs_t(1)] << 8) | m_ram->pointer()[offset | 1];
}
void tsconf_state::ram_write16(offs_t offset, u16 data)
{
ram_page_write(0, offset & ~offs_t(1), data >> 8);
ram_page_write(0, offset | 1, data & 0xff);
m_ram->pointer()[offset | 1] = data & 0xff;
}
u16 tsconf_state::spi_read16()
@ -514,7 +500,7 @@ void tsconf_state::tsconf_port_7ffd_w(u8 data)
void tsconf_state::tsconf_ula_w(offs_t offset, u8 data)
{
spectrum_ula_w(offset, data);
tsconf_port_xxaf_w(BORDER << 8, (data & 0x07) | (m_regs[PAL_SEL] << 4));
tsconf_port_xxaf_w(BORDER << 8, 0xf0 | (data & 0x07));
}
u8 tsconf_state::tsconf_port_xxaf_r(offs_t port)
@ -828,7 +814,9 @@ IRQ_CALLBACK_MEMBER(tsconf_state::irq_vector)
{
u8 vector = 0xff;
if (m_int_mask & 1)
{
m_int_mask &= ~1;
}
else if (m_int_mask & 2)
{
m_int_mask &= ~2;
@ -841,7 +829,7 @@ IRQ_CALLBACK_MEMBER(tsconf_state::irq_vector)
}
if (!m_int_mask)
m_maincpu->set_input_line(0, CLEAR_LINE);
m_maincpu->set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE);
return vector;
}
@ -849,8 +837,6 @@ IRQ_CALLBACK_MEMBER(tsconf_state::irq_vector)
TIMER_CALLBACK_MEMBER(tsconf_state::irq_off)
{
m_int_mask &= ~1;
if (!m_int_mask)
m_maincpu->set_input_line(0, CLEAR_LINE);
}
void tsconf_state::update_frame_timer()
@ -862,10 +848,14 @@ void tsconf_state::update_frame_timer()
{
next = m_screen->time_until_pos(vpos, hpos << 1);
if (next >= m_screen->frame_period())
{
next = attotime::zero;
}
}
else
{
next = attotime::never;
}
m_frame_irq_timer->adjust(next);
}
@ -881,8 +871,7 @@ void tsconf_state::dma_ready(int line)
{
if (BIT(m_regs[INT_MASK], 2))
{
if (!m_int_mask)
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
m_int_mask |= 4;
}
}
@ -891,8 +880,7 @@ TIMER_CALLBACK_MEMBER(tsconf_state::irq_frame)
{
if (BIT(m_regs[INT_MASK], 0))
{
if (!m_int_mask)
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
m_irq_off_timer->adjust(attotime::from_ticks(32, m_maincpu->unscaled_clock()));
m_int_mask |= 1;
}
@ -902,8 +890,7 @@ TIMER_CALLBACK_MEMBER(tsconf_state::irq_scanline)
{
if (BIT(m_regs[INT_MASK], 1))
{
if (!m_int_mask)
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
m_maincpu->set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE);
m_int_mask |= 2;
}

View file

@ -4,11 +4,17 @@
TS-Conf (ZX-Evolution) DMA Controller
TODO:
* Each memory cycle aligned to 7MHz clock and taking 1 tick
**********************************************************************/
#include "emu.h"
#include "tsconfdma.h"
#define VERBOSE ( LOG_GENERAL )
#include "logmacro.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, 0),
@ -36,11 +42,16 @@ void tsconfdma_device::device_start()
save_item(NAME(m_m2));
save_item(NAME(m_asz));
save_item(NAME(m_task));
save_item(NAME(m_tx_s_addr));
save_item(NAME(m_tx_d_addr));
save_item(NAME(m_tx_data));
save_item(NAME(m_tx_block_num));
save_item(NAME(m_tx_block));
}
void tsconfdma_device::device_reset()
{
m_dma_clock->adjust(attotime::never);
m_dma_clock->reset();
m_block_num = 0;
m_ready = ASSERT_LINE;
@ -98,9 +109,12 @@ void tsconfdma_device::set_block_num_h(u8 num_h)
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)
void tsconfdma_device::start_tx(u8 task, bool s_align, bool d_align, bool align_opt)
{
m_task = dev;
if (!m_ready)
LOG("Starting new tx without previous completed\n");
m_task = task;
m_align_s = s_align;
m_align_d = d_align;
m_asz = align_opt;
@ -109,127 +123,90 @@ void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_o
m_m2 = m_asz ? 0x0001ff : 0x0000ff;
m_ready = CLEAR_LINE;
// TODO Transfers 2 byte/cycle at 7MHz
m_dma_clock->adjust(attotime::from_ticks(m_block_num + 1, 7_MHz_XTAL));
m_tx_block_num = 0;
m_tx_block = 0;
m_dma_clock->adjust(attotime::from_ticks(1, clock() / 6), 0, attotime::from_ticks(1, clock() / 6));
}
TIMER_CALLBACK_MEMBER(tsconfdma_device::dma_clock)
{
if (m_tx_block == 0)
{
m_tx_s_addr = m_address_s;
m_tx_d_addr = m_address_d;
}
switch (m_task)
{
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 = m_align_s ? ((s_addr & m_m1) | ((s_addr + 2) & m_m2)) : ((s_addr + 2) & 0x3fffff);
d_addr = m_align_d ? ((d_addr & m_m1) | ((d_addr + 2) & m_m2)) : ((d_addr + 2) & 0x3fffff);
}
m_address_s = m_align_s ? (m_address_s + m_align) : s_addr;
m_address_d = m_align_d ? (m_address_d + m_align) : d_addr;
}
m_out_mreq_cb(m_tx_d_addr, m_in_mreq_cb(m_tx_s_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 = m_align_d ? ((d_addr & m_m1) | ((d_addr + 2) & m_m2)) : ((d_addr + 2) & 0x3fffff);
}
m_address_d = m_align_d ? (m_address_d + m_align) : d_addr;
}
m_out_mreq_cb(m_tx_d_addr, m_in_mspi_cb());
break;
case 0b0100: // Fill
for (u16 block = 0; block <= m_block_num; block++)
if (!m_tx_block_num && !m_tx_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 = m_align_d ? ((d_addr & m_m1) | ((d_addr + 2) & m_m2)) : ((d_addr + 2) & 0x3fffff);
}
m_address_d = m_align_d ? (m_address_d + m_align) : d_addr;
m_tx_data = m_in_mreq_cb(m_address_s);
}
m_out_mreq_cb(m_tx_d_addr, m_tx_data);
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(m_tx_d_addr);
u16 s_val = m_in_mreq_cb(m_tx_s_addr);
if (m_asz)
{
u16 d_val = m_in_mreq_cb(d_addr);
u16 s_val = m_in_mreq_cb(s_addr);
if (m_asz)
{
d_val = (d_val & 0xff00) | (((s_val & 0x00ff) ? s_val : d_val) & 0x00ff);
d_val = (d_val & 0x00ff) | (((s_val & 0xff00) ? s_val : d_val) & 0xff00);
}
else
{
d_val = (d_val & 0xfff0) | (((s_val & 0x000f) ? s_val : d_val) & 0x000f);
d_val = (d_val & 0xff0f) | (((s_val & 0x00f0) ? s_val : d_val) & 0x00f0);
d_val = (d_val & 0xf0ff) | (((s_val & 0x0f00) ? s_val : d_val) & 0x0f00);
d_val = (d_val & 0x0fff) | (((s_val & 0xf000) ? s_val : d_val) & 0xf000);
}
m_out_mreq_cb(d_addr, d_val);
s_addr = m_align_s ? ((s_addr & m_m1) | ((s_addr + 2) & m_m2)) : ((s_addr + 2) & 0x3fffff);
d_addr = m_align_d ? ((d_addr & m_m1) | ((d_addr + 2) & m_m2)) : ((d_addr + 2) & 0x3fffff);
d_val = (d_val & 0xff00) | (((s_val & 0x00ff) ? s_val : d_val) & 0x00ff);
d_val = (d_val & 0x00ff) | (((s_val & 0xff00) ? s_val : d_val) & 0xff00);
}
m_address_s = m_align_s ? (m_address_s + m_align) : s_addr;
m_address_d = m_align_d ? (m_address_d + m_align) : d_addr;
else
{
d_val = (d_val & 0xfff0) | (((s_val & 0x000f) ? s_val : d_val) & 0x000f);
d_val = (d_val & 0xff0f) | (((s_val & 0x00f0) ? s_val : d_val) & 0x00f0);
d_val = (d_val & 0xf0ff) | (((s_val & 0x0f00) ? s_val : d_val) & 0x0f00);
d_val = (d_val & 0x0fff) | (((s_val & 0xf000) ? s_val : d_val) & 0xf000);
}
m_out_mreq_cb(m_tx_d_addr, d_val);
}
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 = m_align_s ? ((s_addr & m_m1) | ((s_addr + 2) & m_m2)) : ((s_addr + 2) & 0x3fffff);
d_addr = m_align_d ? ((d_addr & m_m1) | ((d_addr + 2) & m_m2)) : ((d_addr + 2) & 0x3fffff);
}
m_address_s = m_align_s ? (m_address_s + m_align) : s_addr;
m_address_d = m_align_d ? (m_address_d + m_align) : d_addr;
}
m_out_cram_cb(m_tx_d_addr, m_in_mreq_cb(m_tx_s_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 = m_align_s ? ((s_addr & m_m1) | ((s_addr + 2) & m_m2)) : ((s_addr + 2) & 0x3fffff);
d_addr = m_align_d ? ((d_addr & m_m1) | ((d_addr + 2) & m_m2)) : ((d_addr + 2) & 0x3fffff);
}
m_address_s = m_align_s ? (m_address_s + m_align) : s_addr;
m_address_d = m_align_d ? (m_address_d + m_align) : d_addr;
}
m_out_sfile_cb(m_tx_d_addr, m_in_mreq_cb(m_tx_s_addr));
break;
default:
logerror("'tsdma': TX %02X: %06X (%02X:%04X) -> %06X\n", m_task, m_address_s, m_block_len, m_block_num, m_address_d);
LOG("Unknown task %02X: %06X (%02X:%04X) -> %06X\n", m_task, m_address_s, m_block_len, m_block_num, m_address_d);
m_tx_block_num = m_block_num;
m_tx_block = m_block_len;
break;
}
m_dma_clock->adjust(attotime::never);
m_ready = ASSERT_LINE;
m_on_ready_cb(0);
m_tx_s_addr = m_align_s ? ((m_tx_s_addr & m_m1) | ((m_tx_s_addr + 2) & m_m2)) : ((m_tx_s_addr + 2) & 0x3fffff);
m_tx_d_addr = m_align_d ? ((m_tx_d_addr & m_m1) | ((m_tx_d_addr + 2) & m_m2)) : ((m_tx_d_addr + 2) & 0x3fffff);
++m_tx_block;
if (m_tx_block > m_block_len)
{
m_address_s = m_align_s ? (m_address_s + m_align) : m_tx_s_addr;
m_address_d = m_align_d ? (m_address_d + m_align) : m_tx_d_addr;
m_tx_block = 0;
++m_tx_block_num;
if (m_tx_block_num > m_block_num)
{
m_dma_clock->reset();
m_ready = ASSERT_LINE;
m_on_ready_cb(1);
}
}
}
// device type definition

View file

@ -34,11 +34,11 @@ public:
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);
void start_tx(uint8_t task, bool s_align, bool d_align, bool blitting_opt);
protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
devcb_read16 m_in_mreq_cb;
devcb_write16 m_out_mreq_cb;
@ -57,6 +57,12 @@ private:
u8 m_block_len;
u16 m_block_num;
offs_t m_tx_s_addr;
offs_t m_tx_d_addr;
u16 m_tx_data;
u16 m_tx_block_num;
u16 m_tx_block;
emu_timer *m_dma_clock;
u8 m_task;
bool m_align_s;