mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
357 lines
13 KiB
C++
357 lines
13 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Andrei I. Holub
|
|
/***************************************************************************
|
|
|
|
see: pentevo.cpp
|
|
|
|
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:
|
|
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)
|
|
|
|
TODO:
|
|
- Ram cache
|
|
|
|
****************************************************************************/
|
|
|
|
#include "emu.h"
|
|
#include "tsconf.h"
|
|
|
|
#include "bus/spectrum/zxbus.h"
|
|
#include "cpu/z80/z80.h"
|
|
#include "sound/ay8910.h"
|
|
#include "speaker.h"
|
|
|
|
|
|
ALLOW_SAVE_TYPE(tsconf_state::gluk_ext);
|
|
|
|
|
|
TILE_GET_INFO_MEMBER(tsconf_state::get_tile_info_txt)
|
|
{
|
|
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);
|
|
}
|
|
|
|
template <u8 Layer>
|
|
TILE_GET_INFO_MEMBER(tsconf_state::get_tile_info_16c)
|
|
{
|
|
const u8 col_offset = (tile_index & 0x03f) << 1;
|
|
const u16 row_offset = (tile_index & 0xfc0) << 2;
|
|
|
|
u8 *tile_info_addr = &m_ram->pointer()[(m_regs[T_MAP_PAGE] << 14) | row_offset | (Layer ? 0x80 : 0x00) | col_offset];
|
|
u8 hi = tile_info_addr[1];
|
|
|
|
u16 tile = ((u16(hi) & 0x0f) << 8) | tile_info_addr[0];
|
|
u8 pal = (BIT(m_regs[PAL_SEL], 4 + Layer * 2, 2) << 2) | BIT(hi, 4, 2);
|
|
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(m_bank_ram[0]).w(FUNC(tsconf_state::tsconf_bank_w<0>));
|
|
map(0x0000, 0x3fff).view(m_bank0_rom);
|
|
m_bank0_rom[0](0x0000, 0x3fff).bankr(m_bank_rom[0]);
|
|
|
|
map(0x4000, 0x7fff).bankr(m_bank_ram[1]).w(FUNC(tsconf_state::tsconf_bank_w<1>));
|
|
map(0x8000, 0xbfff).bankr(m_bank_ram[2]).w(FUNC(tsconf_state::tsconf_bank_w<2>));
|
|
map(0xc000, 0xffff).bankr(m_bank_ram[3]).w(FUNC(tsconf_state::tsconf_bank_w<3>));
|
|
}
|
|
|
|
void tsconf_state::tsconf_io(address_map &map)
|
|
{
|
|
map(0x0000, 0xffff).lrw8(
|
|
NAME([this](offs_t offset) { return m_ioext.read_byte((m_beta->dos_io_r() << 16) | offset); }),
|
|
NAME([this](offs_t offset, u8 data) { m_ioext.write_byte((m_beta->dos_io_r() << 16) | offset, data); }));
|
|
}
|
|
|
|
void tsconf_state::tsconf_ioext(address_map &map)
|
|
{
|
|
map.unmap_value_high();
|
|
map(0x0000, 0x0000).mirror(0x7ffd).w(FUNC(tsconf_state::tsconf_port_7ffd_w));
|
|
map(0x001f, 0x001f).mirror(0xff00).r(FUNC(tsconf_state::tsconf_port_xx1f_r));
|
|
map(0x0057, 0x0057).mirror(0xff00).rw(FUNC(tsconf_state::tsconf_port_57_zctr_r), FUNC(tsconf_state::tsconf_port_57_zctr_w)); // spi config
|
|
map(0x0077, 0x0077).mirror(0xff00).rw(FUNC(tsconf_state::tsconf_port_77_zctr_r), FUNC(tsconf_state::tsconf_port_77_zctr_w)); // spi data
|
|
map(0x00fe, 0x00fe).select(0xff00).rw(FUNC(tsconf_state::spectrum_ula_r), FUNC(tsconf_state::tsconf_ula_w));
|
|
map(0x00af, 0x00af).select(0xff00).rw(FUNC(tsconf_state::tsconf_port_xxaf_r), FUNC(tsconf_state::tsconf_port_xxaf_w));
|
|
map(0xfadf, 0xfadf).lr8(NAME([this]() -> u8 { return 0x80 | (m_io_mouse[2]->read() & 0x07); }));
|
|
map(0xfbdf, 0xfbdf).lr8(NAME([this]() -> u8 { return m_io_mouse[0]->read(); }));
|
|
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(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));
|
|
|
|
// IO: Shadow
|
|
map(0x0000, 0xffff).view(m_io_shadow_view);
|
|
m_io_shadow_view[0](0x0000, 0xffff).m(m_beta, FUNC(tsconf_beta_device::tsconf_beta_io));
|
|
}
|
|
|
|
void tsconf_state::tsconf_switch(address_map &map)
|
|
{
|
|
map(0x0000, 0x3fff).r(FUNC(tsconf_state::beta_neutral_r)); // Overlap with next because we want real addresses on the 3e00-3fff range
|
|
map(0x3d00, 0x3dff).r(FUNC(tsconf_state::beta_enable_r));
|
|
map(0x4000, 0xffff).r(FUNC(tsconf_state::beta_disable_r));
|
|
}
|
|
|
|
template <u8 Bank>
|
|
void tsconf_state::tsconf_bank_w(offs_t offset, u8 data)
|
|
{
|
|
tsconf_state::ram_bank_write(Bank, offset, data);
|
|
}
|
|
|
|
static const gfx_layout spectrum_charlayout =
|
|
{
|
|
8, 8, // 8 x 8 characters
|
|
96, // 96 characters
|
|
1, // 1 bits per pixel
|
|
{0}, // no bitplanes
|
|
{STEP8(0, 1)}, // x offsets
|
|
{STEP8(0, 8)}, // y offsets
|
|
8 * 8 // every char takes 8 bytes
|
|
};
|
|
|
|
static const gfx_layout tsconf_charlayout =
|
|
{
|
|
8, 8,
|
|
256,
|
|
1,
|
|
{0},
|
|
{STEP8(0, 1)},
|
|
{STEP8(0, 8)},
|
|
8 * 8
|
|
};
|
|
|
|
static GFXDECODE_START(gfx_tsconf)
|
|
GFXDECODE_ENTRY("maincpu", 0, tsconf_charlayout, 0xf7, 1) // TM_TS_CHAR : TXT
|
|
GFXDECODE_RAM("tiles0_raw", 0, gfx_8x8x8_raw, 0, 16) // TM_TILES0 : T0 16cpp
|
|
GFXDECODE_RAM("tiles1_raw", 0, gfx_8x8x8_raw, 0, 16) // TM_TILES1 : T1 16cpp
|
|
GFXDECODE_RAM("sprites_raw", 0, gfx_8x8x8_raw, 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_contention_pattern = {}; // disable inherited contention
|
|
|
|
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_gfxdecode->gfx(TM_TILES0)->set_granularity(16);
|
|
|
|
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_gfxdecode->gfx(TM_TILES1)->set_granularity(16);
|
|
|
|
m_gfxdecode->gfx(TM_SPRITES)->set_granularity(16);
|
|
|
|
m_frame_irq_timer = timer_alloc(FUNC(tsconf_state::irq_frame), this);
|
|
m_scanline_irq_timer = timer_alloc(FUNC(tsconf_state::irq_scanline), this);
|
|
}
|
|
|
|
void tsconf_state::machine_start()
|
|
{
|
|
spectrum_128_state::machine_start();
|
|
|
|
// reconfigure ROMs
|
|
memory_region *rom = memregion("maincpu");
|
|
m_bank_rom[0]->configure_entries(0, rom->bytes() / 0x4000, rom->base(), 0x4000);
|
|
m_bank_ram[0]->configure_entries(0, m_ram->size() / 0x4000, m_ram->pointer(), 0x4000);
|
|
|
|
save_item(NAME(m_int_mask));
|
|
save_item(NAME(m_update_on_m1));
|
|
save_pointer(NAME(m_regs), 0x100);
|
|
save_item(NAME(m_zctl_di));
|
|
save_item(NAME(m_zctl_cs));
|
|
save_item(NAME(m_port_f7_ext));
|
|
save_item(NAME(m_gfx_y_frame_offset));
|
|
save_item(NAME(m_ay_selected));
|
|
}
|
|
|
|
void tsconf_state::machine_reset()
|
|
{
|
|
m_update_on_m1 = false;
|
|
|
|
m_frame_irq_timer->adjust(attotime::never);
|
|
m_scanline_irq_timer->adjust(attotime::never);
|
|
m_int_mask = 0;
|
|
|
|
m_bank0_rom.select(0);
|
|
|
|
m_glukrs->disable();
|
|
|
|
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
|
|
|
|
m_beta->fddvirt_w(m_regs[FDD_VIRT] & 0x0f);
|
|
|
|
m_zctl_cs = 1;
|
|
m_zctl_di = 0xff;
|
|
m_ay_selected = 0;
|
|
|
|
m_sprites_cache.clear();
|
|
tsconf_update_bank0();
|
|
tsconf_update_video_mode();
|
|
|
|
m_keyboard->write(0xff);
|
|
while (m_keyboard->read() != 0) { /* invalidate buffer */ }
|
|
}
|
|
|
|
void tsconf_state::device_post_load()
|
|
{
|
|
spectrum_128_state::device_post_load();
|
|
m_sprites_cache.clear();
|
|
copy_tiles_to_raw(m_ram->pointer() + ((m_regs[SG_PAGE] & 0xf8) << 14), m_sprites_raw.target());
|
|
copy_tiles_to_raw(m_ram->pointer() + ((m_regs[T0_G_PAGE] & 0xf8) << 14), m_sprites_raw.target());
|
|
copy_tiles_to_raw(m_ram->pointer() + ((m_regs[T1_G_PAGE] & 0xf8) << 14), m_sprites_raw.target());
|
|
}
|
|
|
|
INPUT_PORTS_START( tsconf )
|
|
PORT_INCLUDE( spec_plus )
|
|
|
|
PORT_START("mouse_input1")
|
|
PORT_BIT(0xff, 0, IPT_MOUSE_X) PORT_SENSITIVITY(30)
|
|
|
|
PORT_START("mouse_input2")
|
|
PORT_BIT(0xff, 0, IPT_MOUSE_Y) PORT_SENSITIVITY(30)
|
|
|
|
PORT_START("mouse_input3")
|
|
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_NAME("Left mouse button") PORT_CODE(MOUSECODE_BUTTON1)
|
|
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("Right mouse button") PORT_CODE(MOUSECODE_BUTTON2)
|
|
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_BUTTON6) PORT_NAME("Middle mouse button") PORT_CODE(MOUSECODE_BUTTON3)
|
|
|
|
PORT_START("MOD_AY")
|
|
PORT_CONFNAME(0x01, 0x00, "AY MOD")
|
|
PORT_CONFSETTING(0x00, "Single")
|
|
PORT_CONFSETTING(0x01, "TurboSound")
|
|
INPUT_PORTS_END
|
|
|
|
void tsconf_state::tsconf(machine_config &config)
|
|
{
|
|
spectrum_128(config);
|
|
|
|
config.device_remove("exp");
|
|
config.device_remove("palette");
|
|
|
|
Z80(config.replace(), m_maincpu, 14_MHz_XTAL / 4);
|
|
m_maincpu->set_memory_map(&tsconf_state::tsconf_mem);
|
|
m_maincpu->set_io_map(&tsconf_state::tsconf_io);
|
|
m_maincpu->set_m1_map(&tsconf_state::tsconf_switch);
|
|
m_maincpu->set_irq_acknowledge_callback(FUNC(tsconf_state::irq_vector));
|
|
|
|
m_maincpu->set_vblank_int("screen", FUNC(tsconf_state::tsconf_vblank_interrupt));
|
|
|
|
SPI_SDCARD(config, m_sdcard, 0);
|
|
m_sdcard->set_prefer_sdhc();
|
|
m_sdcard->spi_miso_callback().set(FUNC(tsconf_state::tsconf_spi_miso_w));
|
|
|
|
zxbus_device &zxbus(ZXBUS(config, "zxbus", 0));
|
|
ZXBUS_SLOT(config, "zxbus1", 0, zxbus, zxbus_cards, nullptr);
|
|
//ZXBUS_SLOT(config, "zxbus2", 0, zxbus, zxbus_cards, nullptr);
|
|
|
|
m_ram->set_default_size("4096K");
|
|
|
|
GLUKRS(config, m_glukrs);
|
|
|
|
TSCONF_DMA(config, m_dma, 28_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));
|
|
|
|
TSCONF_BETA(config, m_beta, 0);
|
|
m_beta->out_dos_callback().set(FUNC(tsconf_state::update_io));
|
|
m_beta->out_vdos_m1_callback().set([this](int state) { m_update_on_m1 = true; });
|
|
|
|
SPEAKER(config, "lspeaker").front_left();
|
|
SPEAKER(config, "rspeaker").front_right();
|
|
|
|
config.device_remove("ay8912");
|
|
YM2149(config, m_ay[0], 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);
|
|
YM2149(config, m_ay[1], 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);
|
|
|
|
DAC_8BIT_R2R(config, m_dac, 0).add_route(ALL_OUTPUTS, "mono", 0.75);;
|
|
|
|
PALETTE(config, "palette", palette_device::BLACK, 256);
|
|
m_screen->set_raw(14_MHz_XTAL / 2, 448, with_hblank(0), 448, 320, with_vblank(0), 320);
|
|
m_screen->set_screen_update(FUNC(tsconf_state::screen_update));
|
|
m_screen->set_no_palette();
|
|
|
|
subdevice<gfxdecode_device>("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);
|
|
|
|
SOFTWARE_LIST(config, "betadisc_list_pent").set_original("spectrum_betadisc_flop");
|
|
SOFTWARE_LIST(config, "tsconf_list").set_original("tsconf");
|
|
}
|
|
|
|
ROM_START(tsconf)
|
|
ROM_REGION(0x080000, "maincpu", ROMREGION_ERASEFF) // ROM: 32 * 16KB
|
|
ROM_DEFAULT_BIOS("v2407")
|
|
|
|
ROM_SYSTEM_BIOS(0, "v1", "v1")
|
|
ROMX_LOAD("ts-bios.rom", 0, 0x10000, CRC(b060b0d9) SHA1(820d3539de115141daff220a3cb733fc880d1bab), ROM_BIOS(0))
|
|
|
|
ROM_SYSTEM_BIOS(1, "v2407", "Update 24.07.28")
|
|
ROMX_LOAD("ts-bios.240728.rom", 0, 0x10000, CRC(19f8ad7b) SHA1(9cee82d4a6212686358a50b0fd5a2981b3323ab6), ROM_BIOS(1))
|
|
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)
|