From 4b99732c8b9a5803887e2d5f4eecee070761cb3a Mon Sep 17 00:00:00 2001 From: holub Date: Mon, 14 Feb 2022 09:23:22 -0500 Subject: tsconf.cpp: Implemented more functionality (#9097) * Added sprites and improved video emulation * Added YM2149 * Improved timings and iterrupts * Use pre-configured memory banks * Various clean-ups and general improvements --- src/devices/machine/tsconfdma.cpp | 24 +- src/devices/machine/tsconfdma.h | 4 + src/mame/drivers/scorpion.cpp | 1 + src/mame/drivers/tsconf.cpp | 286 +++++++------- src/mame/includes/spectrum.h | 3 +- src/mame/includes/tsconf.h | 86 +++-- src/mame/machine/tsconf.cpp | 787 ++++++++++++++++++++++++++------------ 7 files changed, 783 insertions(+), 408 deletions(-) diff --git a/src/devices/machine/tsconfdma.cpp b/src/devices/machine/tsconfdma.cpp index cf5d4a5c1df..79ef8bc2d50 100644 --- a/src/devices/machine/tsconfdma.cpp +++ b/src/devices/machine/tsconfdma.cpp @@ -14,7 +14,9 @@ tsconfdma_device::tsconfdma_device(const machine_config &mconfig, const char *ta m_in_mreq_cb(*this), m_out_mreq_cb(*this), m_in_mspi_cb(*this), - m_out_cram_cb(*this) + m_out_cram_cb(*this), + m_out_sfile_cb(*this), + m_on_ready_cb(*this) { } @@ -24,6 +26,8 @@ void tsconfdma_device::device_start() m_out_mreq_cb.resolve_safe(); m_in_mspi_cb.resolve_safe(0); m_out_cram_cb.resolve_safe(); + m_out_sfile_cb.resolve_safe(); + m_on_ready_cb.resolve_safe(); save_item(NAME(m_ready)); save_item(NAME(m_address_s)); @@ -180,8 +184,21 @@ void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_o } break; - //case 0b1101: // RAM -> SFILE - // 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 += 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; default: logerror("'tsdma': TX %02X: %06X (%02X:%04X) -> %06X\n", dev, m_address_s, m_block_len, m_block_num, m_address_d); @@ -189,6 +206,7 @@ void tsconfdma_device::start_tx(u8 dev, bool s_align, bool d_align, bool align_o } m_ready = ASSERT_LINE; + m_on_ready_cb(0); } // device type definition diff --git a/src/devices/machine/tsconfdma.h b/src/devices/machine/tsconfdma.h index 4643fccfe43..49929d3c3ae 100644 --- a/src/devices/machine/tsconfdma.h +++ b/src/devices/machine/tsconfdma.h @@ -20,6 +20,8 @@ public: 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(); } + auto out_sfile_callback() { return m_out_sfile_cb.bind(); } + auto on_ready_callback() { return m_on_ready_cb.bind(); } int is_ready(); @@ -42,6 +44,8 @@ private: devcb_write16 m_out_mreq_cb; devcb_read16 m_in_mspi_cb; devcb_write16 m_out_cram_cb; + devcb_write16 m_out_sfile_cb; + devcb_write_line m_on_ready_cb; u8 m_ready; diff --git a/src/mame/drivers/scorpion.cpp b/src/mame/drivers/scorpion.cpp index e96dee69a10..3f4792606fa 100644 --- a/src/mame/drivers/scorpion.cpp +++ b/src/mame/drivers/scorpion.cpp @@ -52,6 +52,7 @@ private: required_memory_bank m_bank4; required_device m_beta; + uint8_t *m_ram_0000; address_space *m_program; uint8_t *m_p_ram; void scorpion_update_memory(); diff --git a/src/mame/drivers/tsconf.cpp b/src/mame/drivers/tsconf.cpp index 926fb4fc9b8..232267da6e4 100644 --- a/src/mame/drivers/tsconf.cpp +++ b/src/mame/drivers/tsconf.cpp @@ -2,114 +2,106 @@ // 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... +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: +- 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 ****************************************************************************/ #include "emu.h" #include "includes/tsconf.h" +#include "sound/ay8910.h" +#include "speaker.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); + tileinfo.set(TM_TS_CHAR, symbol, 0, 0); } template 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 col_offset = (tile_index % tilemap.cols() + Layer * 64) << 1; + u16 row_offset = (tile_index / tilemap.cols() * 64 * 2) << 1; 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()); + u32 /*u16*/ tile = ((u16(hi) & 0x0f) << 8) | tile_info_addr[0]; + tile = tile / tilemap.cols() * 64 * 8 + (tile % tilemap.cols()); // same as: tmp_tile_oversized_to_code() 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); + tileinfo.set(TM_TILES0 + Layer, tile, pal, TILE_FLIPYX(BIT(hi, 6, 2))); + tileinfo.category = tile == 0 ? 2 : 1; } 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>)); + map(0x0000, 0x3fff).bankr(m_banks[0]).w(FUNC(tsconf_state::tsconf_bank_w<0>)); + map(0x0000, 0x3fff).view(m_bank0_rom); + m_bank0_rom[0](0x0000, 0x3fff).bankr(m_banks[4]); + + map(0x4000, 0x7fff).bankr(m_banks[1]).w(FUNC(tsconf_state::tsconf_bank_w<1>)); + map(0x8000, 0xbfff).bankr(m_banks[2]).w(FUNC(tsconf_state::tsconf_bank_w<2>)); + map(0xc000, 0xffff).bankr(m_banks[3]).w(FUNC(tsconf_state::tsconf_bank_w<3>)); } void tsconf_state::tsconf_io(address_map &map) @@ -122,11 +114,13 @@ void tsconf_state::tsconf_io(address_map &map) 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_ula_r), FUNC(tsconf_state::tsconf_port_fe_w)); + map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(tsconf_state::spectrum_ula_r), FUNC(tsconf_state::tsconf_ula_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)); + 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 tsconf_state::tsconf_switch(address_map &map) @@ -136,7 +130,7 @@ void tsconf_state::tsconf_switch(address_map &map) map(0x4000, 0xffff).r(FUNC(tsconf_state::beta_disable_r)); } -template +template void tsconf_state::tsconf_bank_w(offs_t offset, u8 data) { tsconf_state::ram_bank_write(Bank, offset, data); @@ -145,8 +139,8 @@ 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 */ + 96, /* 96 characters */ + 1, /* 1 bits per pixel */ {0}, /* no bitplanes */ /* x offsets */ {STEP8(0, 1)}, @@ -157,8 +151,7 @@ static const gfx_layout spectrum_charlayout = static const gfx_layout tsconf_charlayout = { - 8, - 8, + 8, 8, 256, 1, {0}, @@ -181,74 +174,80 @@ static const gfx_layout tsconf_tile_16cpp_layout = }; 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_ENTRY("maincpu", 0, tsconf_charlayout, 0xf7, 1) // TM_TS_CHAR : TXT + GFXDECODE_ENTRY("maincpu", 0, tsconf_tile_16cpp_layout, 0, 16) // TM_TILES0 : T0 16cpp + GFXDECODE_ENTRY("maincpu", 0, tsconf_tile_16cpp_layout, 0, 16) // TM_TILES1 : T1 16cpp + GFXDECODE_ENTRY("maincpu", 0, tsconf_tile_16cpp_layout, 0, 16) // TM_SPRITES : Sprites 16cpp + GFXDECODE_ENTRY("maincpu", 0x1fd00, spectrum_charlayout, 0xf7, 1) // TM_ZX_CHAR GFXDECODE_END void tsconf_state::video_start() { spectrum_128_state::video_start(); + m_scanline_timer->reset(); + + m_ts_tilemap[TM_TS_CHAR] = &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[TM_TILES0] = &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[TM_TILES0]->set_transparent_pen(0); + + m_ts_tilemap[TM_TILES1] = &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[TM_TILES1]->set_transparent_pen(0); - 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); + m_frame_irq_timer = timer_alloc(TIMER_IRQ_FRAME); + m_line_irq_timer = timer_alloc(TIMER_IRQ_SCANLINE); } void tsconf_state::machine_start() { + for (auto i = 0; i < 4; i++) + m_banks[i]->configure_entries(0, m_ram->size() / 0x4000, m_ram->pointer(), 0x4000); + + memory_region *rom = memregion("maincpu"); + m_banks[4]->configure_entries(0, rom->bytes() / 0x4000, rom->base(), 0x4000); + save_item(NAME(m_regs)); // TODO save'm'all! } void tsconf_state::machine_reset() { - u8 *messram = m_ram->pointer(); + m_bank0_rom.select(0); 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 + m_scanline_delayed_regs_update = {}; + m_regs[V_CONFIG] = 0x00; // 00000000 + m_regs[V_PAGE] = 0x05; // 00000101 + m_regs[G_X_OFFS_L] = 0x00; // 00000000 + m_regs[G_X_OFFS_H] &= 0xfe; // xxxxxxx0 + m_regs[G_Y_OFFS_L] = 0x00; // 00000000 + m_regs[G_Y_OFFS_H] &= 0xfe; // xxxxxxx0 + m_regs[TS_CONFIG] &= 0x03; // 000000xx + m_regs[PAL_SEL] = 0x0f; // 00001111 + m_regs[PAGE0] = 0x00; // 00000000 + m_regs[PAGE1] = 0x05; // 00000101 + m_regs[PAGE2] = 0x02; // 00000010 + m_regs[PAGE3] = 0x00; // 00000000 + m_regs[FMAPS] &= 0xef; // xxx0xxxx + m_regs[SYS_CONFIG] = 0x00; // 00000000 + m_regs[MEM_CONFIG] = 0x04; // 00000100 + m_regs[HS_INT] = 0x01; // 00000001 + m_regs[VS_INT_L] = 0x00; // 00000000 + m_regs[VS_INT_H] &= 0x0e; // 0000xxx0 + m_regs[FDD_VIRT] &= 0xf0; // xxxx0000 + m_regs[INT_MASK] = 0x01; // xxxxx001 + m_regs[CACHE_CONFIG] &= 0xf0; // xxxx0000 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(); + tsconf_update_bank0(); + tsconf_update_video_mode(); m_keyboard->write(0xff); while (m_keyboard->read() != 0) { /* invalidate buffer */ } @@ -257,40 +256,55 @@ void tsconf_state::machine_reset() void tsconf_state::tsconf(machine_config &config) { spectrum_128(config); + m_maincpu->set_clock(3.5_MHz_XTAL); + 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_maincpu->set_vblank_int("screen", FUNC(tsconf_state::tsconf_vblank_interrupt)); + m_ram->set_default_size("4096K"); GLUKRS(config, m_glukrs); - TSCONF_DMA(config, m_dma, XTAL(14'000'000) / 2); + TSCONF_DMA(config, m_dma, 7_MHz_XTAL); 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)); + m_dma->out_sfile_callback().set(FUNC(tsconf_state::sfile_write16)); + m_dma->on_ready_callback().set(FUNC(tsconf_state::dma_ready)); 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)); + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); + + YM2149(config.replace(), "ay8912", 14_MHz_XTAL / 8) + .add_route(0, "lspeaker", 0.50) + .add_route(1, "lspeaker", 0.25) + .add_route(1, "rspeaker", 0.25) + .add_route(2, "rspeaker", 0.50); + PALETTE(config, "palette", FUNC(tsconf_state::tsconf_palette), 256); - m_screen->set_raw(X1_128_SINCLAIR / 2.5, 448, 0, 360, 320, 0, 288); + m_screen->set_raw(7_MHz_XTAL, 448, with_hblank(), 448, 320, with_vblank(), 320); subdevice("gfxdecode")->set_info(gfx_tsconf); RAM(config, m_cram).set_default_size("512").set_default_value(0); + RAM(config, m_sfile).set_default_size("512").set_default_value(0); // 85*6 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_REGION(0x080000, "maincpu", ROMREGION_ERASEFF) // ROM: 32 * 16KB + ROM_LOAD("ts-bios.rom", 0, 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 ) +COMP( 2011, tsconf, spec128, 0, tsconf, spec_plus, tsconf_state, empty_init, "NedoPC, TS-Labs", "ZX Evolution TS-Configuration", MACHINE_IS_INCOMPLETE) diff --git a/src/mame/includes/spectrum.h b/src/mame/includes/spectrum.h index dda18643898..202013642c3 100644 --- a/src/mame/includes/spectrum.h +++ b/src/mame/includes/spectrum.h @@ -145,7 +145,6 @@ protected: int m_LastFrameStartTime; int m_CyclesPerLine; - uint8_t *m_ram_0000; uint8_t m_ram_disabled_by_beta; uint8_t pre_opcode_fetch_r(offs_t offset); void spectrum_rom_w(offs_t offset, uint8_t data); @@ -211,7 +210,7 @@ protected: optional_ioport m_io_joy1; optional_ioport m_io_joy2; - void spectrum_UpdateBorderBitmap(); + virtual void spectrum_UpdateBorderBitmap(); virtual u16 get_border_color(); virtual void spectrum_UpdateScreenBitmap(bool eof = false); inline unsigned char get_display_color(unsigned char color, int invert); diff --git a/src/mame/includes/tsconf.h b/src/mame/includes/tsconf.h index 4a19a75c64f..5dcee961dd4 100644 --- a/src/mame/includes/tsconf.h +++ b/src/mame/includes/tsconf.h @@ -11,24 +11,23 @@ #pragma once #include "spectrum.h" - #include "machine/beta.h" - #include "machine/glukrs.h" #include "machine/pckeybrd.h" #include "machine/spi_sdcard.h" #include "machine/tsconfdma.h" - #include "tilemap.h" +constexpr u16 with_hblank(u16 pixclocks = 0) { return 88 + pixclocks; } +constexpr u16 with_vblank(u16 pixclocks = 0) { return 32 + pixclocks; } 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_bank0_rom(*this, "bank0_rom"), + m_banks(*this, "bank%u", 0U), m_keyboard(*this, "pc_keyboard"), m_beta(*this, BETA_DISK_TAG), m_dma(*this, "dma"), @@ -36,7 +35,8 @@ public: m_glukrs(*this, "glukrs"), m_palette(*this, "palette"), m_gfxdecode(*this, "gfxdecode"), - m_cram(*this, "cram") + m_cram(*this, "cram"), + m_sfile(*this, "sfile") { } @@ -46,8 +46,15 @@ protected: virtual void video_start() override; virtual void machine_start() override; virtual void machine_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param) override; private: + enum timer_id : u8 + { + TIMER_IRQ_FRAME = TIMER_SCANLINE + 1, + TIMER_IRQ_SCANLINE + }; + enum gluk_ext : u8 { CONF_VERSION = 0x00, @@ -60,6 +67,15 @@ private: DISABLED = 0xff }; + enum tilemaps : u8 + { + TM_TS_CHAR = 0x00, + TM_TILES0, + TM_TILES1, + TM_SPRITES, + TM_ZX_CHAR, + }; + enum tsconf_regs : u8 { V_CONFIG = 0x00, @@ -102,36 +118,46 @@ private: DMA_LEN = 0x26, DMA_CTRL = 0x27, DMA_NUM_L = 0x28, + FDD_VIRT = 0x29, INT_MASK = 0x2a, + CACHE_CONFIG = 0x2b, 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 + T0_X_OFFSET_L = 0x40, + T0_X_OFFSET_H = 0x41, + T0_Y_OFFSET_L = 0x42, + T0_Y_OFFSET_H = 0x43, + T1_X_OFFSET_L = 0x44, + T1_X_OFFSET_H = 0x45, + T1_Y_OFFSET_L = 0x46, + T1_Y_OFFSET_H = 0x47 }; + void update_frame_timer(); + emu_timer *m_frame_irq_timer; + emu_timer *m_line_irq_timer; + + INTERRUPT_GEN_MEMBER(tsconf_vblank_interrupt); + DECLARE_VIDEO_START(tsconf); TILE_GET_INFO_MEMBER(get_tile_info_txt); template 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 spectrum_UpdateBorderBitmap() override; + void spectrum_UpdateZxScreenBitmap(); + void tsconf_UpdateTxtBitmap(unsigned int from_x, unsigned int from_y); + void tsconf_UpdateGfxBitmap(unsigned int from_x, unsigned int from_y); 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 draw_sprites(const rectangle &cliprect); void tsconf_update_video_mode(); - rectangle get_resolution_info(); + rectangle get_screen_area(); void tsconf_port_7ffd_w(u8 data); - void tsconf_port_fe_w(offs_t offset, u8 data); + 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); @@ -142,7 +168,7 @@ private: u8 tsconf_port_f7_r(offs_t offset); void tsconf_port_f7_w(offs_t offset, u8 data); - void tsconf_update_bank1(); + void tsconf_update_bank0(); u8 beta_neutral_r(offs_t offset); u8 beta_enable_r(offs_t offset); u8 beta_disable_r(offs_t offset); @@ -151,24 +177,25 @@ private: void tsconf_mem(address_map &map); void tsconf_switch(address_map &map); - template + u8 mem_bank_read(u8 bank, offs_t offset); + template 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 sfile_write16(offs_t offset, u16 data); void ram_write16(offs_t offset, u16 data); u16 ram_read16(offs_t offset); u16 spi_read16(); + void dma_ready(int line); + std::map m_scanline_delayed_regs_update; u8 m_regs[0x100]; address_space *m_program; - required_region_ptr m_p_rom; - required_memory_bank m_bank1; - required_memory_bank m_bank2; - required_memory_bank m_bank3; - required_memory_bank m_bank4; + memory_view m_bank0_rom; + required_memory_bank_array<5> m_banks; required_device m_keyboard; @@ -182,10 +209,13 @@ private: gluk_ext m_port_f7_ext; u8 m_port_f7_gluk_reg; - optional_device m_palette; + u16 m_rendering_gfx_y_offset; + required_device m_palette; required_device m_gfxdecode; - tilemap_t *m_ts_tilemap[4]; + tilemap_t *m_ts_tilemap[3]; required_device m_cram; + required_device m_sfile; + u16 m_previous_tsu_vpos; }; /*----------- defined in drivers/tsconf.c -----------*/ diff --git a/src/mame/machine/tsconf.cpp b/src/mame/machine/tsconf.cpp index 1b35f167878..5f9a4f10d08 100644 --- a/src/mame/machine/tsconf.cpp +++ b/src/mame/machine/tsconf.cpp @@ -10,14 +10,15 @@ #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 OFFS_512(_rl) (((m_regs[_rl + 1] & 1) << 8) | m_regs[_rl]) #define VM static_cast(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 +static constexpr rectangle screen_area[4] = { + rectangle(with_hblank(52), with_hblank(256 + 51), with_vblank(48), with_vblank(192 + 47)), // 52|256|52 x 48-192-48 + rectangle(with_hblank(20), with_hblank(320 + 19), with_vblank(44), with_vblank(200 + 43)), // 20|320|20 x 44-200-44 + rectangle(with_hblank(20), with_hblank(320 + 19), with_vblank(24), with_vblank(240 + 23)), // 20|320|20 x 24-240-24 + rectangle(with_hblank(00), with_hblank(360 - 01), with_vblank(00), with_vblank(288 - 01)) // 00|360|00 x 00-288-00 }; enum v_mode : u8 @@ -28,6 +29,11 @@ enum v_mode : u8 VM_TXT }; +static constexpr u32 tmp_tile_oversized_to_code(u16 code) +{ + return code / 64 * 64 * 8 + (code % 64); +} + // 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, @@ -40,12 +46,11 @@ 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 tsconf_state::get_screen_area() { - rectangle info = resolution_info[BIT(m_regs[V_CONFIG], 6, 2)]; + rectangle info = screen_area[BIT(m_regs[V_CONFIG], 6, 2)]; if (VM == VM_TXT) { - info.set_origin(0, 0); info.set_width(info.width() << 1); } return info; @@ -57,10 +62,8 @@ void tsconf_state::tsconf_palette(palette_device &palette) const palette.set_pen_colors(0, colors); } -void tsconf_state::tsconf_update_bank1() +void tsconf_state::tsconf_update_bank0() { - - //W0_WE if (NW0_MAP) { m_ROMSelection = m_regs[PAGE0]; @@ -72,191 +75,375 @@ void tsconf_state::tsconf_update_bank1() m_ROMSelection |= (m_regs[PAGE0] & 0xfc); } - uint8_t *rom0; if (W0_RAM) { - rom0 = m_ram->pointer() + PAGE4K(m_ROMSelection); - m_bank1->set_base(rom0); + m_banks[0]->set_entry(m_ROMSelection); + m_bank0_rom.disable(); } else { - rom0 = &m_p_rom[0x10000 + PAGE4K(m_ROMSelection & 0x1f)]; - m_bank1->set_base(rom0); + m_banks[4]->set_entry(m_ROMSelection & 0x1f); + m_bank0_rom.select(0); } - 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 + rectangle visarea = screen_area[3]; + if (VM == VM_TXT) { - m_screen_location = messram + ((m_port_7ffd_data & 8) ? PAGE4K(7) : PAGE4K(5)); - break; - } - default: - break; + // scale screen for Text Mode + rectangle origin_screen = screen_area[BIT(m_regs[V_CONFIG], 6, 2)]; + visarea.set_width(visarea.width() + origin_screen.width()); + m_gfxdecode->gfx(TM_TS_CHAR)->set_source(m_ram->pointer() + PAGE4K(m_regs[V_PAGE] ^ 0x01)); + m_ts_tilemap[TM_TS_CHAR]->mark_all_dirty(); } - m_screen->configure(resolution.width(), resolution.height(), resolution, HZ_TO_ATTOSECONDS(50)); + m_ts_tilemap[TM_TILES0]->set_scrolldx(get_screen_area().left(), 0); + m_ts_tilemap[TM_TILES0]->set_scrolldy(get_screen_area().top(), 0); + m_ts_tilemap[TM_TILES1]->set_scrolldx(get_screen_area().left(), 0); + m_ts_tilemap[TM_TILES1]->set_scrolldy(get_screen_area().top(), 0); + + m_screen->configure(visarea.max_x + 1, visarea.max_y + 1, visarea, m_screen->frame_period().as_attoseconds()); } uint32_t tsconf_state::screen_update_spectrum(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { - if (m_screen_bitmap.valid()) + return 0; +} + +void to_display(rectangle area, unsigned int &x, unsigned int &y) +{ + if (y < area.top() || y > area.bottom()) { - // 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); - } - } + x = area.left(); + y = area.top(); + } + else if (x < area.left()) + x = area.left(); + else if (x > area.right()) + { + x = area.left(); + to_display(area, x, ++y); + } +} - // Main Graphics - rectangle resolution = get_resolution_info(); - if (!BIT(m_regs[V_CONFIG], 5)) +void tsconf_state::spectrum_UpdateZxScreenBitmap() +{ + unsigned int to_x = m_screen->hpos(); + unsigned int to_y = m_screen->vpos(); + to_display(m_screen->visible_area(), to_x, to_y); + + if ((m_previous_screen_x == to_x) && (m_previous_screen_y == to_y)) + return; + + bitmap_ind16 *bm = &m_screen->curbitmap().as_ind16(); + if (bm->valid()) + { + u8 pal_offset = m_regs[PAL_SEL] << 4; + u16 border_color = m_regs[BORDER]; + bool border_only = VM != VM_ZX || BIT(m_regs[V_CONFIG], 5); + rectangle screen = screen_area[0]; + do { - if (VM == VM_ZX) + if (border_only || !screen.contains(m_previous_screen_x, m_previous_screen_y)) + bm->pix(m_previous_screen_y, m_previous_screen_x) = border_color; + else { - // Zx palette is stored at 0xf0. Adjust bitmaps colors. - for (auto y = cliprect.top(); y <= cliprect.bottom(); y++) + u16 x = m_previous_screen_x - screen.left(); + if ((x & 7) == 0) { - u16 *bm = &m_screen_bitmap.pix(y, 0); - for (auto x = cliprect.left(); x <= cliprect.right(); x++) - { - *bm++ |= 0xf0; - } + u16 y = m_previous_screen_y - screen.top(); + u16 *pix = &bm->pix(m_previous_screen_y, m_previous_screen_x); + u8 attr = *(m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + ((y & 0xF8) << 2) + (x >> 3) + 0x1800); + u8 scr = *(m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + ((y & 7) << 8) + ((y & 0x38) << 2) + ((y & 0xC0) << 5) + (x >> 3)); + u16 ink = ((attr & 0x07) + ((attr >> 3) & 0x08)) | pal_offset; + u16 pap = ((attr >> 3) & 0x0f) | pal_offset; + + if (m_flash_invert && (attr & 0x80)) + scr = ~scr; + + for (uint8_t b = 0x80; b != 0; b >>= 1) + *pix++ = (scr & b) ? ink : pap; } - spectrum_state::screen_update_spectrum(screen, bitmap, cliprect); - } - else - { - copyscrollbitmap(bitmap, m_screen_bitmap, 0, nullptr, 0, nullptr, resolution); } + + to_display(m_screen->visible_area(), ++m_previous_screen_x, m_previous_screen_y); + } while (!((m_previous_screen_x == to_x) && (m_previous_screen_y == to_y))); + } +} + +void tsconf_state::tsconf_UpdateTxtBitmap(unsigned int from_x, unsigned int from_y) +{ + unsigned int to_x = m_screen->hpos(); + unsigned int to_y = m_screen->vpos(); + rectangle screen = get_screen_area(); + to_display(screen, to_x, to_y); + + u8 pal_offset = m_regs[PAL_SEL] << 4; + while (!((from_x == to_x) && (from_y == to_y))) + { + if (from_x == screen.left() && (from_y == screen.top())) + m_rendering_gfx_y_offset = OFFS_512(G_Y_OFFS_L); + + u16 x = from_x - screen.left(); + u16 *bm = &m_screen->curbitmap().as_ind16().pix(from_y, from_x); + s16 width = (screen.width() - x) / 8; + + // TODO u16 x_offset = OFFS_512(G_X_OFFS_L); + u8 *font_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE] ^ 0x01); + u8 *text_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + (m_rendering_gfx_y_offset / 8 * 256 + x / 8); + for (; width > 0; width--) + { + u8 char_x = *(font_location + (*text_location * 8) + (m_rendering_gfx_y_offset % 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++; } - // Tiles & Sprites - // TODO layers - if (!BIT(m_regs[V_CONFIG], 4)) + + if (from_y == to_y) + // done - scanline updated partially + from_x = to_x; + else { - if (BIT(m_regs[TS_CONFIG], 5)) + from_y += 1; + m_rendering_gfx_y_offset = (m_rendering_gfx_y_offset + 1) & 0x1ff; + from_x = screen.left(); + to_display(screen, from_x, from_y); + } + } +} + +void tsconf_state::tsconf_UpdateGfxBitmap(unsigned int from_x, unsigned int from_y) +{ + unsigned int to_x = m_screen->hpos(); + unsigned int to_y = m_screen->vpos(); + rectangle screen = get_screen_area(); + to_display(screen, to_x, to_y); + + u8 pal_offset = m_regs[PAL_SEL] << 4; + while (!((from_x == to_x) && (from_y == to_y))) + { + if (from_x == screen.left() && (from_y == screen.top())) + m_rendering_gfx_y_offset = OFFS_512(G_Y_OFFS_L); + + u16 x = from_x - screen.left(); + u16 x_offset = (OFFS_512(G_X_OFFS_L) + x) & 0x1ff; + u16 *bm = &m_screen->curbitmap().as_ind16().pix(from_y, from_x); + u8 *video_location = m_ram->pointer() + PAGE4K(m_regs[V_PAGE]) + ((m_rendering_gfx_y_offset * 512 + x_offset) >> (2 - VM)); + s16 width = screen.width() - x; + if (VM == VM_16C) + { + if (x_offset & 1) { - m_ts_tilemap[1]->draw(screen, bitmap, resolution, 0); + *bm++ = (*video_location++ & 0x0f) | pal_offset; + x_offset++; + width--; } - if (BIT(m_regs[TS_CONFIG], 6)) + for (; width > 0; width -= 2) { - m_ts_tilemap[2]->draw(screen, bitmap, resolution, 0); + if (x_offset == 512) + video_location -= 256; + u8 pix = *video_location++; + *bm++ = (pix >> 4) | pal_offset; + if (width == 1) + x_offset++; + else + { + *bm++ = (pix & 0x0f) | pal_offset; + x_offset += 2; + } } - if (BIT(m_regs[TS_CONFIG], 7)) + } + else // VM_256C + { + for (; width > 0; width--) { - draw_sprites(screen, bitmap, resolution); + if (x_offset == 512) + video_location -= 512; + *bm++ = *video_location++; + x_offset++; } } + + if (from_y == to_y) + // done - scanline updated partially + from_x = to_x; + else + { + from_y += 1; + m_rendering_gfx_y_offset = (m_rendering_gfx_y_offset + 1) & 0x1ff; + from_x = screen.left(); + to_display(screen, from_x, from_y); + } } - return 0; } +/* +Layered as: + + Border + + Graphics + + Sprites 0 + + Tiles 0 + + Sprites 1 + + Tiles 1 + + Sprites 2 +*/ void tsconf_state::spectrum_UpdateScreenBitmap(bool eof) { - if (!BIT(m_regs[V_CONFIG], 5)) + rectangle screen = get_screen_area(); + unsigned int from_x = m_previous_screen_x; + unsigned int from_y = m_previous_screen_y; + + spectrum_UpdateZxScreenBitmap(); + if (!BIT(m_regs[V_CONFIG], 5) && VM != VM_ZX) + { + to_display(screen, from_x, from_y); + if (VM == VM_TXT) + tsconf_UpdateTxtBitmap(from_x, from_y); + else + tsconf_UpdateGfxBitmap(from_x, from_y); + } + + if (!BIT(m_regs[V_CONFIG], 4)) { - if (VM == VM_ZX) + if (m_screen->vpos() == m_previous_tsu_vpos) + return; + + bool draw = false; + s16 y = m_screen->vpos() - screen.top(); + if (m_screen->vpos() == screen.bottom()) { - spectrum_state::spectrum_UpdateScreenBitmap(eof); + m_previous_tsu_vpos = screen.top(); + screen.min_y = m_previous_tsu_vpos; + draw = true; } - else if (!eof) + else if (y >= 0 && y < screen.height()) { - u8 pal_offset = m_regs[PAL_SEL] << 4; - rectangle resolution = get_resolution_info(); - if (VM == VM_TXT) + // Update unrendered above excluding current line. + screen.sety(m_previous_tsu_vpos, m_screen->vpos() - 1); + // Too expencive to draw every line. Batch 8+ for now. + draw = screen.height() > 7; + if (!draw && (screen.bottom() + 1) == get_screen_area().bottom()) { - 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++; - } - } + screen.max_y++; + draw = true; } + if (draw) + m_previous_tsu_vpos = m_screen->vpos(); + } + + if (draw) + { + m_screen->priority().fill(0, screen); + if (BIT(m_regs[TS_CONFIG], 5)) + m_ts_tilemap[TM_TILES0]->draw(*m_screen, m_screen->curbitmap().as_ind16(), screen, + BIT(m_regs[TS_CONFIG], 2) ? TILEMAP_DRAW_ALL_CATEGORIES : TILEMAP_DRAW_CATEGORY(1), 1); + + if (BIT(m_regs[TS_CONFIG], 6)) + m_ts_tilemap[TM_TILES1]->draw(*m_screen, m_screen->curbitmap().as_ind16(), screen, + BIT(m_regs[TS_CONFIG], 3) ? TILEMAP_DRAW_ALL_CATEGORIES : TILEMAP_DRAW_CATEGORY(1), 2); + + if (BIT(m_regs[TS_CONFIG], 7)) + draw_sprites(screen); } } } -u16 tsconf_state::get_border_color() +void tsconf_state::spectrum_UpdateBorderBitmap() { - return m_regs[BORDER]; + spectrum_UpdateScreenBitmap(); } -void tsconf_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +/* +SFILE Reg.16 7 6 5 4 3 2 1 0 +0 R0L Y[7:0] +1 R0H YF LEAP ACT - YS[2:0] Y[8] +2 R1L X[7:0] +3 R1H XF - - - XS[2:0] X[8] +4 R2L TNUM[7:0] +5 R2H SPAL[7:4] TNUM[11:8] +*/ +void tsconf_state::draw_sprites(const rectangle &cliprect) { - //u8 *messram = m_ram->pointer(); - //u8 *sprites_location = messram + PAGE4K(m_regs[SG_PAGE]); - for (u8 i = 0; i < 85; i++) + rectangle screen = get_screen_area(); + + u8 layer = 0; + u8 *sinfo = m_sfile->pointer() + 1; + u8 sid = 1; + // Higher Sprite draws on top. Prepare to iterate backwards. + for (; sid < 85 && layer < 3; sid++) { - logerror("Draw Sprites ... TODO\n"); + if (BIT(*sinfo, 6)) + layer++; + sinfo += 6; + } + sinfo -= 1; + + for (; sid; sid--) + { + s16 y = *sinfo++; + y |= BIT(*sinfo, 0) << 8; + y += screen.top() - (y >= screen.height() ? 512 : 0); + u8 height8 = BIT(*sinfo, 1, 3); + layer -= BIT(*sinfo, 6); + if (!BIT(*sinfo, 5)) + { + // sprite disabled -> move to previous + sinfo -= 7; + } + else + { + bool flipy = BIT(*sinfo++, 7); + s16 x = *sinfo++; + x |= BIT(*sinfo, 0) << 8; + x += screen.left() - (x >= screen.width() ? 512 : 0); + u8 width8 = BIT(*sinfo, 1, 3); + bool flipx = BIT(*sinfo++, 7); + u16 code = *sinfo++; + code |= BIT(*sinfo, 0, 4) << 8; + u8 pal = BIT(*sinfo, 4, 4); + sinfo -= 11; + + u32 pmask = layer ? (layer == 1 ? GFX_PMASK_2 : 0) : (GFX_PMASK_1 | GFX_PMASK_2); + + u8 tile_row = code / 64 + flipy * height8; + for (auto iy = y; iy <= y + height8 * 8; iy = iy + 8) + { + u8 tile_col = (code % 64) + flipx * width8; + for (auto ix = x; ix <= x + width8 * 8; ix = ix + 8) + { + m_gfxdecode->gfx(TM_SPRITES)->prio_transpen(m_screen->curbitmap().as_ind16(), cliprect, tmp_tile_oversized_to_code((tile_row % 64) * 64 + (tile_col % 64)), pal, flipx, flipy, ix, iy, m_screen->priority(), pmask, 0); + tile_col += flipx ? -1 : 1; + } + tile_row += flipy ? -1 : 1; + } + } } } 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))) + if (BIT(m_regs[FMAPS], 4)) { - cram_write(machine_addr - fmap_addr, data); + offs_t machine_addr = PAGE4K(bank) + offset; + offs_t fmap_addr = BIT(m_regs[FMAPS], 0, 4) << 12; + if ((machine_addr >= fmap_addr) && (machine_addr < (fmap_addr + 256 * 5))) + { + u16 addr_w = machine_addr - fmap_addr; + if (addr_w < 512) + cram_write(addr_w, data); + else if (addr_w < 1024) + m_sfile->write(addr_w - 512, data); + else + tsconf_port_xxaf_w((addr_w - 1024) << 8, data); + } } - else if (bank > 0 || (W0_WE && W0_RAM)) - { + + 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) @@ -264,26 +451,27 @@ 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(); + // TODO invalidate sprites, not entire map + m_ts_tilemap[offset & 128 ? TM_TILES1 : TM_TILES0]->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(); - } + 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)) - { - 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_gfxdecode->gfx(TM_TILES1)->mark_all_dirty(); } + if (ram_addr >= PAGE4K(m_regs[V_PAGE]) && ram_addr < PAGE4K(m_regs[V_PAGE] + 1)) + 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)) + m_gfxdecode->gfx(TM_SPRITES)->mark_all_dirty(); + m_ram->write(ram_addr, data); } @@ -294,8 +482,8 @@ u16 tsconf_state::ram_read16(offs_t offset) void tsconf_state::ram_write16(offs_t offset, u16 data) { - m_ram->write(offset & 0xfffffffe, data >> 8); - m_ram->write(offset | 1, data & 0xff); + ram_page_write(0, offset & 0xfffffffe, data >> 8); + ram_page_write(0, offset | 1, data & 0xff); } u16 tsconf_state::spi_read16() @@ -305,9 +493,10 @@ u16 tsconf_state::spi_read16() 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))); + u16 dest = offset & 0x1ff; + m_cram->write(dest, data); + u8 pen = dest >> 1; + rgb_t rgb = from_pwm((m_cram->read(dest | 1) << 8 | m_cram->read(dest & 0x1fe))); m_palette->set_pen_color(pen, rgb); }; @@ -317,26 +506,37 @@ void tsconf_state::cram_write16(offs_t offset, u16 data) cram_write(offset | 1, data & 0xff); }; -void tsconf_state::tsconf_port_7ffd_w(u8 data) +void tsconf_state::sfile_write16(offs_t offset, u16 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; + u16 dest = offset & 0x1fe; + m_sfile->write(dest, data >> 8); + m_sfile->write(dest | 1, data & 0xff); +}; - /* update memory */ - tsconf_update_bank1(); - tsconf_update_video_mode(); +void tsconf_state::tsconf_port_7ffd_w(u8 data) +{ + // LOCK? BIT(data, 5); + u8 page3 = (m_regs[PAGE3] & ~0x07) | BIT(data, 0, 3); // 128K: 0..2 -> 0..2 + switch (BIT(m_regs[MEM_CONFIG], 6, 2)) + { + case 4: + page3 = (page3 & ~0x20) | (data & 0x20); // 1024K: 5 -> 5 + [[fallthrough]]; + case 0: + page3 = (page3 & ~0x18) | (BIT(data, 6, 2) << 3); // 512K: 6..7 -> 3..4 + break; + default: + break; + } + tsconf_port_xxaf_w(PAGE3 << 8, page3); + tsconf_port_xxaf_w(MEM_CONFIG << 8, (m_regs[MEM_CONFIG] & 0xfe) | BIT(data, 4)); // ROM128 + tsconf_port_xxaf_w(V_PAGE << 8, BIT(data, 3) ? 7 : 5); } -void tsconf_state::tsconf_port_fe_w(offs_t offset, u8 data) +void tsconf_state::tsconf_ula_w(offs_t offset, u8 data) { - m_regs[BORDER] = (data & 0x07) | 0xf0; spectrum_ula_w(offset, data); + tsconf_port_xxaf_w(BORDER << 8, (data & 0x07) | (m_regs[PAL_SEL] << 4)); } u8 tsconf_state::tsconf_port_xxaf_r(offs_t port) @@ -366,82 +566,66 @@ u8 tsconf_state::tsconf_port_xxaf_r(offs_t port) break; } - //LOGWARN("'tsconf': reg read %02X = %02x\n", nreg, data); + // 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; + // 1. Updates which effect is delayed till next scanline + bool delay_update = true; 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(); + // more registers which marked as *1 in the xls, but rest need to be tested + case G_X_OFFS_L: + case G_X_OFFS_H: + case G_Y_OFFS_L: + case G_Y_OFFS_H: + m_scanline_delayed_regs_update[static_cast(nreg)] = data; 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]); + default: + delay_update = false; break; + } + if (delay_update) + return; - case T1_G_PAGE: - m_gfxdecode->gfx(3)->set_source(m_ram->pointer() + PAGE4K(data)); - m_ts_tilemap[2]->mark_all_dirty(); - break; + bool val_changed = m_regs[nreg] != data; - 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]); + // 2. Updates which require some pre-work before change + switch (nreg) + { + case BORDER: + if (val_changed) + spectrum_UpdateScreenBitmap(); break; - case SG_PAGE: - m_gfxdecode->gfx(4)->set_source(m_ram->pointer() + PAGE4K(data)); - m_ts_tilemap[3]->mark_all_dirty(); + default: break; + } + m_regs[nreg] = data; + // 3. Even same value must be processed + switch (nreg) + { case MEM_CONFIG: - m_port_7ffd_data = (m_port_7ffd_data & 0xef) | (ROM128 << 4); - tsconf_update_bank1(); - break; - case PAGE0: - tsconf_update_bank1(); + tsconf_update_bank0(); break; case PAGE1: - m_bank2->set_base(m_ram->pointer() + PAGE4K(data)); + m_banks[1]->set_entry(data); break; case PAGE2: - m_bank3->set_base(m_ram->pointer() + PAGE4K(data)); + m_banks[2]->set_entry(data); break; case PAGE3: - m_bank4->set_base(m_ram->pointer() + PAGE4K(data)); - break; - - case BORDER: - spectrum_UpdateBorderBitmap(); + m_banks[3]->set_entry(data); break; case DMAS_ADDRESS_L: @@ -484,37 +668,80 @@ void tsconf_state::tsconf_port_xxaf_w(offs_t port, u8 data) m_dma->start_tx(((BIT(data, 7) << 3) | (data & 0x07)), BIT(data, 5), BIT(data, 4), BIT(data, 3)); break; + default: + break; + } + + // 3. Can skip update if value not changed + if (!val_changed) + return; + + 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)); + 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; - } + m_maincpu->set_clock(3.5_MHz_XTAL * (1 << (data & 0x03))); + m_regs[CACHE_CONFIG] = BIT(data, 2) ? 0x0f : 0x00; 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: + update_frame_timer(); + break; + + case FMAPS: + case PAL_SEL: + case TS_CONFIG: case INT_MASK: + // TODO + case FDD_VIRT: + case CACHE_CONFIG: break; default: - logerror("Unsupported reg write: %02X = %02x\n", nreg, data); break; } } @@ -561,7 +788,7 @@ void tsconf_state::tsconf_port_f7_w(offs_t offset, u8 data) { strcpy((char *)m_fx, "M.A.M.E."); PAIR16 m_ver; - m_ver.w = ((21 << 9) | (12 << 5) | 15); + m_ver.w = ((22 << 9) | (02 << 5) | 8); // y.m.d m_fx[0x0c] = m_ver.b.l; m_fx[0x0d] = m_ver.b.h; break; @@ -603,9 +830,9 @@ void tsconf_state::tsconf_port_57_zctr_w(offs_t port, u8 data) { for (u8 m = 0x80; m; m >>= 1) { - m_sdcard->spi_clock_w(CLEAR_LINE); //0-S R + 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 + m_sdcard->spi_clock_w(ASSERT_LINE); // 1-L W } } } @@ -622,6 +849,88 @@ void tsconf_state::tsconf_spi_miso_w(u8 data) m_zctl_di |= data; } +void tsconf_state::update_frame_timer() +{ + u16 vpos = OFFS_512(VS_INT_L); + u16 hpos = m_regs[HS_INT]; + if (hpos > 0 && vpos <= 319 && hpos <= 223) + { + // Only if not overlapping with scanline. Otherwise we need to prioritize. + m_frame_irq_timer->adjust(m_screen->time_until_pos(vpos, hpos << 1)); + } + else + { + m_frame_irq_timer->adjust(attotime::never); + } +} + +INTERRUPT_GEN_MEMBER(tsconf_state::tsconf_vblank_interrupt) +{ + update_frame_timer(); + m_line_irq_timer->adjust(attotime::zero); +} + +void tsconf_state::dma_ready(int line) +{ + if (BIT(m_regs[INT_MASK], 4)) + { + m_maincpu->set_input_line_and_vector(line, ASSERT_LINE, 0xfb); + m_irq_off_timer->adjust(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03)))); + } +} + +void tsconf_state::device_timer(emu_timer &timer, device_timer_id id, int param) +{ + switch (id) + { + case TIMER_IRQ_FRAME: + { + if (BIT(m_regs[INT_MASK], 0)) + { + m_maincpu->set_input_line_and_vector(0, ASSERT_LINE, 0xff); + m_irq_off_timer->adjust(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03)))); + } + break; + } + case TIMER_IRQ_SCANLINE: + { + for (const auto &[reg, val] : m_scanline_delayed_regs_update) + { + m_regs[reg] = val; + switch (reg) + { + case G_Y_OFFS_L: + case G_Y_OFFS_H: + m_rendering_gfx_y_offset = OFFS_512(G_Y_OFFS_L); + break; + + default: + break; + } + } + m_scanline_delayed_regs_update.clear(); + + u16 screen_vpos = m_screen->vpos(); + m_line_irq_timer->adjust(m_screen->time_until_pos(screen_vpos + 1)); + if (BIT(m_regs[INT_MASK], 1)) + { + m_maincpu->set_input_line_and_vector(0, ASSERT_LINE, 0xfd); + // Not quite precise. Scanline can't be skipped. + m_irq_off_timer->adjust(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03)))); + } + if (BIT(m_regs[INT_MASK], 0) && OFFS_512(VS_INT_L) == screen_vpos && m_regs[HS_INT] == 0) + { + m_maincpu->set_input_line_and_vector(0, ASSERT_LINE, 0xff); + m_irq_off_timer->adjust(m_maincpu->clocks_to_attotime(32 * (1 << (m_regs[SYS_CONFIG] & 0x03)))); + } + spectrum_UpdateScreenBitmap(); + break; + } + default: + spectrum_state::device_timer(timer, id, param); + } +} + u8 tsconf_state::beta_neutral_r(offs_t offset) { return m_program->read_byte(offset); @@ -634,7 +943,7 @@ u8 tsconf_state::beta_enable_r(offs_t offset) if (m_beta->started() /*&& !m_beta->is_active()*/) { m_beta->enable(); - tsconf_update_bank1(); + tsconf_update_bank0(); } } @@ -646,7 +955,7 @@ u8 tsconf_state::beta_disable_r(offs_t offset) if (m_beta->started() && m_beta->is_active()) { m_beta->disable(); - tsconf_update_bank1(); + tsconf_update_bank0(); } return m_program->read_byte(offset + 0x4000); -- cgit v1.2.3