sinclair/tsconf.cpp: finalize regs delayed updates; fix graphic pages padding (#11248)

- finalize regs delayed updates; fix graphic pages padding
- fix spectrum page switch
This commit is contained in:
holub 2023-05-24 20:25:54 -04:00 committed by GitHub
parent 1109aa3c3d
commit 5c8a49c92c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 119 additions and 87 deletions

View File

@ -27,17 +27,6 @@ TsConf: https://github.com/tslabs/zx-evo/blob/master/pentevo/docs/TSconf/tsconf_
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:
# 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:
- Ram cache
- VDos
@ -56,7 +45,7 @@ TODO:
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 *m_row_location = &m_ram->pointer()[get_vpage_offset() + (tile_index / tilemap.cols() * 256)];
u8 col = tile_index % tilemap.cols();
u8 symbol = m_row_location[col];
tileinfo.set(TM_TS_CHAR, symbol, 0, 0);

View File

@ -150,6 +150,7 @@ private:
TILE_GET_INFO_MEMBER(get_tile_info_16c);
u8 get_border_color(u16 hpos = ~0, u16 vpos = ~0) override;
u32 get_vpage_offset();
rectangle get_screen_area() override;
void spectrum_update_screen(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) override;
void tsconf_UpdateZxScreenBitmap(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
@ -164,10 +165,10 @@ private:
void tsconf_ula_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);
u8 tsconf_port_77_zctr_r();
void tsconf_port_77_zctr_w(u8 data);
u8 tsconf_port_57_zctr_r();
void tsconf_port_57_zctr_w(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);

View File

@ -107,6 +107,11 @@ u8 tsconf_state::get_border_color(u16 hpos, u16 vpos)
return m_regs[BORDER];
}
u32 tsconf_state::get_vpage_offset()
{
return PAGE4K(m_regs[V_PAGE] & ((VM == VM_16C) ? 0xf8 : 0xf0));
}
/*
Layered as:
+ Border - already updated with screen_update_spectrum()
@ -158,7 +163,7 @@ void tsconf_state::tsconf_UpdateZxScreenBitmap(screen_device &screen, bitmap_ind
{
u8 pal_offset = m_regs[PAL_SEL] << 4;
u8 *screen_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]);
u8 *attrs_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + 0x1800;
u8 *attrs_location = screen_location + 0x1800;
bool invert_attrs = u64(screen.frame_number() / m_frame_invert_count) & 1;
for (u16 vpos = cliprect.top(); vpos <= cliprect.bottom(); vpos++)
{
@ -215,7 +220,7 @@ void tsconf_state::tsconf_UpdateGfxBitmap(bitmap_ind16 &bitmap, const rectangle
{
u16 y_offset = (OFFS_512(G_Y_OFFS_L) + m_gfx_y_frame_offset + vpos) & 0x1ff;
u16 x_offset = (OFFS_512(G_X_OFFS_L) + (cliprect.left() - get_screen_area().left())) & 0x1ff;
u8 *video_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + ((y_offset * 512 + x_offset) >> (2 - VM));
u8 *video_location = m_ram->pointer() + get_vpage_offset() + ((y_offset * 512 + x_offset) >> (2 - VM));
u16 *bm = &(bitmap.pix(vpos, cliprect.left()));
s16 width = cliprect.width();
if (VM == VM_16C)
@ -347,20 +352,20 @@ void tsconf_state::ram_page_write(u8 page, offs_t offset, u8 data)
}
else
{
if (ram_addr >= PAGE4K(m_regs[T0_G_PAGE]) && ram_addr < PAGE4K(m_regs[T0_G_PAGE] + 8))
if (ram_addr >= PAGE4K(m_regs[T0_G_PAGE] & 0xf8) && ram_addr < PAGE4K((m_regs[T0_G_PAGE] & 0xf8) + 8))
m_gfxdecode->gfx(TM_TILES0)->mark_all_dirty();
if (ram_addr >= PAGE4K(m_regs[T1_G_PAGE]) && ram_addr < PAGE4K(m_regs[T1_G_PAGE] + 8))
if (ram_addr >= PAGE4K(m_regs[T1_G_PAGE] & 0xf8) && ram_addr < PAGE4K((m_regs[T1_G_PAGE] & 0xf8) + 8))
m_gfxdecode->gfx(TM_TILES1)->mark_all_dirty();
}
if (ram_addr >= PAGE4K(m_regs[V_PAGE]) && ram_addr < PAGE4K(m_regs[V_PAGE] + 1))
if (ram_addr >= get_vpage_offset() && ram_addr < get_vpage_offset() + PAGE4K((VM == VM_16C) ? 8 : 16))
m_ts_tilemap[TM_TS_CHAR]->mark_all_dirty();
if (ram_addr >= PAGE4K(m_regs[m_regs[V_PAGE] ^ 0x01]) && ram_addr < PAGE4K(m_regs[m_regs[V_PAGE] ^ 0x01] + 1))
m_gfxdecode->gfx(TM_TS_CHAR)->mark_all_dirty();
if (ram_addr >= PAGE4K(m_regs[SG_PAGE]) && ram_addr < PAGE4K(m_regs[SG_PAGE] + 8))
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);
@ -379,7 +384,8 @@ void tsconf_state::ram_write16(offs_t offset, u16 data)
u16 tsconf_state::spi_read16()
{
return (tsconf_port_57_zctr_r(0) << 8) | tsconf_port_57_zctr_r(0);
const u16 data_hi = tsconf_port_57_zctr_r() << 8;
return data_hi | tsconf_port_57_zctr_r();
}
void tsconf_state::cram_write(u16 offset, u8 data)
@ -475,11 +481,19 @@ void tsconf_state::tsconf_port_xxaf_w(offs_t port, u8 data)
bool delay_update = true;
switch (nreg)
{
// more registers which marked as *1 in the xls, but rest need to be tested
case V_CONFIG:
case V_PAGE:
case G_X_OFFS_L:
case G_X_OFFS_H:
case G_Y_OFFS_L:
case G_Y_OFFS_H:
case PAL_SEL:
case T0_G_PAGE:
case T1_G_PAGE:
case T0_X_OFFSET_L:
case T0_X_OFFSET_H:
case T1_X_OFFSET_L:
case T1_X_OFFSET_H:
m_scanline_delayed_regs_update[static_cast<tsconf_regs>(nreg)] = data;
break;
@ -575,46 +589,23 @@ void tsconf_state::tsconf_port_xxaf_w(offs_t port, u8 data)
switch (nreg)
{
case V_CONFIG:
case V_PAGE:
tsconf_update_video_mode();
break;
case T_MAP_PAGE:
m_ts_tilemap[TM_TILES0]->mark_all_dirty();
m_ts_tilemap[TM_TILES1]->mark_all_dirty();
break;
case T0_G_PAGE:
m_gfxdecode->gfx(TM_TILES0)->set_source(m_ram->pointer() + PAGE4K(data));
break;
case T0_X_OFFSET_L:
case T0_X_OFFSET_H:
m_ts_tilemap[TM_TILES0]->set_scrollx(OFFS_512(T0_X_OFFSET_L));
break;
case T0_Y_OFFSET_L:
case T0_Y_OFFSET_H:
m_ts_tilemap[TM_TILES0]->set_scrolly(OFFS_512(T0_Y_OFFSET_L));
break;
case T1_G_PAGE:
m_gfxdecode->gfx(TM_TILES1)->set_source(m_ram->pointer() + PAGE4K(data));
break;
case T1_X_OFFSET_L:
case T1_X_OFFSET_H:
m_ts_tilemap[TM_TILES1]->set_scrollx(OFFS_512(T1_X_OFFSET_L));
break;
case T1_Y_OFFSET_L:
case T1_Y_OFFSET_H:
m_ts_tilemap[TM_TILES1]->set_scrolly(OFFS_512(T1_Y_OFFSET_L));
break;
case SG_PAGE:
m_gfxdecode->gfx(TM_SPRITES)->set_source(m_ram->pointer() + PAGE4K(data));
m_gfxdecode->gfx(TM_SPRITES)->set_source(m_ram->pointer() + PAGE4K(data & 0xf8));
break;
case SYS_CONFIG:
@ -630,7 +621,6 @@ void tsconf_state::tsconf_port_xxaf_w(offs_t port, u8 data)
break;
case FMAPS:
case PAL_SEL:
case TS_CONFIG:
case INT_MASK:
// TODO
@ -709,38 +699,38 @@ void tsconf_state::tsconf_port_f7_w(offs_t offset, u8 data)
}
}
void tsconf_state::tsconf_port_77_zctr_w(offs_t port, u8 data)
void tsconf_state::tsconf_port_77_zctr_w(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)
u8 tsconf_state::tsconf_port_77_zctr_r()
{
return 0x02 | (m_sdcard->get_card_present() ? 0x00 : 0x01);
}
void tsconf_state::tsconf_port_57_zctr_w(offs_t port, u8 data)
void tsconf_state::tsconf_port_57_zctr_w(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(CLEAR_LINE); // 0-S R
m_sdcard->spi_clock_w(ASSERT_LINE); // 1-L W
}
}
}
u8 tsconf_state::tsconf_port_57_zctr_r(offs_t port)
u8 tsconf_state::tsconf_port_57_zctr_r()
{
if (m_zctl_cs)
return 0xff;
u8 data = m_zctl_di;
if (!machine().side_effects_disabled())
tsconf_port_57_zctr_w(0, 0xff);
tsconf_port_57_zctr_w(0xff);
return data;
}
@ -844,12 +834,18 @@ TIMER_CALLBACK_MEMBER(tsconf_state::irq_scanline)
u16 screen_vpos = m_screen->vpos();
m_scanline_irq_timer->adjust(m_screen->time_until_pos(screen_vpos + 1));
m_screen->update_now();
if (!m_scanline_delayed_regs_update.empty())
m_screen->update_now();
for (const auto &[reg, val] : m_scanline_delayed_regs_update)
{
m_regs[reg] = val;
switch (reg)
{
case V_CONFIG:
case V_PAGE:
tsconf_update_video_mode();
break;
case G_Y_OFFS_L:
case G_Y_OFFS_H:
m_gfx_y_frame_offset = screen_vpos < get_screen_area().top()
@ -857,6 +853,27 @@ TIMER_CALLBACK_MEMBER(tsconf_state::irq_scanline)
: -screen_vpos;
break;
case T0_G_PAGE:
m_gfxdecode->gfx(TM_TILES0)->set_source(m_ram->pointer() + PAGE4K(val & 0xf8));
break;
case T1_G_PAGE:
m_gfxdecode->gfx(TM_TILES1)->set_source(m_ram->pointer() + PAGE4K(val & 0xf8));
break;
case T0_X_OFFSET_L:
case T0_X_OFFSET_H:
m_ts_tilemap[TM_TILES0]->set_scrollx(OFFS_512(T0_X_OFFSET_L));
break;
case T1_X_OFFSET_L:
case T1_X_OFFSET_H:
m_ts_tilemap[TM_TILES1]->set_scrollx(OFFS_512(T1_X_OFFSET_L));
break;
case G_X_OFFS_L:
case G_X_OFFS_H:
case PAL_SEL:
default:
break;
}

View File

@ -22,6 +22,8 @@ tsconfdma_device::tsconfdma_device(const machine_config &mconfig, const char *ta
void tsconfdma_device::device_start()
{
m_dma_clock = timer_alloc(FUNC(tsconfdma_device::dma_clock), this);
m_in_mreq_cb.resolve_safe(0);
m_out_mreq_cb.resolve_safe();
m_in_mspi_cb.resolve_safe(0);
@ -37,10 +39,14 @@ void tsconfdma_device::device_start()
save_item(NAME(m_align_s));
save_item(NAME(m_align_d));
save_item(NAME(m_align));
save_item(NAME(m_asz));
save_item(NAME(m_task));
}
void tsconfdma_device::device_reset()
{
m_dma_clock->adjust(attotime::never);
m_block_num = 0;
m_ready = ASSERT_LINE;
}
@ -52,32 +58,32 @@ int tsconfdma_device::is_ready()
void tsconfdma_device::set_saddr_l(u8 addr_l)
{
m_address_s = (m_address_s & 0xffffff00) | (addr_l & 0xfe);
m_address_s = (m_address_s & 0x3fff00) | (addr_l & 0xfe);
}
void tsconfdma_device::set_saddr_h(u8 addr_h)
{
m_address_s = (m_address_s & 0xffffc0ff) | ((addr_h & 0x3f) << 8);
m_address_s = (m_address_s & 0x3fc0ff) | ((addr_h & 0x3f) << 8);
}
void tsconfdma_device::set_saddr_x(u8 addr_x)
{
m_address_s = (m_address_s & 0x0003fff) | (addr_x << 14);
m_address_s = (m_address_s & 0x003fff) | (addr_x << 14);
}
void tsconfdma_device::set_daddr_l(u8 addr_l)
{
m_address_d = (m_address_d & 0xffffff00) | (addr_l & 0xfe);
m_address_d = (m_address_d & 0x3fff00) | (addr_l & 0xfe);
}
void tsconfdma_device::set_daddr_h(u8 addr_h)
{
m_address_d = (m_address_d & 0xffffc0ff) | ((addr_h & 0x3f) << 8);
m_address_d = (m_address_d & 0x3fc0ff) | ((addr_h & 0x3f) << 8);
}
void tsconfdma_device::set_daddr_x(u8 addr_x)
{
m_address_d = (m_address_d & 0x0003fff) | (addr_x << 14);
m_address_d = (m_address_d & 0x003fff) | (addr_x << 14);
}
void tsconfdma_device::set_block_len(u8 len)
@ -99,11 +105,20 @@ void tsconfdma_device::set_block_num_h(u8 num_h)
void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_opt)
{
m_task = dev;
m_align_s = s_align;
m_align_d = d_align;
m_asz = align_opt;
m_align = m_asz ? 512 : 256;
m_ready = CLEAR_LINE;
m_align = align_opt ? 512 : 256;
// TODO Transfers 2 byte/cycle at 7MHz
switch (dev)
m_dma_clock->adjust(attotime::from_ticks(m_block_num + 1, 7_MHz_XTAL));
}
TIMER_CALLBACK_MEMBER(tsconfdma_device::dma_clock)
{
switch (m_task)
{
case 0b0001: // Mem -> Mem
for (u16 block = 0; block <= m_block_num; block++)
@ -113,11 +128,11 @@ void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_o
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;
s_addr = (s_addr + 2) & 0x3fffff;
d_addr = (d_addr + 2) & 0x3fffff;
}
m_address_s = s_align ? (m_address_s + m_align) : s_addr;
m_address_d = d_align ? (m_address_d + m_align) : d_addr;
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;
}
break;
@ -127,10 +142,12 @@ void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_o
auto d_addr = m_address_d;
for (u16 len = 0; len <= m_block_len; len++)
{
if (d_addr == 3801154)
printf("!");
m_out_mreq_cb(d_addr, m_in_mspi_cb());
d_addr += 2;
d_addr = (d_addr + 2) & 0x3fffff;
}
m_address_d = d_align ? (m_address_d + m_align) : d_addr;
m_address_d = m_align_d ? (m_address_d + m_align) : d_addr;
}
break;
@ -142,9 +159,9 @@ void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_o
for (u16 len = 0; len <= m_block_len; len++)
{
m_out_mreq_cb(d_addr, data);
d_addr += 2;
d_addr = (d_addr + 2) & 0x3fffff;
}
m_address_d = d_align ? (m_address_d + m_align) : d_addr;
m_address_d = m_align_d ? (m_address_d + m_align) : d_addr;
}
break;
@ -157,7 +174,7 @@ void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_o
{
u16 d_val = m_in_mreq_cb(d_addr);
u16 s_val = m_in_mreq_cb(s_addr);
if (align_opt)
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);
@ -170,11 +187,11 @@ void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_o
d_val = (d_val & 0x0fff) | (((s_val & 0xf000) ? s_val : d_val) & 0xf000);
}
m_out_mreq_cb(d_addr, d_val);
s_addr += 2;
d_addr += 2;
s_addr = (s_addr + 2) & 0x3fffff;
d_addr = (d_addr + 2) & 0x3fffff;
}
m_address_s = s_align ? (m_address_s + m_align) : s_addr;
m_address_d = d_align ? (m_address_d + m_align) : d_addr;
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;
}
break;
@ -186,11 +203,11 @@ void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_o
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;
s_addr = (s_addr + 2) & 0x3fffff;
d_addr = (d_addr + 2) & 0x3fffff;
}
m_address_s = s_align ? (m_address_s + m_align) : s_addr;
m_address_d = d_align ? (m_address_d + m_align) : d_addr;
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;
}
break;
@ -202,19 +219,20 @@ void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_o
for (u16 len = 0; len <= m_block_len; len++)
{
m_out_sfile_cb(d_addr, m_in_mreq_cb(s_addr));
s_addr += 2;
d_addr += 2;
s_addr = (s_addr + 2) & 0x3fffff;
d_addr = (d_addr + 2) & 0x3fffff;
}
m_address_s = s_align ? (m_address_s + m_align) : s_addr;
m_address_d = d_align ? (m_address_d + m_align) : d_addr;
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;
}
break;
default:
logerror("'tsdma': TX %02X: %06X (%02X:%04X) -> %06X\n", dev, m_address_s, m_block_len, m_block_num, m_address_d);
logerror("'tsdma': TX %02X: %06X (%02X:%04X) -> %06X\n", m_task, m_address_s, m_block_len, m_block_num, m_address_d);
break;
}
m_dma_clock->adjust(attotime::never);
m_ready = ASSERT_LINE;
m_on_ready_cb(0);
}

View File

@ -36,7 +36,7 @@ public:
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:
protected:
virtual void device_start() override;
virtual void device_reset() override;
@ -47,14 +47,21 @@ private:
devcb_write16 m_out_sfile_cb;
devcb_write_line m_on_ready_cb;
private:
TIMER_CALLBACK_MEMBER(dma_clock);
u8 m_ready;
offs_t m_address_s;
offs_t m_address_d;
u8 m_block_len;
u16 m_block_num;
emu_timer *m_dma_clock;
u8 m_task;
bool m_align_s;
bool m_align_d;
bool m_asz;
u16 m_align;
};