From bf96defded71edc6a07ce4c79cf33538cbdf820f Mon Sep 17 00:00:00 2001 From: Andrei Holub Date: Wed, 25 Sep 2024 11:07:48 -0400 Subject: [PATCH] spg format + softlist --- hash/tsconf_betadisc_flop.xml | 416 ++++++++++++++++++++++- src/mame/sinclair/spec128.cpp | 7 + src/mame/sinclair/spec128.h | 1 + src/mame/sinclair/spec_snqk.cpp | 561 +++++++++++++++++++++++++++++--- src/mame/sinclair/spectrum.cpp | 4 +- src/mame/sinclair/spectrum.h | 36 +- src/mame/sinclair/tsconf.h | 2 + src/mame/sinclair/tsconf_m.cpp | 5 + 8 files changed, 973 insertions(+), 59 deletions(-) diff --git a/hash/tsconf_betadisc_flop.xml b/hash/tsconf_betadisc_flop.xml index d315425839eb6..36817e13398d6 100644 --- a/hash/tsconf_betadisc_flop.xml +++ b/hash/tsconf_betadisc_flop.xml @@ -5,10 +5,65 @@ license:CC0-1.0 --> + + Alter Ego + 2011 + <homebrew> + + + + + + + + + + + + Bomberman + 2012 + <homebrew> + + + + + + + + + + + + + Bruce Lee + 2015 + <homebrew> + + + + + + + + + + Chase + 2012 + <homebrew> + + + + + + + + + Copter v0.1 2012 - Wizart/DT + <homebrew> + @@ -16,10 +71,367 @@ license:CC0-1.0 + + Digger + 2016 + <homebrew> + + + + + + + + + + + + Edge Grinder v1.01 + 2018 + <homebrew> + + + + + + + + + + + + Jim Power Test + 201? + <homebrew> + + + + + + + + + + Lirus + 201? + <homebrew> + + + + + + + + + + + + + + + Touhou Zero. Lost Donation Box Incident + 201? + <homebrew> + + + + + + + + + + + + + + + MultiDude + 2014 + <homebrew> + + + + + + + + + + + + + Ninja Gaiden + 201? + <homebrew> + + + + + + + + + + Once Upon a Time in a Kingdom + 201? + <homebrew> + + + + + + + + + + + + + + + Otter & Smoker + 201? + <homebrew> + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ottifants + 201? + <homebrew> + + + + + + + + + + + + + + + + + PacPack + 2018 + <homebrew> + + + + + + + + + + Cannon Fodder Parallax + 201? + <homebrew> + + + + + + + + + + Sir Ababol + 201? + <homebrew> + + + + + + + + + + + + Socoban + 2015 + <homebrew> + + + + + + + + + + Sonic the Hedgehog + 201? + <homebrew> + + + + + + + + + + + Synchronization + 201? + Robus + + + + + + + + + + + + + T-circles + 201? + <homebrew> + + + + + + + + + + Tetris + 201? + <homebrew> + + + + + + + + + + TS-TechDemo + 2013 + Wizart/DT + + + + + + + + + + TSolitaire + 201? + ERA Creative Group (Multinational) + + + + + + + + + + + + + + + + + + + + + + + Uwol - Quest for Money + 2012 + <homebrew> + + + + + + + + + + + Wonder Boy + 201? + <homebrew> + + + + + + + + + + Xonix + 2012 + <homebrew> + + + + + + + + + + Zen Loops + 201? + <homebrew> + + + + + + + + ZX Battle City v1.4 (NoVDAC) 2020 - Marie Slip / n1k-o + <homebrew> + + diff --git a/src/mame/sinclair/spec128.cpp b/src/mame/sinclair/spec128.cpp index 8895627ffcbd9..7247d7ac23747 100644 --- a/src/mame/sinclair/spec128.cpp +++ b/src/mame/sinclair/spec128.cpp @@ -238,6 +238,13 @@ void spectrum_128_state::spectrum_128_port_7ffd_w(offs_t offset, uint8_t data) m_exp->iorq_w(offset | 1, data); } +void spectrum_128_state::bank3_set_page(u8 page) +{ + m_port_7ffd_data &= 0xf8; + m_port_7ffd_data |= page & 0x07; + spectrum_128_update_memory(); +} + void spectrum_128_state::spectrum_128_update_memory() { m_bank_rom[0]->set_entry(BIT(m_port_7ffd_data, 4)); diff --git a/src/mame/sinclair/spec128.h b/src/mame/sinclair/spec128.h index 44451e727e92a..a0ca7c41a7964 100644 --- a/src/mame/sinclair/spec128.h +++ b/src/mame/sinclair/spec128.h @@ -33,6 +33,7 @@ class spectrum_128_state : public spectrum_state virtual void machine_start() override; virtual void machine_reset() override; + virtual void bank3_set_page(u8 page) override; virtual void spectrum_128_update_memory() override; virtual rectangle get_screen_area() override; diff --git a/src/mame/sinclair/spec_snqk.cpp b/src/mame/sinclair/spec_snqk.cpp index 784dc7998c537..6035ab3429359 100644 --- a/src/mame/sinclair/spec_snqk.cpp +++ b/src/mame/sinclair/spec_snqk.cpp @@ -130,7 +130,8 @@ SNAPSHOT_LOAD_MEMBER(spectrum_state::snapshot_cb) } else if (image.is_filetype("sp")) { - if ((snapshot_data[0] != 'S' && snapshot_data[1] != 'P') && (snapshot_size != SP_NEW_SIZE_16K && snapshot_size != SP_NEW_SIZE_48K)) + if ((snapshot_data[0] != 'S' || snapshot_data[1] != 'P') + || (snapshot_size != SP_NEW_SIZE_16K && snapshot_size != SP_NEW_SIZE_48K)) { if (snapshot_size != SP_OLD_SIZE) return std::make_pair(image_error::INVALIDLENGTH, "Invalid .SP file size"); @@ -160,9 +161,9 @@ SNAPSHOT_LOAD_MEMBER(spectrum_state::snapshot_cb) } else if (image.is_filetype("sem")) { - if (snapshot_data[0] != 0x05 && snapshot_data[1] != 'S' && - snapshot_data[2] != 'P' && snapshot_data[3] != 'E' && - snapshot_data[4] != 'C' && snapshot_data[5] != '1') + if (snapshot_data[0] != 0x05 || snapshot_data[1] != 'S' + || snapshot_data[2] != 'P' || snapshot_data[3] != 'E' + || snapshot_data[4] != 'C' || snapshot_data[5] != '1') { if (snapshot_size != SEM_SIZE) return std::make_pair(image_error::INVALIDLENGTH, "Invalid .SEM file size"); @@ -192,8 +193,8 @@ SNAPSHOT_LOAD_MEMBER(spectrum_state::snapshot_cb) } else if (image.is_filetype("snx")) { - if (snapshot_data[0] != 'X' && snapshot_data[1] != 'S' && - snapshot_data[2] != 'N' && snapshot_data[3] != 'A') + if (snapshot_data[0] != 'X' || snapshot_data[1] != 'S' + || snapshot_data[2] != 'N' || snapshot_data[3] != 'A') return std::make_pair(image_error::INVALIDIMAGE, "Invalid .SNX file header"); setup_snx(&snapshot_data[0], snapshot_size); @@ -205,6 +206,15 @@ SNAPSHOT_LOAD_MEMBER(spectrum_state::snapshot_cb) setup_frz(&snapshot_data[0], snapshot_size); } + else if (image.is_filetype("spg")) + { + if (snapshot_data[32] != 'S' || snapshot_data[33] != 'p' || snapshot_data[34] != 'e' || snapshot_data[35] != 'c' + || snapshot_data[36] != 't' || snapshot_data[37] != 'r' || snapshot_data[38] != 'u' || snapshot_data[39] != 'm' + || snapshot_data[40] != 'P' || snapshot_data[41] != 'r' ||snapshot_data[42] != 'o' || snapshot_data[43] != 'g') + return std::make_pair(image_error::INVALIDIMAGE, "Invalid .SPG file header."); + + setup_spg(&snapshot_data[0], snapshot_size); + } else { setup_z80(&snapshot_data[0], snapshot_size); @@ -285,7 +295,7 @@ void spectrum_state::border_update(int data) #endif } -void spectrum_state::setup_sp(uint8_t *snapdata, uint32_t snapsize) +void spectrum_state::setup_sp(const uint8_t *snapdata, uint32_t snapsize) { int i, SP_OFFSET; uint8_t intr; @@ -484,7 +494,7 @@ void spectrum_state::setup_sp(uint8_t *snapdata, uint32_t snapsize) * in which case it is included twice. * *******************************************************************/ -void spectrum_state::setup_sna(uint8_t *snapdata, uint32_t snapsize) +void spectrum_state::setup_sna(const uint8_t *snapdata, uint32_t snapsize) { int i, j, usedbanks[8]; long bank_offset; @@ -702,7 +712,7 @@ void spectrum_state::setup_sna(uint8_t *snapdata, uint32_t snapsize) * 16640 49152 RAM dump * *******************************************************************/ -void spectrum_state::setup_ach(uint8_t *snapdata, uint32_t snapsize) +void spectrum_state::setup_ach(const uint8_t *snapdata, uint32_t snapsize) { int i; uint8_t intr; @@ -833,7 +843,7 @@ void spectrum_state::setup_ach(uint8_t *snapdata, uint32_t snapsize) * suffer from the same "top of the stack" bug as well as .SNA images. * *******************************************************************/ -void spectrum_state::setup_prg(uint8_t *snapdata, uint32_t snapsize) +void spectrum_state::setup_prg(const uint8_t *snapdata, uint32_t snapsize) { int i; uint8_t intr; @@ -1001,7 +1011,7 @@ void spectrum_state::setup_prg(uint8_t *snapdata, uint32_t snapsize) * suffer from the same "top of the stack" bug as well as .SNA images. * *******************************************************************/ -void spectrum_state::setup_plusd(uint8_t *snapdata, uint32_t snapsize) +void spectrum_state::setup_plusd(const uint8_t *snapdata, uint32_t snapsize) { int i, j; uint8_t intr; @@ -1167,7 +1177,7 @@ void spectrum_state::setup_plusd(uint8_t *snapdata, uint32_t snapsize) * Following these data, there are optional POKE blocks * *******************************************************************/ -void spectrum_state::setup_sem(uint8_t *snapdata, uint32_t snapsize) +void spectrum_state::setup_sem(const uint8_t *snapdata, uint32_t snapsize) { int i; uint8_t intr; @@ -1284,7 +1294,7 @@ void spectrum_state::setup_sem(uint8_t *snapdata, uint32_t snapsize) * 16412 49152 RAM dump * *******************************************************************/ -void spectrum_state::setup_sit(uint8_t *snapdata, uint32_t snapsize) +void spectrum_state::setup_sit(const uint8_t *snapdata, uint32_t snapsize) { int i; uint8_t intr; @@ -1412,7 +1422,7 @@ void spectrum_state::setup_sit(uint8_t *snapdata, uint32_t snapsize) * 49476 10 0x00 (reserved for future use) * *******************************************************************/ -void spectrum_state::setup_zx(uint8_t *snapdata, uint32_t snapsize) +void spectrum_state::setup_zx(const uint8_t *snapdata, uint32_t snapsize) { int i; uint8_t intr; @@ -1542,7 +1552,7 @@ void spectrum_state::setup_zx(uint8_t *snapdata, uint32_t snapsize) * 49181 2 HL' * *******************************************************************/ -void spectrum_state::setup_snp(uint8_t *snapdata, uint32_t snapsize) +void spectrum_state::setup_snp(const uint8_t *snapdata, uint32_t snapsize) { int i; uint8_t intr; @@ -1720,7 +1730,7 @@ void spectrum_state::setup_snp(uint8_t *snapdata, uint32_t snapsize) * length of the block. * *******************************************************************/ -void spectrum_state::snx_decompress_block(address_space &space, uint8_t *source, uint16_t dest, uint16_t size) +void spectrum_state::snx_decompress_block(address_space &space, const uint8_t *source, uint16_t dest, uint16_t size) { uint8_t counthi, countlo, compress, fill; uint16_t block = 0, count, i, j, numbytes; @@ -1766,7 +1776,357 @@ void spectrum_state::snx_decompress_block(address_space &space, uint8_t *source, } } -void spectrum_state::setup_snx(uint8_t *snapdata, uint32_t snapsize) +static u16 hrust_decompress_block(uint8_t *dest, const uint8_t *source, uint16_t size) +{ + class bb_stream + { + private: + const u8 *base; + const u8 *p; + int idx; + int len; + bool eof; + u16 bits; + + public: + bb_stream(const u8 *from, int block_size) + { + base = p = from; + + len = block_size; + idx = 0; + eof = false; + + bits = get_byte(); + bits += 256 * get_byte(); + } + + u8 get_byte() + { + if (p - base == len) + { + eof = true; + return 0; + } + return *p++; + } + + u8 get_bit() + { + u8 bit = BIT(bits, 15 - idx); + if (idx == 15) + { + bits = get_byte(); + bits += 256 * get_byte(); + } + + idx = (idx + 1) % 16; + return bit; + } + + u8 get_bits(int n) + { + u8 r = 0; + do + { + r = 2 * r + get_bit(); + } while (--n); + return r; + } + + bool error() { return eof; } + }; + + bb_stream s(source, size); + u8 *to = dest; + *to++ = s.get_byte(); + u8 no_bits = 2; + constexpr u8 mask[] = {0, 0, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0}; + + while (!s.error()) + { + while (s.get_bit()) + *to++ = s.get_byte(); + + u16 len = 0; + u8 bb /* = 0*/; + do + { + bb = s.get_bits(2); + len += bb; + } while (bb == 0x03 && len != 0x0f); + + short offset = 0; + if (len == 0) + { + offset = 0xfff8 + s.get_bits(3); + *to = to[offset]; + to++; + continue; + } + + if (len == 1) + { + u8 code = s.get_bits(2); + + if (code == 2) + { + u8 b = s.get_byte(); + if (b >= 0xe0) + { + b <<= 1; + ++b; // rlca + b ^= 2; // xor c + + if (b == 0xff) + { + ++no_bits; + continue; + } + + offset = 0xff00 + b - 0x0f; + *to = to[offset]; + to++; + *to++ = s.get_byte(); + *to = to[offset]; + to++; + continue; + } + offset = 0xff00 + b; + } + + if (code == 0 || code == 1) + { + offset = s.get_byte(); + offset += 256 * (code ? 0xfe : 0xfd); + } + if (code == 3) + offset = 0xffe0 + s.get_bits(5); + + for (u8 i = 0; i < 2; ++i) + { + *to = to[offset]; + to++; + } + continue; + } + + if (len == 3) + { + if (s.get_bit()) + { + offset = 0xfff0 + s.get_bits(4); + *to = to[offset]; + to++; + *to++ = s.get_byte(); + *to = to[offset]; + to++; + continue; + } + + if (s.get_bit()) + { + u8 noBytes = 6 + s.get_bits(4); + for (u8 i = 0; i < 2 * noBytes; ++i) + *to++ = s.get_byte(); + continue; + } + + len = s.get_bits(7); + if (len == 0x0f) + break; // EOF + if (len < 0x0f) + len = 256 * len + s.get_byte(); + } + + if (len == 2) + ++len; + + u8 code = s.get_bits(2); + + if (code == 1) + { + u8 b = s.get_byte(); + + if (b >= 0xe0) + { + if (len > 3) + return false; + + b <<= 1; + ++b; // rlca + b ^= 3; // xor c + + offset = 0xff00 + b - 0x0f; + + *to = to[offset]; + to++; + *to++ = s.get_byte(); + *to = to[offset]; + to++; + continue; + } + offset = 0xff00 + b; + } + + if (code == 0) + offset = 0xfe00 + s.get_byte(); + else if (code == 2) + offset = 0xffe0 + s.get_bits(5); + else if (code == 3) + { + offset = 256 * (mask[no_bits] + s.get_bits(no_bits)); + offset += s.get_byte(); + } + + for (u16 i = 0; i < len; ++i) + { + *to = to[offset]; + to++; + } + } + + return to - dest; +} + +static void mlz_decompress_block(uint8_t *dest, const uint8_t *source) +{ + class de_mlz + { + private: + const u8 *from; + u8 *to; + u8 bitstream; + int bitcount; + + public: + de_mlz(u8 *dst, const u8 *src) + { + from = src; + to = dst; + } + + void init_bitstream() + { + bitstream = get_byte(); + bitcount = 8; + } + + u8 get_byte() + { + return *from++; + } + + void put_byte(u8 val) + { + *to++ = val; + } + + void repeat(u32 disp, int num) + { + for (int i = 0; i < num; i++) + { + u8 val = *(to - disp); + put_byte(val); + } + } + + // gets specified number of bits from bitstream + // returns them LSB-aligned + u32 get_bits(int count) + { + u32 bits = 0; + while (count--) + { + if (bitcount--) + { + bits <<= 1; + bits |= 1 & (bitstream >> 7); + bitstream <<= 1; + } + else + { + init_bitstream(); + count++; // repeat loop once more + } + } + + return bits; + } + + int get_bigdisp() + { + u32 bits; + + // inter displacement + if (get_bits(1)) + { + bits = get_bits(4); + return 0x1100 - (bits << 8) - get_byte(); + } + + // shorter displacement + else + return 256 - get_byte(); + } + }; + + de_mlz s(dest, source); + u32 done = 0; + int i; + + // get first byte of packed file and write to output + s.put_byte(s.get_byte()); + + // second byte goes to bitstream + s.init_bitstream(); + + // actual depacking loop! + do + { + // get 1st bit - either OUTBYTE or beginning of LZ code + // OUTBYTE + if (s.get_bits(1)) + s.put_byte(s.get_byte()); + + // LZ code + else + { + switch (s.get_bits(2)) + { + case 0: // 000 + s.repeat(8 - s.get_bits(3), 1); + break; + + case 1: // 001 + s.repeat(256 - s.get_byte(), 2); + break; + + case 2: // 010 + s.repeat(s.get_bigdisp(), 3); + break; + + case 3: // 011 + // extract num of length bits + for (i = 1; !s.get_bits(1); i++) + ; + + // check for exit code + if (i == 9) + done = 1; + else if (i <= 7) + { + // get length bits itself + int bits = s.get_bits(i); + s.repeat(s.get_bigdisp(), 2 + (1 << i) + bits); + } + break; + } + } + } while (!done); +} + +void spectrum_state::setup_snx(const uint8_t *snapdata, uint32_t snapsize) { uint8_t intr; uint16_t data, addr; @@ -1917,7 +2277,7 @@ void spectrum_state::setup_snx(uint8_t *snapdata, uint32_t snapsize) * The 8 16K banks are stored in the order 5, 2, 0, 1, 3, 4, 6, 7 * *******************************************************************/ -void spectrum_state::setup_frz(uint8_t *snapdata, uint32_t snapsize) +void spectrum_state::setup_frz(const uint8_t *snapdata, uint32_t snapsize) { int i, j; uint8_t intr; @@ -2029,7 +2389,7 @@ void spectrum_state::setup_frz(uint8_t *snapdata, uint32_t snapsize) //logerror("Snapshot loaded.\nExecution resuming at bank:%d %s\n", m_port_7ffd_data & 0x07, m_maincpu->state_string(Z80_PC).c_str()); } -void spectrum_state::z80_decompress_block(address_space &space, uint8_t *source, uint16_t dest, uint16_t size) +void spectrum_state::z80_decompress_block(address_space &space, const uint8_t *source, uint16_t dest, uint16_t size) { uint8_t ch; int i; @@ -2089,7 +2449,7 @@ void spectrum_state::z80_decompress_block(address_space &space, uint8_t *source, while (size > 0); } -static SPECTRUM_Z80_SNAPSHOT_TYPE spectrum_identify_z80 (uint8_t *snapdata, uint32_t snapsize) +static SPECTRUM_Z80_SNAPSHOT_TYPE spectrum_identify_z80 (const uint8_t *snapdata, uint32_t snapsize) { uint8_t lo, hi, data; @@ -2137,7 +2497,7 @@ static SPECTRUM_Z80_SNAPSHOT_TYPE spectrum_identify_z80 (uint8_t *snapdata, uint } // supports 48k & 128k .Z80 files -void spectrum_state::setup_z80(uint8_t *snapdata, uint32_t snapsize) +void spectrum_state::setup_z80(const uint8_t *snapdata, uint32_t snapsize) { int i; uint8_t lo, hi, data; @@ -2289,7 +2649,6 @@ void spectrum_state::setup_z80(uint8_t *snapdata, uint32_t snapsize) } else { - uint8_t *pSource; int header_size; header_size = 30 + 2 + ((snapdata[30] & 0x0ff) | ((snapdata[31] & 0x0ff) << 8)); @@ -2311,29 +2670,28 @@ void spectrum_state::setup_z80(uint8_t *snapdata, uint32_t snapsize) ay8912->address_w(snapdata[38]); } - pSource = snapdata + header_size; - if (z80_type == SPECTRUM_Z80_SNAPSHOT_48K) // Ensure 48K Basic ROM is used page_basicrom(); + const uint8_t *p_source = snapdata + header_size; do { unsigned short length; uint8_t page; - int Dest = 0; + int dest = 0; - length = (pSource[0] & 0x0ff) | ((pSource[1] & 0x0ff) << 8); - page = pSource[2]; + length = (p_source[0] & 0x0ff) | ((p_source[1] & 0x0ff) << 8); + page = p_source[2]; if (z80_type == SPECTRUM_Z80_SNAPSHOT_48K || z80_type == SPECTRUM_Z80_SNAPSHOT_TS2068) { switch (page) { - case 4: Dest = 0x08000; break; - case 5: Dest = 0x0c000; break; - case 8: Dest = 0x04000; break; - default: Dest = 0; break; + case 4: dest = 0x08000; break; + case 5: dest = 0x0c000; break; + case 8: dest = 0x04000; break; + default: dest = 0; break; } } else @@ -2344,14 +2702,14 @@ void spectrum_state::setup_z80(uint8_t *snapdata, uint32_t snapsize) // Page the appropriate bank into 0xc000 - 0xfff m_port_7ffd_data = page - 3; update_paging(); - Dest = 0x0c000; + dest = 0x0c000; } else // Other values correspond to ROM pages - Dest = 0x0; + dest = 0x0; } - if (Dest != 0) + if (dest != 0) { if (length == 0x0ffff) { @@ -2360,21 +2718,21 @@ void spectrum_state::setup_z80(uint8_t *snapdata, uint32_t snapsize) // not compressed for (i = 0; i < 16384; i++) - space.write_byte(i + Dest, pSource[i]); + space.write_byte(i + dest, p_source[i]); } else { logerror("Compressed\n"); // block is compressed - z80_decompress_block(space, &pSource[3], Dest, 16384); + z80_decompress_block(space, &p_source[3], dest, 16384); } } // go to next block - pSource += (3 + length); + p_source += (3 + length); } - while ((pSource - snapdata) < snapsize); + while ((p_source - snapdata) < snapsize); if ((m_port_7ffd_data != -1) && (z80_type != SPECTRUM_Z80_SNAPSHOT_48K)) { @@ -2397,6 +2755,129 @@ void spectrum_state::setup_z80(uint8_t *snapdata, uint32_t snapsize) } } +/* + Load a .SPG (Spectrum Prog) file. + + v1.1: https://raw.githubusercontent.com/tslabs/zx-evo/master/pentevo/docs/Formats/SPGv1_1.txt + v1.0: https://raw.githubusercontent.com/tslabs/zx-evo/master/pentevo/docs/Formats/SPGv1_0.txt + v0.2 https://raw.githubusercontent.com/tslabs/zx-evo/master/pentevo/docs/Formats/SPGv0_2.txt +*/ +void spectrum_state::setup_spg(const u8 *snapdata, u32 snapsize) +{ + struct spg_v10 + { + char author[32]; + char magic[12]; + struct + { + u8 minor : 4; + u8 major : 4; + } version; + struct + { + u8 day; + u8 month; + u8 year; // 2000 + X + } date; + u16 pc; + u16 sp; + u8 win3_pg; + struct + { + u8 clock : 2; + u8 ei : 1; + u8 reserved : 5; + } cpu; + u16 pager_address; + u16 resident_address; + u16 blocks_num; + struct + { + u8 seconds; + u8 minutes; + u8 hours; + } time; + u8 reserved_1[17]; + char utility[32]; + u8 reserved_2[144]; + struct block + { + struct + { + u8 address512 : 5; // 0-#C000, 1f-#FE00 + u8 reserved_1 : 2; + bool is_last : 1; + }; + struct + { + u8 size512 : 5; // 0-512b, 1f-16kB + u8 reserved_2 : 1; + u8 compression : 2; // 0-NONE, 1-MLZ, 2-HRUST + }; + u8 page; // #00-#DF + } blocks[256]; + u8 data; + }; + + spg_v10* spg = (spg_v10*)snapdata; + + const u8 v_maj = spg->version.major; + const u8 v_min = spg->version.minor; + if (v_maj != 1 || v_min != 0) // just v1.0 for now + { + logerror("Can't load .SPG file v%d.%d\n", v_maj, v_min); + return; + } + + m_maincpu->set_state_int(Z80_IY, 0x5c3a); + m_maincpu->set_state_int(Z80_HL2, 0x2758); + m_maincpu->set_state_int(Z80_I, 0x3f); + m_maincpu->set_state_int(Z80_IM, 1); + m_port_7ffd_data = 16; + + m_maincpu->set_state_int(Z80_SP, spg->sp); + m_maincpu->set_state_int(Z80_PC, spg->pc); + m_maincpu->set_state_int(Z80_IFF1, spg->cpu.ei); + + bank3_set_page(spg->win3_pg); + + u8 *data = &spg->data; + for (u8 i = 0; i < spg->blocks_num; i++) + { + const u16 size = (spg->blocks[i].size512 + 1) * 512; + const u8 page = spg->blocks[i].page; + const u16 offs = (spg->blocks[i].address512) * 512; + if (m_ram->size() < ((page << 14) + size)) + { + logerror("Can't write to %d, only %d available\n", (page << 14) + size, m_ram->size()); + return; + } + switch (spg->blocks[i].compression) + { + case 0x00: + memcpy(m_ram->pointer() + (page << 14) + offs, data, size); + break; + + case 0x01: + mlz_decompress_block(m_ram->pointer() + (page << 14) + offs, data); + break; + + case 0x02: + hrust_decompress_block(m_ram->pointer() + (page << 14) + offs, data, size); + break; + + default: + // + logerror("Unsupported compression\n"); + return; + } + + data += size; + if (spg->blocks[i].is_last) + break; + } +} + QUICKLOAD_LOAD_MEMBER(spectrum_state::quickload_cb) { size_t quickload_size = image.length(); @@ -2451,7 +2932,7 @@ QUICKLOAD_LOAD_MEMBER(spectrum_state::quickload_cb) * SAVE "filename" CODE 16384,6144 * *******************************************************************/ -void spectrum_state::setup_scr(uint8_t *quickdata, uint32_t quicksize) +void spectrum_state::setup_scr(const uint8_t *quickdata, uint32_t quicksize) { address_space &space = m_maincpu->space(AS_PROGRAM); @@ -2487,7 +2968,7 @@ void spectrum_state::setup_scr(uint8_t *quickdata, uint32_t quicksize) * However, no image of such type has ever surfaced. * *******************************************************************/ -void spectrum_state::setup_raw(uint8_t *quickdata, uint32_t quicksize) +void spectrum_state::setup_raw(const uint8_t *quickdata, uint32_t quicksize) { address_space &space = m_maincpu->space(AS_PROGRAM); diff --git a/src/mame/sinclair/spectrum.cpp b/src/mame/sinclair/spectrum.cpp index 8af3df274a1b8..55dd33b49dde0 100644 --- a/src/mame/sinclair/spectrum.cpp +++ b/src/mame/sinclair/spectrum.cpp @@ -835,7 +835,9 @@ void spectrum_state::spectrum_common(machine_config &config) m_exp->fb_r_handler().set(FUNC(spectrum_state::floating_bus_r)); /* devices */ - SNAPSHOT(config, "snapshot", "ach,frz,plusd,prg,sem,sit,sna,snp,snx,sp,z80,zx").set_load_callback(FUNC(spectrum_state::snapshot_cb)); + SNAPSHOT(config, m_snapshot, "ach,frz,plusd,prg,sem,sit,sna,snp,snx,sp,z80,zx,spg"); + m_snapshot->set_load_callback(FUNC(spectrum_state::snapshot_cb)); + m_snapshot->set_interface("spectrum_snapshot"); QUICKLOAD(config, "quickload", "raw,scr", attotime::from_seconds(2)).set_load_callback(FUNC(spectrum_state::quickload_cb)); // The delay prevents the screen from being cleared by the RAM test at boot CASSETTE(config, m_cassette); diff --git a/src/mame/sinclair/spectrum.h b/src/mame/sinclair/spectrum.h index 8cee77b453cba..9f8d29586a397 100644 --- a/src/mame/sinclair/spectrum.h +++ b/src/mame/sinclair/spectrum.h @@ -54,6 +54,7 @@ class spectrum_state : public driver_device m_video_ram(*this, "video_ram"), m_maincpu(*this, "maincpu"), m_screen(*this, "screen"), + m_snapshot(*this, "snapshot"), m_cassette(*this, "cassette"), m_ram(*this, RAM_TAG), m_specmem(*this, "specmem"), @@ -90,6 +91,7 @@ class spectrum_state : public driver_device virtual void video_start() override; // until machine/spec_snqk.cpp gets somehow disentangled + virtual void bank3_set_page(u8 page) { } virtual void plus3_update_memory() { } virtual void spectrum_128_update_memory() { } virtual void ts2068_update_memory() { } @@ -154,6 +156,7 @@ class spectrum_state : public driver_device void spectrum_map(address_map &map); void spectrum_data(address_map &map); + optional_device m_snapshot; required_device m_cassette; required_device m_ram; optional_device m_specmem; @@ -193,25 +196,26 @@ class spectrum_state : public driver_device void update_paging(); void page_basicrom(); void border_update(int data); - void setup_sp(uint8_t *snapdata, uint32_t snapsize); - void setup_sna(uint8_t *snapdata, uint32_t snapsize); - void setup_ach(uint8_t *snapdata, uint32_t snapsize); - void setup_prg(uint8_t *snapdata, uint32_t snapsize); - void setup_plusd(uint8_t *snapdata, uint32_t snapsize); - void setup_sem(uint8_t *snapdata, uint32_t snapsize); - void setup_sit(uint8_t *snapdata, uint32_t snapsize); - void setup_zx(uint8_t *snapdata, uint32_t snapsize); - void setup_snp(uint8_t *snapdata, uint32_t snapsize); - void snx_decompress_block(address_space &space, uint8_t *source, uint16_t dest, uint16_t size); - void setup_snx(uint8_t *snapdata, uint32_t snapsize); - void setup_frz(uint8_t *snapdata, uint32_t snapsize); - void z80_decompress_block(address_space &space, uint8_t *source, uint16_t dest, uint16_t size); - void setup_z80(uint8_t *snapdata, uint32_t snapsize); + void setup_sp(const uint8_t *snapdata, uint32_t snapsize); + void setup_sna(const uint8_t *snapdata, uint32_t snapsize); + void setup_ach(const uint8_t *snapdata, uint32_t snapsize); + void setup_prg(const uint8_t *snapdata, uint32_t snapsize); + void setup_plusd(const uint8_t *snapdata, uint32_t snapsize); + void setup_sem(const uint8_t *snapdata, uint32_t snapsize); + void setup_sit(const uint8_t *snapdata, uint32_t snapsize); + void setup_zx(const uint8_t *snapdata, uint32_t snapsize); + void setup_snp(const uint8_t *snapdata, uint32_t snapsize); + void snx_decompress_block(address_space &space, const uint8_t *source, uint16_t dest, uint16_t size); + void setup_snx(const uint8_t *snapdata, uint32_t snapsize); + void setup_frz(const uint8_t *snapdata, uint32_t snapsize); + void z80_decompress_block(address_space &space, const uint8_t *source, uint16_t dest, uint16_t size); + void setup_z80(const uint8_t *snapdata, uint32_t snapsize); + void setup_spg(const u8 *snapdata, u32 snapsize); // quickload helpers void log_quickload(const char *type, uint32_t start, uint32_t length, uint32_t exec, const char *exec_format); - void setup_scr(uint8_t *quickdata, uint32_t quicksize); - void setup_raw(uint8_t *quickdata, uint32_t quicksize); + void setup_scr(const uint8_t *quickdata, uint32_t quicksize); + void setup_raw(const uint8_t *quickdata, uint32_t quicksize); }; /*----------- defined in drivers/spectrum.cpp -----------*/ diff --git a/src/mame/sinclair/tsconf.h b/src/mame/sinclair/tsconf.h index 70495c250dbf7..b0f5438b2d0ea 100644 --- a/src/mame/sinclair/tsconf.h +++ b/src/mame/sinclair/tsconf.h @@ -56,6 +56,8 @@ class tsconf_state : public spectrum_128_state virtual void machine_reset() override ATTR_COLD; virtual void device_post_load() override ATTR_COLD; + virtual void bank3_set_page(u8 page) override; + virtual TIMER_CALLBACK_MEMBER(irq_off) override; TIMER_CALLBACK_MEMBER(irq_frame); TIMER_CALLBACK_MEMBER(irq_scanline); diff --git a/src/mame/sinclair/tsconf_m.cpp b/src/mame/sinclair/tsconf_m.cpp index 92f9678fd1776..9e1da1dea1161 100644 --- a/src/mame/sinclair/tsconf_m.cpp +++ b/src/mame/sinclair/tsconf_m.cpp @@ -477,6 +477,11 @@ u8 tsconf_state::tsconf_port_xx1f_r(offs_t offset) { : 0x00; // TODO kempston read } +void tsconf_state::bank3_set_page(u8 page) +{ + tsconf_port_xxaf_w(PAGE3 << 8, page); +} + void tsconf_state::tsconf_port_7ffd_w(u8 data) { // LOCK? BIT(data, 5);