summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/formats/spec_snqk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/formats/spec_snqk.c')
-rw-r--r--src/mess/formats/spec_snqk.c2579
1 files changed, 2579 insertions, 0 deletions
diff --git a/src/mess/formats/spec_snqk.c b/src/mess/formats/spec_snqk.c
new file mode 100644
index 00000000000..959d8dd6895
--- /dev/null
+++ b/src/mess/formats/spec_snqk.c
@@ -0,0 +1,2579 @@
+/***************************************************************************
+
+ mess/formats/spec_snqk.c
+
+ TODO:
+
+ - Implement the following snapshot formats
+ .89C (Tezxas)
+ .SLT (Various emulators)
+ .SZX (Spectaculator)
+ .ZLS (ZX-Live!)
+ .ZX (ZXSpectr)
+ .ZX82 (Speculator '97)
+ .ZXS (ZX32)
+
+ - Implement the following quickload formats
+ .$? (HoBeta)
+ .__? (SpecEm)
+ .BAS (BASin)
+ .H/.B (Roman ZX)
+ .RAW (Various emulators)
+ .SCR variants
+
+ - Cleanup of the .Z80 format
+
+***************************************************************************/
+
+#include "emu.h"
+#include "ui.h"
+#include "cpu/z80/z80.h"
+#include "includes/spectrum.h"
+#include "sound/ay8910.h"
+#include "formats/spec_snqk.h"
+
+#define LOAD_REG(_cpu, _reg, _data) \
+ do { \
+ cpu_set_reg(_cpu, _reg, (_data)); \
+ } while (0)
+
+#define EXEC_NA "N/A"
+
+/*-------------------------------------------------
+ log_quickload - logs and displays useful
+ data for the end user
+-------------------------------------------------*/
+
+static void log_quickload(const char *type, UINT32 start, UINT32 length, UINT32 exec, const char *exec_format)
+{
+ astring tempstring;
+
+ logerror("Loading %04X bytes of RAM at %04X\n", length, start);
+
+ tempstring.catprintf("Quickload type: %s Length: %d bytes\n", type, length);
+ tempstring.catprintf("Start: 0x%04X End: 0x%04X Exec: ", start, start + length - 1);
+
+ logerror("Quickload loaded.\n");
+ if (!mame_stricmp(exec_format, EXEC_NA))
+ tempstring.cat("N/A");
+ else
+ {
+ logerror("Execution can resume with ");
+ logerror(exec_format, exec);
+ logerror("\n");
+ tempstring.catprintf(exec_format, exec);
+ }
+
+ ui_popup_time(10, "%s", tempstring.cstr());
+}
+
+/*******************************************************************
+ *
+ * Update the memory and paging of the spectrum being emulated
+ *
+ * if port_7ffd_data is -1 then machine is 48K - no paging
+ * if port_1ffd_data is -1 then machine is 128K
+ * if neither port is -1 then machine is +2a/+3
+ *
+ * Note: the 128K .SNA and .Z80 file formats do not store the
+ * port 1FFD setting so it is necessary to calculate the appropriate
+ * value for the ROM paging.
+ *
+ *******************************************************************/
+static void spectrum_update_paging(running_machine &machine)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ if (state->m_port_7ffd_data == -1)
+ return;
+ if (state->m_port_1ffd_data == -1)
+ spectrum_128_update_memory(machine);
+
+ else
+ {
+ if (BIT(state->m_port_7ffd_data, 4))
+ /* Page in Spec 48K basic ROM */
+ state->m_port_1ffd_data = 0x04;
+ else
+ state->m_port_1ffd_data = 0x00;
+ spectrum_plus3_update_memory(machine);
+ }
+}
+
+/* Page in the 48K Basic ROM. Used when running 48K snapshots on a 128K machine. */
+static void spectrum_page_basicrom(running_machine &machine)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ if (state->m_port_7ffd_data == -1)
+ return;
+ state->m_port_7ffd_data |= 0x10;
+ spectrum_update_paging(machine);
+}
+
+
+SNAPSHOT_LOAD(spectrum)
+{
+ UINT8 *snapshot_data = NULL;
+
+ snapshot_data = (UINT8*)malloc(snapshot_size);
+ if (!snapshot_data)
+ goto error;
+
+ image.fread(snapshot_data, snapshot_size);
+
+ if (!mame_stricmp(file_type, "sna"))
+ {
+ if ((snapshot_size != SNA48_SIZE) && (snapshot_size != SNA128_SIZE_1) && (snapshot_size != SNA128_SIZE_2))
+ {
+ logerror("Invalid .SNA file size.\n");
+ goto error;
+ }
+ spectrum_setup_sna(image.device().machine(), snapshot_data, snapshot_size);
+ }
+ else if (!mame_stricmp(file_type, "sp"))
+ {
+ 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)
+ {
+ logerror("Invalid .SP file size.\n");
+ goto error;
+ }
+ }
+ spectrum_setup_sp(image.device().machine(), snapshot_data, snapshot_size);
+ }
+ else if (!mame_stricmp(file_type, "ach"))
+ {
+ if (snapshot_size != ACH_SIZE)
+ {
+ logerror("Invalid .ACH file size.\n");
+ goto error;
+ }
+ spectrum_setup_ach(image.device().machine(), snapshot_data, snapshot_size);
+ }
+ else if (!mame_stricmp(file_type, "prg"))
+ {
+ if (snapshot_size != PRG_SIZE)
+ {
+ logerror("Invalid .PRG file size.\n");
+ goto error;
+ }
+ spectrum_setup_prg(image.device().machine(), snapshot_data, snapshot_size);
+ }
+ else if (!mame_stricmp(file_type, "plusd"))
+ {
+ if ((snapshot_size != PLUSD48_SIZE) && (snapshot_size != PLUSD128_SIZE))
+ {
+ logerror("Invalid .PLUSD file size.\n");
+ goto error;
+ }
+ spectrum_setup_plusd(image.device().machine(), snapshot_data, snapshot_size);
+ }
+ else if (!mame_stricmp(file_type, "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_size != SEM_SIZE)
+ {
+ logerror("Invalid .SEM file size.\n");
+ goto error;
+ }
+ }
+ spectrum_setup_sem(image.device().machine(), snapshot_data, snapshot_size);
+ }
+ else if (!mame_stricmp(file_type, "sit"))
+ {
+ if (snapshot_size != SIT_SIZE)
+ {
+ logerror("Invalid .SIT file size.\n");
+ goto error;
+ }
+ spectrum_setup_sit(image.device().machine(), snapshot_data, snapshot_size);
+ }
+ else if (!mame_stricmp(file_type, "zx"))
+ {
+ if (snapshot_size != ZX_SIZE)
+ {
+ logerror("Invalid .ZX file size.\n");
+ goto error;
+ }
+ spectrum_setup_zx(image.device().machine(), snapshot_data, snapshot_size);
+ }
+ else if (!mame_stricmp(file_type, "snp"))
+ {
+ if (snapshot_size != SNP_SIZE)
+ {
+ logerror("Invalid .SNP file size.\n");
+ goto error;
+ }
+ spectrum_setup_snp(image.device().machine(), snapshot_data, snapshot_size);
+ }
+ else if (!mame_stricmp(file_type, "snx"))
+ {
+ if (snapshot_data[0] != 'X' && snapshot_data[1] != 'S' && \
+ snapshot_data[2] != 'N' && snapshot_data[3] != 'A')
+ {
+ logerror("Invalid .SNX file size.\n");
+ goto error;
+ }
+ spectrum_setup_snx(image.device().machine(), snapshot_data, snapshot_size);
+ }
+ else if (!mame_stricmp(file_type, "frz"))
+ {
+ if (snapshot_size != FRZ_SIZE)
+ {
+ logerror("Invalid .FRZ file size.\n");
+ goto error;
+ }
+ spectrum_setup_frz(image.device().machine(), snapshot_data, snapshot_size);
+ }
+ else
+ {
+ spectrum_setup_z80(image.device().machine(), snapshot_data, snapshot_size);
+ }
+
+ free(snapshot_data);
+
+ return IMAGE_INIT_PASS;
+
+error:
+ if (snapshot_data)
+ free(snapshot_data);
+ return IMAGE_INIT_FAIL;
+}
+
+/*******************************************************************
+ *
+ * Load a .SP file.
+ *
+ * There are two kinds of .SP files: "old" and "new".
+ *
+ * The old version is always 49184 bytes long and is created
+ * by a leaked copy of the VGASpec emulator.
+ *
+ * Subsequently Pedro Gimeno (the author of VGASpec) renamed it
+ * to "Spectrum" (but it's colloquially known as the "Spanish
+ * Spectrum emulator") and extended the header to break backward
+ * compatibility: the new format supports both 16K and 48K
+ * images and it's 16422 or 49190 bytes long.
+ *
+ * http://www.formauri.es/personal/pgimeno/spec/spec.html
+ *
+ * The formats are defined as follows:
+ *
+ * Offset Size Description (all registers stored with LSB first)
+ * ------------------- ------- -------------------------------------------------
+ * VGASPEC SPECTRUM
+ * ------------------- ------- -------------------------------------------------
+ * N/A 0 2 "SP" (signature)
+ * N/A 2 2 Program length
+ * N/A 4 2 Program location
+ * 0 6 2 BC
+ * 2 8 2 DE
+ * 4 10 2 HL
+ * 6 12 2 AF
+ * 8 14 2 IX
+ * 10 16 2 IY
+ * 12 18 2 BC'
+ * 14 20 2 DE'
+ * 16 22 2 HL'
+ * 18 24 2 AF'
+ * 20 26 1 R
+ * 21 27 1 I
+ * 22 28 2 SP
+ * 24 30 2 PC
+ * 26 32 2 0x00 (reserved for future use)
+ * 28 34 1 Border color
+ * 29 35 1 0x00 (reserved for future use)
+ * 30 36 2 Status word
+ * 32 38 16384/ RAM dump
+ * 49152
+ *
+ * Status word:
+ * Bit Description
+ * ------- ---------------------------------------------------
+ * 15-8 Reserved for future use
+ * 7-6 Reserved for internal use (0)
+ * 5 Status of the flash attribute: 0=normal/1=inverse
+ * 4 Interrupt pending for execution
+ * 3 If 1, IM 0; if 0, bit 1 determines interrupt mode
+ * (Spectrum v0.99e had this behaviour reversed,
+ * and this bit was not used in versions previous
+ * to v 0.99e)
+ * 2 IFF2: 0=DI/1=EI
+ * 1 Interrupt mode (if bit 3 reset): 0=IM1/1=IM2
+ * 0 IFF1: 0=DI/1=EI
+ *
+ *******************************************************************/
+static void spectrum_border_update(running_machine &machine, int data)
+{
+ spectrum_EventList_Reset(machine);
+ spectrum_border_set_last_color(machine, data);
+ spectrum_border_force_redraw(machine);
+}
+
+void spectrum_setup_sp(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ int i, SP_OFFSET;
+ UINT8 intr;
+ UINT16 start, size, data, status;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ device_t *cpu = machine.device("maincpu");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ if (snapsize == SP_NEW_SIZE_16K || snapsize == SP_NEW_SIZE_48K)
+ {
+ SP_OFFSET = 0;
+ start = (snapdata[SP_OFFSET + 5] << 8) | snapdata[SP_OFFSET + 4];
+ size = (snapdata[SP_OFFSET + 3] << 8) | snapdata[SP_OFFSET + 2];
+ }
+ else
+ {
+ SP_OFFSET = SP_OLD_HDR - SP_NEW_HDR;
+ start = BASE_RAM;
+ size = 3*SPECTRUM_BANK;
+ }
+
+ data = (snapdata[SP_OFFSET + 13] << 8) | snapdata[SP_OFFSET + 12];
+ LOAD_REG(cpu, Z80_AF, data);
+
+ data = (snapdata[SP_OFFSET + 7] << 8) | snapdata[SP_OFFSET + 6];
+ LOAD_REG(cpu, Z80_BC, data);
+
+ data = (snapdata[SP_OFFSET + 9] << 8) | snapdata[SP_OFFSET + 8];
+ LOAD_REG(cpu, Z80_DE, data);
+
+ data = (snapdata[SP_OFFSET + 11] << 8) | snapdata[SP_OFFSET + 10];
+ LOAD_REG(cpu, Z80_HL, data);
+
+
+ data = (snapdata[SP_OFFSET + 25] << 8) | snapdata[SP_OFFSET + 24];
+ LOAD_REG(cpu, Z80_AF2, data);
+
+ data = (snapdata[SP_OFFSET + 19] << 8) | snapdata[SP_OFFSET + 18];
+ LOAD_REG(cpu, Z80_BC2, data);
+
+ data = (snapdata[SP_OFFSET + 21] << 8) | snapdata[SP_OFFSET + 20];
+ LOAD_REG(cpu, Z80_DE2, data);
+
+ data = (snapdata[SP_OFFSET + 23] << 8) | snapdata[SP_OFFSET + 22];
+ LOAD_REG(cpu, Z80_HL2, data);
+
+
+ data = (snapdata[SP_OFFSET + 15] << 8) | snapdata[SP_OFFSET + 14];
+ LOAD_REG(cpu, Z80_IX, data);
+
+ data = (snapdata[SP_OFFSET + 17] << 8) | snapdata[SP_OFFSET + 16];
+ LOAD_REG(cpu, Z80_IY, data);
+
+
+ data = snapdata[SP_OFFSET + 26];
+ LOAD_REG(cpu, Z80_R, data);
+
+ data = snapdata[SP_OFFSET + 27];
+ LOAD_REG(cpu, Z80_I, data);
+
+
+ data = (snapdata[SP_OFFSET + 29] << 8) | snapdata[SP_OFFSET + 28];
+ LOAD_REG(cpu, Z80_SP, data);
+
+ data = (snapdata[SP_OFFSET + 31] << 8) | snapdata[SP_OFFSET + 30];
+ LOAD_REG(cpu, Z80_PC, data);
+
+
+ status = (snapdata[SP_OFFSET + 37] << 8) | snapdata[SP_OFFSET + 36];
+
+ data = (BIT(status, 3) << 1) | BIT(status, 1);
+ switch(data)
+ {
+ case 0: // case 2: in version 0.99e of the emulator
+ LOAD_REG(cpu, Z80_IM, 1);
+ break;
+ case 1: // case 3: in version 0.99e of the emulator
+ LOAD_REG(cpu, Z80_IM, 2);
+ break;
+ case 2: // case 0: in version 0.99e of the emulator
+ case 3: // case 1: in version 0.99e of the emulator
+ LOAD_REG(cpu, Z80_IM, (UINT64)0);
+ }
+
+ data = BIT(status, 0);
+ LOAD_REG(cpu, Z80_IFF1, data);
+
+ data = BIT(status, 2);
+ LOAD_REG(cpu, Z80_IFF2, data);
+
+ intr = BIT(status, 4) ? ASSERT_LINE : CLEAR_LINE;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, intr);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ data = BIT(status, 5);
+ state->m_flash_invert = data;
+ logerror("FLASH state: %s\n", data ? "PAPER on INK" : "INK on PAPER");
+
+ /* Memory dump */
+ logerror("Loading %04X bytes of RAM at %04X\n", size, start);
+ for (i = 0; i < size; i++)
+ space->write_byte(start + i, snapdata[SP_OFFSET + SP_NEW_HDR + i]);
+
+ /* Set border color */
+ data = snapdata[SP_OFFSET + 34] & 0x07;
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ spectrum_page_basicrom(machine);
+
+ //logerror("Snapshot loaded.\nExecution resuming at %s\n", cpu_get_reg_string(cpu, Z80_PC));
+}
+
+/*******************************************************************
+ *
+ * Load a .SNA file.
+ *
+ * This format was used by Arnt Gulbrandsen for its JPP
+ * emulator, and it's based on the format used by the Mirage
+ * Microdriver, a Microdrive backup accessory.
+ *
+ * http://www.worldofspectrum.org/infoseekid.cgi?id=1000266
+ *
+ * The 48K image is always 49179 bytes long.
+ *
+ * .SNA snapshots save the PC on the top of the stack, thus
+ * deleting the original bytes: not a good feature for a snapshot...
+ *
+ * It's been reported that snapshots saved at critical moments would
+ * subsequently crash on restore due to the fact that the stack was full
+ * or pointed to a ROM address. A workaround for this situation is to
+ * store 0x0000 into the word where the PC was located.
+ *
+ * For sake of fidelity, the code that zeroes the top of the stack has
+ * been written but commented out.
+ *
+ * Later, the format has been extended to store the whole Spectrum 128 status.
+ *
+ * 48K format as follows:
+ *
+ * Offset Size Description (all registers stored with LSB first)
+ * ------- ------- -------------------------------------------------
+ * 0 1 I
+ * 1 2 HL'
+ * 3 2 DE'
+ * 5 2 BC'
+ * 7 2 AF'
+ * 9 2 HL
+ * 11 2 DE
+ * 13 2 BC
+ * 15 2 IY
+ * 17 2 IX
+ * 19 1 IFF1/2: bit 0 contains IFF1, bit 2 contains IFF2 (0=DI/1=EI)
+ * 20 1 R
+ * 21 2 AF
+ * 23 2 SP
+ * 25 1 Interrupt mode (0=IM0/1=IM1/2=IM2)
+ * 26 1 Border color
+ * 27 49152 RAM dump
+ *
+ * PC is stored on stack.
+ *
+ * 128K format as follows:
+ *
+ * Offset Size Description (all registers stored with LSB first)
+ * ------- ------- -------------------------------------------------
+ * 0 1 I
+ * 1 2 HL'
+ * 3 2 DE'
+ * 5 2 BC'
+ * 7 2 AF'
+ * 9 2 HL
+ * 11 2 DE
+ * 13 2 BC
+ * 15 2 IY
+ * 17 2 IX
+ * 19 1 IFF1/2: bit 0 contains IFF1, bit 2 contains IFF2 (0=DI/1=EI)
+ * 20 1 R
+ * 21 2 AF
+ * 23 2 SP
+ * 25 1 Interrupt mode (0=IM0/1=IM1/2=IM2)
+ * 26 1 Border color
+ * 27 16384 RAM bank 5 (0x4000-0x7fff)
+ * 16411 16384 RAM bank 2 (0x8000-0xbfff)
+ * 32795 16384 RAM bank n (0xc000-0xffff - currently paged bank)
+ * 49179 2 PC
+ * 49181 1 Port 0x7FFD data
+ * 49182 1 TR-DOS rom paged (0=no/1=yes)
+ * 49183 81920/ Remaining RAM banks in ascending order
+ * 98304
+ *
+ * PC is NOT stored on stack.
+ *
+ * The bank in 0xc000 is always included even if it is page 2 or 5
+ * in which case it is included twice.
+ *
+ *******************************************************************/
+void spectrum_setup_sna(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ int i, j, usedbanks[8];
+ long bank_offset;
+ UINT8 intr;
+ UINT16 data, addr;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ device_t *cpu = machine.device("maincpu");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ if ((snapsize != SNA48_SIZE) && (state->m_port_7ffd_data == -1))
+ {
+ logerror("Can't load 128K .SNA file into 48K machine\n");
+ return;
+ }
+
+
+ data = (snapdata[SNA48_OFFSET + 22] << 8) | snapdata[SNA48_OFFSET + 21];
+ LOAD_REG(cpu, Z80_AF, data);
+
+ data = (snapdata[SNA48_OFFSET + 14] << 8) | snapdata[SNA48_OFFSET + 13];
+ LOAD_REG(cpu, Z80_BC, data);
+
+ data = (snapdata[SNA48_OFFSET + 12] << 8) | snapdata[SNA48_OFFSET + 11];
+ LOAD_REG(cpu, Z80_DE, data);
+
+ data = (snapdata[SNA48_OFFSET + 10] << 8) | snapdata[SNA48_OFFSET + 9];
+ LOAD_REG(cpu, Z80_HL, data);
+
+
+ data = (snapdata[SNA48_OFFSET + 8] << 8) | snapdata[SNA48_OFFSET + 7];
+ LOAD_REG(cpu, Z80_AF2, data);
+
+ data = (snapdata[SNA48_OFFSET + 6] << 8) | snapdata[SNA48_OFFSET + 5];
+ LOAD_REG(cpu, Z80_BC2, data);
+
+ data = (snapdata[SNA48_OFFSET + 4] << 8) | snapdata[SNA48_OFFSET + 3];
+ LOAD_REG(cpu, Z80_DE2, data);
+
+ data = (snapdata[SNA48_OFFSET + 2] << 8) | snapdata[SNA48_OFFSET + 1];
+ LOAD_REG(cpu, Z80_HL2, data);
+
+
+ data = (snapdata[SNA48_OFFSET + 18] << 8) | snapdata[SNA48_OFFSET + 17];
+ LOAD_REG(cpu, Z80_IX, data);
+
+ data = (snapdata[SNA48_OFFSET + 16] << 8) | snapdata[SNA48_OFFSET + 15];
+ LOAD_REG(cpu, Z80_IY, data);
+
+
+ data = snapdata[SNA48_OFFSET + 20];
+ LOAD_REG(cpu, Z80_R, data);
+
+ data = snapdata[SNA48_OFFSET + 0];
+ LOAD_REG(cpu, Z80_I, data);
+
+
+ data = (snapdata[SNA48_OFFSET + 24] << 8) | snapdata[SNA48_OFFSET + 23];
+ LOAD_REG(cpu, Z80_SP, data);
+
+
+ data = snapdata[SNA48_OFFSET + 25] & 0x03;
+ if (data == 3)
+ data = 2;
+ LOAD_REG(cpu, Z80_IM, data);
+
+ data = snapdata[SNA48_OFFSET + 19];
+ LOAD_REG(cpu, Z80_IFF1, BIT(data, 0));
+ LOAD_REG(cpu, Z80_IFF2, BIT(data, 2));
+
+ intr = BIT(data, 0) ? CLEAR_LINE : ASSERT_LINE;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, intr);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ if (snapsize == SNA48_SIZE)
+ /* 48K Snapshot */
+ spectrum_page_basicrom(machine);
+ else
+ {
+ /* 128K Snapshot */
+ state->m_port_7ffd_data = snapdata[SNA128_OFFSET + 2];
+ logerror ("Port 7FFD:%02X\n", state->m_port_7ffd_data);
+ if (snapdata[SNA128_OFFSET + 3])
+ {
+ /* TODO: page TR-DOS ROM when supported */
+ }
+ spectrum_update_paging(machine);
+ }
+
+ if (snapsize == SNA48_SIZE)
+ {
+ /* Memory dump */
+ logerror("Loading %04X bytes of RAM at %04X\n", 3*SPECTRUM_BANK, BASE_RAM);
+ for (i = 0; i < 3*SPECTRUM_BANK; i++)
+ space->write_byte(BASE_RAM + i, snapdata[SNA48_HDR + i]);
+
+ /* Get PC from stack */
+ addr = cpu_get_reg(cpu, Z80_SP);
+
+ if (addr < BASE_RAM || addr > 4*SPECTRUM_BANK - 2)
+ logerror("Corrupted SP out of range:%04X", addr);
+ else
+ logerror("Fetching PC from the stack at SP:%04X\n", addr);
+
+ data = (space->read_byte(addr + 1) << 8) | space->read_byte(addr + 0);
+ LOAD_REG(cpu, Z80_PC, data);
+
+#if 0
+ space->write_byte(addr + 0, 0); // It's been reported that zeroing these locations fixes the loading
+ space->write_byte(addr + 1, 0); // of a few images that were snapshot at a "wrong" instant
+#endif
+
+ addr += 2;
+ logerror("Fixing SP:%04X\n", addr);
+ cpu_set_reg(cpu, Z80_SP, addr);
+
+ /* Set border color */
+ data = snapdata[SNA48_OFFSET + 26] & 0x07;
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ //logerror("Snapshot loaded.\nExecution resuming at %s\n", cpu_get_reg_string(cpu, Z80_PC));
+ }
+ else
+ {
+ /* Set up other RAM banks */
+ for (i = 0; i < 8; i++)
+ usedbanks[i] = 0;
+
+ usedbanks[5] = 1; /* 0x4000-0x7fff */
+ usedbanks[2] = 1; /* 0x8000-0xbfff */
+ usedbanks[state->m_port_7ffd_data & 0x07] = 1; /* Banked memory */
+
+ logerror("Loading %05X bytes of RAM at %04X\n", 8*SPECTRUM_BANK, BASE_RAM);
+ logerror("Loading bank 5 from offset:0001B\n");
+ logerror("Loading bank 2 from offset:0401B\n");
+ logerror("Loading bank %d from offset:0801B\n", snapdata[SNA128_OFFSET + 2] & 0x07);
+ for (i = 0; i < 3*SPECTRUM_BANK; i++)
+ space->write_byte(BASE_RAM + i, snapdata[SNA48_HDR + i]);
+
+ bank_offset = SNA48_SIZE + SNA128_HDR;
+ for (i = 0; i < 8; i++)
+ {
+ if (!usedbanks[i])
+ {
+ logerror("Loading bank %d from offset:%05lX\n", i, bank_offset);
+ state->m_port_7ffd_data &= 0xf8;
+ state->m_port_7ffd_data += i;
+ spectrum_update_paging(machine);
+ for (j = 0; j < SPECTRUM_BANK; j++)
+ space->write_byte(j + 3*SPECTRUM_BANK, snapdata[bank_offset + j]);
+ bank_offset += SPECTRUM_BANK;
+ }
+ }
+
+ /* program counter */
+ data = (snapdata[SNA128_OFFSET + 1] << 8) | snapdata[SNA128_OFFSET + 0];
+ LOAD_REG(cpu, Z80_PC, data);
+
+ /* Set border color */
+ data = snapdata[SNA48_OFFSET + 26] & 0x07;
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+ data = state->m_port_7ffd_data & 0x07;
+
+ /* Reset paging */
+ state->m_port_7ffd_data = snapdata[SNA128_OFFSET + 2];
+ spectrum_update_paging(machine);
+
+ //logerror("Snapshot loaded.\nExecution resuming at bank:%d %s\n", data, cpu_get_reg_string(cpu, Z80_PC));
+ }
+}
+
+/*******************************************************************
+ *
+ * Load a .ACH file.
+ *
+ * .ACH files were produced by a commercial Archimedes
+ * (hence the name) emulator called !Speccy.
+ *
+ * The files are always 65792 bytes long and store both
+ * a copy of the ROM and the whole 48K RAM.
+ *
+ *
+ * Offset Size Description (all registers stored with LSB first
+ * except when noted with *BE*)
+ * ------- ------- -------------------------------------------------
+ * 0 4 A
+ * 4 4 F
+ * 8 4 B
+ * 12 4 C
+ * 16 4 D
+ * 20 4 E
+ * 24 4 H
+ * 28 4 L
+ * 32 4 PC
+ * 36 4 0x00 (reserved for future use)
+ * 40 4 SP
+ * 44 104 0x00 (reserved for future use)
+ * 148 4 R
+ * 152 4 0x00 (reserved for future use)
+ * 156 4 Border color
+ * 160 4 0x00 (reserved for future use)
+ * 164 2 Interrupt mode (0=IM0/1=IM1/2=IM2)
+ * 166 24 0x00 (reserved for future use)
+ * 190 1 I
+ * 191 1 IFF1/2: (0=DI/1=EI)
+ * 192 44 0x00 (reserved for future use)
+ * 236 4 AF' *BE*
+ * 240 4 BC' *BE*
+ * 244 2 DE' *BE*
+ * 246 2 HL' *BE*
+ * 248 4 IX
+ * 252 4 IY
+ * 256 16384 ROM dump
+ * 16640 49152 RAM dump
+ *
+ *******************************************************************/
+void spectrum_setup_ach(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ int i;
+ UINT8 intr;
+ UINT16 data;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ device_t *cpu = machine.device("maincpu");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ data = (snapdata[ACH_OFFSET + 0] << 8) | snapdata[ACH_OFFSET + 4];
+ LOAD_REG(cpu, Z80_AF, data);
+
+ data = (snapdata[ACH_OFFSET + 8] << 8) | snapdata[ACH_OFFSET + 12];
+ LOAD_REG(cpu, Z80_BC, data);
+
+ data = (snapdata[ACH_OFFSET + 16] << 8) | snapdata[ACH_OFFSET + 20];
+ LOAD_REG(cpu, Z80_DE, data);
+
+ data = (snapdata[ACH_OFFSET + 24] << 8) | snapdata[ACH_OFFSET + 28];
+ LOAD_REG(cpu, Z80_HL, data);
+
+
+ data = (snapdata[ACH_OFFSET + 236] << 8) | snapdata[ACH_OFFSET + 237];
+ LOAD_REG(cpu, Z80_AF2, data);
+
+ data = (snapdata[ACH_OFFSET + 240] << 8) | snapdata[ACH_OFFSET + 241];
+ LOAD_REG(cpu, Z80_BC2, data);
+
+ data = (snapdata[ACH_OFFSET + 244] << 8) | snapdata[ACH_OFFSET + 245];
+ LOAD_REG(cpu, Z80_DE2, data);
+
+ data = (snapdata[ACH_OFFSET + 246] << 8) | snapdata[ACH_OFFSET + 247];
+ LOAD_REG(cpu, Z80_HL2, data);
+
+
+ data = (snapdata[ACH_OFFSET + 249] << 8) | snapdata[ACH_OFFSET + 248];
+ LOAD_REG(cpu, Z80_IX, data);
+
+ data = (snapdata[ACH_OFFSET + 253] << 8) | snapdata[ACH_OFFSET + 252];
+ LOAD_REG(cpu, Z80_IY, data);
+
+ data = snapdata[ACH_OFFSET + 148];
+ LOAD_REG(cpu, Z80_R, data);
+
+ data = snapdata[ACH_OFFSET + 190];
+ LOAD_REG(cpu, Z80_I, data);
+
+
+ data = (snapdata[ACH_OFFSET + 41] << 8) | snapdata[ACH_OFFSET + 40];
+ LOAD_REG(cpu, Z80_SP, data);
+
+ data = (snapdata[ACH_OFFSET + 33] << 8) | snapdata[ACH_OFFSET + 32];
+ LOAD_REG(cpu, Z80_PC, data);
+
+ data = snapdata[ACH_OFFSET + 164] & 0x03;
+ if (data == 3)
+ data = 0;
+ LOAD_REG(cpu, Z80_IM, data);
+
+ data = snapdata[ACH_OFFSET + 191] ? 1 : 0;
+ LOAD_REG(cpu, Z80_IFF1, data);
+ LOAD_REG(cpu, Z80_IFF2, data);
+
+ intr = snapdata[ACH_OFFSET + 191] ? CLEAR_LINE : ASSERT_LINE;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, intr);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ logerror("Skipping the 16K ROM dump at offset:%04X\n", ACH_OFFSET + 256);
+
+ /* Memory dump */
+ logerror("Loading %04X bytes of RAM at %04X\n", 3*SPECTRUM_BANK, BASE_RAM);
+ for (i = 0; i < 3*SPECTRUM_BANK; i++)
+ space->write_byte(BASE_RAM + i, snapdata[ACH_HDR + SPECTRUM_BANK + i]);
+
+ /* Set border color */
+ data = snapdata[ACH_OFFSET + 156] & 0x07;
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ spectrum_page_basicrom(machine);
+
+ //logerror("Snapshot loaded.\nExecution resuming at %s\n", cpu_get_reg_string(cpu, Z80_PC));
+}
+
+/*******************************************************************
+ *
+ * Load a .PRG file.
+ *
+ * .PRG files were produced by an irish emulator called SpecEm
+ * written by Kevin Phair (thanks for the help, Kevin!)
+ *
+ * http://code.google.com/p/specem/
+ *
+ * The files are always 49408 bytes long and use some stack space
+ * to store registers.
+ *
+ * The header actually mimics the file descriptor format used by
+ * the DISCiPLE/+D interface.
+ *
+ * Offset Size Description (all registers stored with LSB first
+ * except when noted with *BE*)
+ * ------- ------- -------------------------------------------------
+ * 0 1 File type (always 0x05, corresponding to "48K Snapshot"
+ * 1 10 Program name (padded with 0x20)
+ * 11 2 Number of sectors occupied by the file *BE*
+ * 13 1 Track number of the first sector of the file
+ * 14 1 Sector number of the first sector of the file
+ * 15 195 Sector allocation bitmap
+ * 210 10 0x00 (reserved for future use)
+ * 220 2 IY
+ * 222 2 IX
+ * 224 2 DE'
+ * 226 2 BC'
+ * 228 2 HL'
+ * 230 2 AF'
+ * 232 2 DE
+ * 234 2 BC
+ * 236 2 HL
+ * 238 1 Junk created when saving I via LD A,I/PUSH AF
+ * 239 1 I
+ * 240 2 SP
+ * 242 14 0x00 (reserved for future use)
+ * 256 49152 RAM dump
+ *
+ * IFF1/2, R, AF and PC are stored on the stack. Due to a bug in the
+ * BIOS, the snapshots created with the DISCiPLE have the AF' register
+ * replaced with the AF register.
+ *
+ * It's unknown (but likely possible) that the snapshots could
+ * suffer from the same "top of the stack" bug as well as .SNA images.
+ *
+ *******************************************************************/
+void spectrum_setup_prg(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ int i;
+ UINT8 intr;
+ UINT16 addr, data;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ device_t *cpu = machine.device("maincpu");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ data = snapdata[PRG_OFFSET + 0];
+ if (data != 0x05)
+ logerror("Wrong DISCiPLE/+D file type: %02X instead of 05\n", data);
+
+ data = (snapdata[PRG_OFFSET + 235] << 8) | snapdata[PRG_OFFSET + 234];
+ LOAD_REG(cpu, Z80_BC, data);
+
+ data = (snapdata[PRG_OFFSET + 233] << 8) | snapdata[PRG_OFFSET + 232];
+ LOAD_REG(cpu, Z80_DE, data);
+
+ data = (snapdata[PRG_OFFSET + 237] << 8) | snapdata[PRG_OFFSET + 236];
+ LOAD_REG(cpu, Z80_HL, data);
+
+
+ data = (snapdata[PRG_OFFSET + 231] << 8) | snapdata[PRG_OFFSET + 230];
+ LOAD_REG(cpu, Z80_AF2, data);
+
+ data = (snapdata[PRG_OFFSET + 227] << 8) | snapdata[PRG_OFFSET + 226];
+ LOAD_REG(cpu, Z80_BC2, data);
+
+ data = (snapdata[PRG_OFFSET + 225] << 8) | snapdata[PRG_OFFSET + 224];
+ LOAD_REG(cpu, Z80_DE2, data);
+
+ data = (snapdata[PRG_OFFSET + 229] << 8) | snapdata[PRG_OFFSET + 228];
+ LOAD_REG(cpu, Z80_HL2, data);
+
+
+ data = (snapdata[PRG_OFFSET + 223] << 8) | snapdata[PRG_OFFSET + 222];
+ LOAD_REG(cpu, Z80_IX, data);
+
+ data = (snapdata[PRG_OFFSET + 221] << 8) | snapdata[PRG_OFFSET + 220];
+ LOAD_REG(cpu, Z80_IY, data);
+
+ data = snapdata[PRG_OFFSET + 239];
+ LOAD_REG(cpu, Z80_I, data);
+
+ LOAD_REG(cpu, Z80_IM, (data == 0x00 || data == 0x3f) ? 1 : 2);
+
+ /* Memory dump */
+ logerror("Loading %04X bytes of RAM at %04X\n", 3*SPECTRUM_BANK, BASE_RAM);
+ for (i = 0; i < 3*SPECTRUM_BANK; i++)
+ space->write_byte(BASE_RAM + i, snapdata[PRG_HDR + i]);
+
+ addr = (snapdata[PRG_OFFSET + 241] << 8) | snapdata[PRG_OFFSET + 240];
+ if (addr < BASE_RAM || addr > 4*SPECTRUM_BANK - 6)
+ logerror("Corrupted SP out of range:%04X", addr);
+ else
+ logerror("Fetching registers IFF1/2, R, AF and PC from the stack at SP:%04X\n", addr);
+
+ data = space->read_byte(addr + 0); // IFF1/2: (bit 2, 0=DI/1=EI)
+ LOAD_REG(cpu, Z80_IFF1, BIT(data, 2));
+ LOAD_REG(cpu, Z80_IFF2, BIT(data, 2));
+
+ intr = BIT(data, 2) ? CLEAR_LINE : ASSERT_LINE;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, intr);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ data = space->read_byte(addr + 1);
+ LOAD_REG(cpu, Z80_R, data);
+
+ data = (space->read_byte(addr + 3) << 8) | space->read_byte(addr + 2);
+ LOAD_REG(cpu, Z80_AF, data);
+
+ data = (space->read_byte(addr + 5) << 8) | space->read_byte(addr + 4);
+ LOAD_REG(cpu, Z80_PC, data);
+
+#if 0
+ space->write_byte(addr + 0, 0); // It's been reported that zeroing these locations fixes the loading
+ space->write_byte(addr + 1, 0); // of a few images that were snapshot at a "wrong" instant
+ space->write_byte(addr + 2, 0);
+ space->write_byte(addr + 3, 0);
+ space->write_byte(addr + 4, 0);
+ space->write_byte(addr + 5, 0);
+#endif
+
+ addr += 6;
+ logerror("Fixing SP:%04X\n", addr);
+ cpu_set_reg(cpu, Z80_SP, addr);
+
+ /* Set border color */
+ data = (space->read_byte(0x5c48) >> 3) & 0x07; // Get the current border color from BORDCR system variable.
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ spectrum_page_basicrom(machine);
+
+ //logerror("Snapshot loaded.\nExecution resuming at %s\n", cpu_get_reg_string(cpu, Z80_PC));
+}
+
+/*******************************************************************
+ *
+ * Load a .PLUSD file.
+ *
+ * .PLUSD files are the snapshots produced by the DISCiPLE or
+ * the +D disk interface, thus share the same internal organization
+ * of the .PRG files, with a couple of notable exceptions:
+ *
+ * 1) The filesystem metadata is missing
+ * 2) Spectrum 128 snapshots (file type 9) are allowed
+ *
+ * A commented disassembly of both BIOSes is avilable at:
+ *
+ * http://www.biehold.nl/rudy/
+ *
+ * 48K snapshots are 49174 bytes long, 128K snapshots are 131095
+ * bytes long.
+ *
+ * Philip Kendall's FUSE emulator at http://fuse-emulator.sourceforge.net
+ * supports this format, but no extension is officially provided.
+ * Therefore I have used .PLUSD - corrections are welcome!
+ *
+ * 48K snapshot format
+ * -------------------
+ *
+ * Offset Size Description (all registers stored with LSB first
+ * ------- ------- -------------------------------------------------
+ * 0 2 IY
+ * 2 2 IX
+ * 4 2 DE'
+ * 6 2 BC'
+ * 8 2 HL'
+ * 10 2 AF'
+ * 12 2 DE
+ * 14 2 BC
+ * 16 2 HL
+ * 18 1 Junk created when saving I via LD A,I/PUSH AF
+ * 19 1 I
+ * 20 2 SP
+ * 22 49152 RAM dump
+ *
+ * 128K snapshot format
+ * --------------------
+ *
+ * Offset Size Description (all registers stored with LSB first
+ * ------- ------- -------------------------------------------------
+ * 0 2 IY
+ * 2 2 IX
+ * 4 2 DE'
+ * 6 2 BC'
+ * 8 2 HL'
+ * 10 2 AF'
+ * 12 2 DE
+ * 14 2 BC
+ * 16 2 HL
+ * 18 1 Junk created when saving I via LD A,I/PUSH AF
+ * 19 1 I
+ * 20 2 SP
+ * 22 1 Port 0x7FFD data
+ * 23 131072 RAM dump
+ *
+ * The 8 RAM banks are stored in the order 0-7.
+ *
+ * IFF1/2, R, AF and PC are stored on the stack. Due to a bug in the
+ * BIOS, the snapshots created with the DISCiPLE have the AF' register
+ * replaced with the AF register.
+ *
+ * It's unknown (but likely possible) that the snapshots could
+ * suffer from the same "top of the stack" bug as well as .SNA images.
+ *
+ *******************************************************************/
+void spectrum_setup_plusd(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ int i, j;
+ UINT8 intr;
+ UINT16 addr = 0, data;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ device_t *cpu = machine.device("maincpu");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ data = (snapdata[PLUSD_OFFSET + 15] << 8) | snapdata[PLUSD_OFFSET + 14];
+ LOAD_REG(cpu, Z80_BC, data);
+
+ data = (snapdata[PLUSD_OFFSET + 13] << 8) | snapdata[PLUSD_OFFSET + 12];
+ LOAD_REG(cpu, Z80_DE, data);
+
+ data = (snapdata[PLUSD_OFFSET + 17] << 8) | snapdata[PLUSD_OFFSET + 16];
+ LOAD_REG(cpu, Z80_HL, data);
+
+
+ data = (snapdata[PLUSD_OFFSET + 11] << 8) | snapdata[PLUSD_OFFSET + 10];
+ LOAD_REG(cpu, Z80_AF2, data);
+
+ data = (snapdata[PLUSD_OFFSET + 7] << 8) | snapdata[PLUSD_OFFSET + 6];
+ LOAD_REG(cpu, Z80_BC2, data);
+
+ data = (snapdata[PLUSD_OFFSET + 5] << 8) | snapdata[PLUSD_OFFSET + 4];
+ LOAD_REG(cpu, Z80_DE2, data);
+
+ data = (snapdata[PLUSD_OFFSET + 9] << 8) | snapdata[PLUSD_OFFSET + 8];
+ LOAD_REG(cpu, Z80_HL2, data);
+
+
+ data = (snapdata[PLUSD_OFFSET + 3] << 8) | snapdata[PLUSD_OFFSET + 2];
+ LOAD_REG(cpu, Z80_IX, data);
+
+ data = (snapdata[PLUSD_OFFSET + 1] << 8) | snapdata[PLUSD_OFFSET + 0];
+ LOAD_REG(cpu, Z80_IY, data);
+
+ data = snapdata[PLUSD_OFFSET + 19];
+ LOAD_REG(cpu, Z80_I, data);
+
+ LOAD_REG(cpu, Z80_IM, (data == 0x00 || data == 0x3f) ? 1 : 2);
+
+ if (snapsize == PLUSD48_SIZE)
+ {
+ spectrum_page_basicrom(machine);
+
+ /* Memory dump */
+ logerror("Loading %04X bytes of RAM at %04X\n", 3*SPECTRUM_BANK, BASE_RAM);
+ for (i = 0; i < 3*SPECTRUM_BANK; i++)
+ space->write_byte(BASE_RAM + i, snapdata[PLUSD48_HDR + i]);
+ }
+ else
+ {
+ logerror("Loading %05X bytes of RAM at %04X\n", 8*SPECTRUM_BANK, BASE_RAM);
+ for (i = 0; i < 8; i++)
+ {
+ switch (i)
+ {
+ case 5: addr = SPECTRUM_BANK;
+ break;
+ case 2: addr = 2*SPECTRUM_BANK;
+ break;
+ case 0:
+ case 1:
+ case 3:
+ case 4:
+ case 6:
+ case 7: addr = 3*SPECTRUM_BANK;
+ state->m_port_7ffd_data &= 0xf8;
+ state->m_port_7ffd_data += i;
+ spectrum_update_paging(machine);
+ break;
+ };
+ logerror("Loading bank %d from offset:%05X\n", i, PLUSD128_HDR + i*SPECTRUM_BANK);
+ for (j = 0; j < SPECTRUM_BANK; j++)
+ space->write_byte(j + addr, snapdata[j + PLUSD128_HDR + i*SPECTRUM_BANK]);
+ }
+ state->m_port_7ffd_data = snapdata[PLUSD_OFFSET + 22];
+ logerror ("Port 7FFD:%02X\n", state->m_port_7ffd_data);
+ logerror ("Paging bank:%d\n", state->m_port_7ffd_data & 0x07);
+ spectrum_update_paging(machine);
+ }
+
+ addr = (snapdata[PLUSD_OFFSET + 21] << 8) | snapdata[PLUSD_OFFSET + 20];
+ if (addr < BASE_RAM || addr > 4*SPECTRUM_BANK - 6)
+ logerror("Corrupted SP out of range:%04X", addr);
+ else
+ logerror("Fetching registers IFF1/2, R, AF and PC from the stack at SP:%04X\n", addr);
+
+ data = space->read_byte(addr + 0); // IFF1/2: (bit 2, 0=DI/1=EI)
+ LOAD_REG(cpu, Z80_IFF1, BIT(data, 2));
+ LOAD_REG(cpu, Z80_IFF2, BIT(data, 2));
+
+ intr = BIT(data, 2) ? CLEAR_LINE : ASSERT_LINE;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, intr);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ data = space->read_byte(addr + 1);
+ LOAD_REG(cpu, Z80_R, data);
+
+ data = (space->read_byte(addr + 3) << 8) | space->read_byte(addr + 2);
+ LOAD_REG(cpu, Z80_AF, data);
+
+ data = (space->read_byte(addr + 5) << 8) | space->read_byte(addr + 4);
+ LOAD_REG(cpu, Z80_PC, data);
+
+#if 0
+ space->write_byte(addr + 0, 0); // It's been reported that zeroing these locations fixes the loading
+ space->write_byte(addr + 1, 0); // of a few images that were snapshot at a "wrong" instant
+ space->write_byte(addr + 2, 0);
+ space->write_byte(addr + 3, 0);
+ space->write_byte(addr + 4, 0);
+ space->write_byte(addr + 5, 0);
+#endif
+
+ addr += 6;
+ logerror("Fixing SP:%04X\n", addr);
+ cpu_set_reg(cpu, Z80_SP, addr);
+
+ /* Set border color */
+ data = (space->read_byte(0x5c48) >> 3) & 0x07; // Get the current border color from BORDCR system variable.
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ //if (snapsize == PLUSD48_SIZE)
+ //logerror("Snapshot loaded.\nExecution resuming at %s\n", cpu_get_reg_string(cpu, Z80_PC));
+ //else
+ //logerror("Snapshot loaded.\nExecution resuming at bank:%d %s\n", state->m_port_7ffd_data & 0x07, cpu_get_reg_string(cpu, Z80_PC));
+}
+
+/*******************************************************************
+ *
+ * Load a .SEM file.
+ *
+ * .SEM files were produced by a german emulator called SpecEmu
+ * written by Bernd Waschke.
+ *
+ * The files are usually 49192 bytes long unless optional POKE
+ * blocks are stored at the end of the file.
+ *
+ * Offset Size Description (all registers stored with LSB first)
+ * ------- ------- -------------------------------------------------
+ * 0 1 0x05 (signature length)
+ * 1 5 "SPEC1" (signature)
+ * 6 49152 RAM dump
+ * 49158 2 AF
+ * 49160 2 BC
+ * 49162 2 DE
+ * 49164 2 HL
+ * 49166 2 AF'
+ * 49168 2 BC'
+ * 49170 2 DE'
+ * 49172 2 HL'
+ * 49174 2 PC
+ * 49176 2 SP
+ * 49178 2 IX
+ * 49180 2 IY
+ * 49182 2 I
+ * 49184 2 R
+ * 49186 2 IFF1 (0=DI/1=EI)
+ * 49188 2 IFF2 (0=DI/1=EI)
+ * 49190 2 Interrupt mode (0=IM0/1=IM1/2=IM2)
+ *
+ * Following these data, there are optional POKE blocks
+ *
+ *******************************************************************/
+void spectrum_setup_sem(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ int i;
+ UINT8 intr;
+ UINT16 data;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ device_t *cpu = machine.device("maincpu");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ data = (snapdata[SEM_OFFSET + 1] << 8) | snapdata[SEM_OFFSET + 0];
+ LOAD_REG(cpu, Z80_AF, data);
+
+ data = (snapdata[SEM_OFFSET + 3] << 8) | snapdata[SEM_OFFSET + 2];
+ LOAD_REG(cpu, Z80_BC, data);
+
+ data = (snapdata[SEM_OFFSET + 5] << 8) | snapdata[SEM_OFFSET + 4];
+ LOAD_REG(cpu, Z80_DE, data);
+
+ data = (snapdata[SEM_OFFSET + 7] << 8) | snapdata[SEM_OFFSET + 6];
+ LOAD_REG(cpu, Z80_HL, data);
+
+
+ data = (snapdata[SEM_OFFSET + 9] << 8) | snapdata[SEM_OFFSET + 8];
+ LOAD_REG(cpu, Z80_AF2, data);
+
+ data = (snapdata[SEM_OFFSET + 11] << 8) | snapdata[SEM_OFFSET + 10];
+ LOAD_REG(cpu, Z80_BC2, data);
+
+ data = (snapdata[SEM_OFFSET + 13] << 8) | snapdata[SEM_OFFSET + 12];
+ LOAD_REG(cpu, Z80_DE2, data);
+
+ data = (snapdata[SEM_OFFSET + 15] << 8) | snapdata[SEM_OFFSET + 14];
+ LOAD_REG(cpu, Z80_HL2, data);
+
+
+ data = (snapdata[SEM_OFFSET + 21] << 8) | snapdata[SEM_OFFSET + 20];
+ LOAD_REG(cpu, Z80_IX, data);
+
+ data = (snapdata[SEM_OFFSET + 23] << 8) | snapdata[SEM_OFFSET + 22];
+ LOAD_REG(cpu, Z80_IY, data);
+
+
+ data = snapdata[SEM_OFFSET + 26];
+ LOAD_REG(cpu, Z80_R, data);
+
+ data = snapdata[SEM_OFFSET + 24];
+ LOAD_REG(cpu, Z80_I, data);
+
+
+ data = (snapdata[SEM_OFFSET + 19] << 8) | snapdata[SEM_OFFSET + 18];
+ LOAD_REG(cpu, Z80_SP, data);
+
+ data = (snapdata[SEM_OFFSET + 17] << 8) | snapdata[SEM_OFFSET + 16];
+ LOAD_REG(cpu, Z80_PC, data);
+
+ data = snapdata[SEM_OFFSET + 32];
+ LOAD_REG(cpu, Z80_IM, data);
+
+ data = snapdata[SEM_OFFSET + 28];
+ LOAD_REG(cpu, Z80_IFF1, BIT(data, 0));
+ data = snapdata[SEM_OFFSET + 30];
+ LOAD_REG(cpu, Z80_IFF2, BIT(data, 0));
+
+ intr = BIT(snapdata[SEM_OFFSET + 30], 0) ? CLEAR_LINE : ASSERT_LINE;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, intr);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ /* Memory dump */
+ logerror("Loading %04X bytes of RAM at %04X\n", 3*SPECTRUM_BANK, BASE_RAM);
+ for (i = 0; i < 3*SPECTRUM_BANK; i++)
+ space->write_byte(BASE_RAM + i, snapdata[SEM_SIGNATURE + i]);
+
+ /* Set border color */
+ data = (space->read_byte(0x5c48) >> 3) & 0x07; // Get the current border color from BORDCR system variable.
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ spectrum_page_basicrom(machine);
+
+ //logerror("Snapshot loaded.\nExecution resuming at %s\n", cpu_get_reg_string(cpu, Z80_PC));
+
+/* TODO: Decode the optional POKE bank at the end of the image */
+
+}
+
+/*******************************************************************
+ *
+ * Load a .SIT file.
+ *
+ * .SIT files were produced by a spanish emulator called Sinclair
+ * written by Pedro M. R. Salas.
+ *
+ * http://www.ugr.es/~pedrom/sinclair.htm
+ *
+ * The files are always 65564 bytes long and store both ROM and RAM.
+ *
+ * Offset Size Description (all registers stored with LSB first)
+ * ------- ------- -------------------------------------------------
+ * 0 2 BC
+ * 2 2 DE
+ * 4 2 HL
+ * 6 2 AF
+ * 8 2 IX
+ * 10 2 IY
+ * 12 2 SP
+ * 14 2 PC
+ * 16 1 R
+ * 17 1 I
+ * 18 2 BC'
+ * 20 2 DE'
+ * 22 2 HL'
+ * 24 2 AF'
+ * 26 1 Interrupt mode (0=IM0/1=IM1/2=IM2)
+ * 27 1 Border color
+ * 28 16384 ROM dump
+ * 16412 49152 RAM dump
+ *
+ *******************************************************************/
+void spectrum_setup_sit(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ int i;
+ UINT8 intr;
+ UINT16 data;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ device_t *cpu = machine.device("maincpu");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ data = (snapdata[SIT_OFFSET + 7] << 8) | snapdata[SIT_OFFSET + 6];
+ LOAD_REG(cpu, Z80_AF, data);
+
+ data = (snapdata[SIT_OFFSET + 1] << 8) | snapdata[SIT_OFFSET + 0];
+ LOAD_REG(cpu, Z80_BC, data);
+
+ data = (snapdata[SIT_OFFSET + 3] << 8) | snapdata[SIT_OFFSET + 2];
+ LOAD_REG(cpu, Z80_DE, data);
+
+ data = (snapdata[SIT_OFFSET + 5] << 8) | snapdata[SIT_OFFSET + 4];
+ LOAD_REG(cpu, Z80_HL, data);
+
+
+ data = (snapdata[SIT_OFFSET + 25] << 8) | snapdata[SIT_OFFSET + 24];
+ LOAD_REG(cpu, Z80_AF2, data);
+
+ data = (snapdata[SIT_OFFSET + 19] << 8) | snapdata[SIT_OFFSET + 18];
+ LOAD_REG(cpu, Z80_BC2, data);
+
+ data = (snapdata[SIT_OFFSET + 21] << 8) | snapdata[SIT_OFFSET + 20];
+ LOAD_REG(cpu, Z80_DE2, data);
+
+ data = (snapdata[SIT_OFFSET + 23] << 8) | snapdata[SIT_OFFSET + 22];
+ LOAD_REG(cpu, Z80_HL2, data);
+
+
+ data = (snapdata[SIT_OFFSET + 9] << 8) | snapdata[SIT_OFFSET + 8];
+ LOAD_REG(cpu, Z80_IX, data);
+
+ data = (snapdata[SIT_OFFSET + 11] << 8) | snapdata[SIT_OFFSET + 10];
+ LOAD_REG(cpu, Z80_IY, data);
+
+
+ data = snapdata[SIT_OFFSET + 16];
+ LOAD_REG(cpu, Z80_R, data);
+
+ data = snapdata[SIT_OFFSET + 17];
+ LOAD_REG(cpu, Z80_I, data);
+
+
+ data = (snapdata[SIT_OFFSET + 13] << 8) | snapdata[SIT_OFFSET + 12];
+ LOAD_REG(cpu, Z80_SP, data);
+
+ data = (snapdata[SIT_OFFSET + 15] << 8) | snapdata[SIT_OFFSET + 14];
+ LOAD_REG(cpu, Z80_PC, data);
+
+ data = snapdata[SIT_OFFSET + 26];
+ LOAD_REG(cpu, Z80_IM, data);
+
+ data = 0x01; // .SIT snapshots don't specify whether interrupts are enabled or not, so I assume they are.
+ LOAD_REG(cpu, Z80_IFF1, data);
+ LOAD_REG(cpu, Z80_IFF2, data);
+
+ intr = data ? CLEAR_LINE : ASSERT_LINE;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, intr);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ /* Memory dump */
+ logerror("Skipping the 16K ROM dump at offset:%04X\n", SIT_OFFSET + 28);
+ logerror("Loading %04X bytes of RAM at %04X\n", 3*SPECTRUM_BANK, BASE_RAM);
+ for (i = 0; i < 3*SPECTRUM_BANK; i++)
+ space->write_byte(BASE_RAM + i, snapdata[SIT_HDR + SPECTRUM_BANK + i]);
+
+ /* Set border color */
+ data = snapdata[SIT_OFFSET + 27] & 0x07;
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ spectrum_page_basicrom(machine);
+
+ //logerror("Snapshot loaded.\nExecution resuming at %s\n", cpu_get_reg_string(cpu, Z80_PC));
+}
+
+/*******************************************************************
+ *
+ * Load a .ZX file.
+ *
+ * .ZX files were produced by the Amiga emulator called KGB
+ *
+ * The files are usually 49486 bytes and store at the beginning
+ * of the file the last 132 bytes of the ROM.
+ *
+ * Offset Size Description (all registers stored with MSB first)
+ * ------- ------- -------------------------------------------------
+ * 0 132 Last 132 bytes of ROM dump
+ * 132 49152 RAM dump
+ * 49284 132 0x00 (reserved for future use)
+ * 49416 10 Various KGB settings
+ * 49426 1 IFF1/2: (0=DI/1=EI)
+ * 49427 2 Reserved (must be 0x0003)
+ * 49429 1 KGB ColorMode (0=BW/1=Color)
+ * 49430 4 0x00 (reserved for future use)
+ * 49434 2 BC
+ * 49436 2 BC'
+ * 49438 2 DE
+ * 49440 2 DE'
+ * 49442 2 HL
+ * 49444 2 HL'
+ * 49446 2 IX
+ * 49448 2 IY
+ * 49450 1 I
+ * 49451 1 R
+ * 49452 3 0x00 (reserved for future use)
+ * 49455 1 A'
+ * 49456 1 0x00 (reserved for future use)
+ * 49457 1 A
+ * 49458 1 0x00 (reserved for future use)
+ * 49459 1 F'
+ * 49460 1 0x00 (reserved for future use)
+ * 49461 1 F
+ * 49462 2 0x00 (reserved for future use)
+ * 49464 2 PC
+ * 49466 2 0x00 (reserved for future use)
+ * 49468 2 SP
+ * 49470 2 KGB Soundmode (0=Simple/1=Pitch/2=RomOnly)
+ * 49472 2 KGB HaltMode (0=NoHalt/1=Halt)
+ * 49474 2 Interrupt mode (-1=IM0/0=IM1/1=IM2)
+ * 49476 10 0x00 (reserved for future use)
+ *
+ *******************************************************************/
+void spectrum_setup_zx(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ int i;
+ UINT8 intr;
+ UINT16 data, mode;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ device_t *cpu = machine.device("maincpu");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ logerror("Skipping last 132 bytes of the 16K ROM dump at offset:0000\n");
+
+ data = (snapdata[ZX_OFFSET + 173] << 8) | snapdata[ZX_OFFSET + 177];
+ LOAD_REG(cpu, Z80_AF, data);
+
+ data = (snapdata[ZX_OFFSET + 150] << 8) | snapdata[ZX_OFFSET + 151];
+ LOAD_REG(cpu, Z80_BC, data);
+
+ data = (snapdata[ZX_OFFSET + 154] << 8) | snapdata[ZX_OFFSET + 155];
+ LOAD_REG(cpu, Z80_DE, data);
+
+ data = (snapdata[ZX_OFFSET + 158] << 8) | snapdata[ZX_OFFSET + 159];
+ LOAD_REG(cpu, Z80_HL, data);
+
+
+ data = (snapdata[ZX_OFFSET + 171] << 8) | snapdata[ZX_OFFSET + 175];
+ LOAD_REG(cpu, Z80_AF2, data);
+
+ data = (snapdata[ZX_OFFSET + 152] << 8) | snapdata[ZX_OFFSET + 153];
+ LOAD_REG(cpu, Z80_BC2, data);
+
+ data = (snapdata[ZX_OFFSET + 156] << 8) | snapdata[ZX_OFFSET + 157];
+ LOAD_REG(cpu, Z80_DE2, data);
+
+ data = (snapdata[ZX_OFFSET + 160] << 8) | snapdata[ZX_OFFSET + 161];
+ LOAD_REG(cpu, Z80_HL2, data);
+
+
+ data = (snapdata[ZX_OFFSET + 162] << 8) | snapdata[ZX_OFFSET + 163];
+ LOAD_REG(cpu, Z80_IX, data);
+
+ data = (snapdata[ZX_OFFSET + 164] << 8) | snapdata[ZX_OFFSET + 165];
+ LOAD_REG(cpu, Z80_IY, data);
+
+
+ data = snapdata[ZX_OFFSET + 167];
+ LOAD_REG(cpu, Z80_R, data);
+
+ data = snapdata[ZX_OFFSET + 166];
+ LOAD_REG(cpu, Z80_I, data);
+
+
+ data = (snapdata[ZX_OFFSET + 184] << 8) | snapdata[ZX_OFFSET + 185];
+ LOAD_REG(cpu, Z80_SP, data);
+
+ data = (snapdata[ZX_OFFSET + 180] << 8) | snapdata[ZX_OFFSET + 181];
+ LOAD_REG(cpu, Z80_PC, data);
+
+ mode = (snapdata[ZX_OFFSET + 190] << 8) | snapdata[ZX_OFFSET + 191];
+ switch (mode)
+ {
+ case 0xffff:
+ LOAD_REG(cpu, Z80_IM, (UINT64)0);
+ break;
+ case 0x00:
+ LOAD_REG(cpu, Z80_IM, 1);
+ break;
+ case 0x01:
+ LOAD_REG(cpu, Z80_IM, 2);
+ break;
+ default:
+ logerror("Invalid IM:%04X\n", mode);
+ }
+
+ data = BIT(snapdata[ZX_OFFSET + 142], 0);
+ LOAD_REG(cpu, Z80_IFF1, data);
+ LOAD_REG(cpu, Z80_IFF2, data);
+
+ intr = BIT(snapdata[ZX_OFFSET + 142], 0) ? CLEAR_LINE : ASSERT_LINE;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, intr);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ /* Memory dump */
+ logerror("Loading %04X bytes of RAM at %04X\n", 3*SPECTRUM_BANK, BASE_RAM);
+ for (i = 0; i < 3*SPECTRUM_BANK; i++)
+ space->write_byte(BASE_RAM + i, snapdata[132 + i]);
+
+ /* Set border color */
+ data = (space->read_byte(0x5c48) >> 3) & 0x07; // Get the current border color from BORDCR system variable.
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ spectrum_page_basicrom(machine);
+
+ //logerror("Snapshot loaded.\nExecution resuming at %s\n", cpu_get_reg_string(cpu, Z80_PC));
+}
+
+/*******************************************************************
+ *
+ * Load a .SNP file.
+ *
+ * .SNP files were produced by a polish emulator called Nuclear ZX
+ * written by Radovan Garabik and Lubomir Salanci.
+ *
+ * http://korpus.juls.savba.sk/~garabik/old/zx.html
+ *
+ * The files are always 49183 bytes long.
+ *
+ * Offset Size Description (all registers stored with LSB first)
+ * ------- ------- -------------------------------------------------
+ * 0 49152 RAM dump
+ * 49152 2 AF
+ * 49154 1 Border color
+ * 49155 1 0x00 (reserved for future use)
+ * 49156 2 BC
+ * 49158 2 DE
+ * 49160 2 HL
+ * 49162 2 PC
+ * 49164 2 SP
+ * 49166 2 IX
+ * 49168 2 IY
+ * 49170 1 0x00 (reserved for IFF2 but not implemented)
+ * 49171 1 IFF1 (0=DI/other=EI)
+ * 49172 1 Interrupt mode (0=IM0/1=IM1/2=IM2)
+ * 49173 1 R
+ * 49174 1 I
+ * 49175 2 AF'
+ * 49177 2 BC'
+ * 49179 2 DE'
+ * 49181 2 HL'
+ *
+ *******************************************************************/
+void spectrum_setup_snp(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ int i;
+ UINT8 intr;
+ UINT16 data;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ device_t *cpu = machine.device("maincpu");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ data = (snapdata[SNP_OFFSET + 1] << 8) | snapdata[SNP_OFFSET + 0];
+ LOAD_REG(cpu, Z80_AF, data);
+
+ data = (snapdata[SNP_OFFSET + 5] << 8) | snapdata[SNP_OFFSET + 4];
+ LOAD_REG(cpu, Z80_BC, data);
+
+ data = (snapdata[SNP_OFFSET + 7] << 8) | snapdata[SNP_OFFSET + 6];
+ LOAD_REG(cpu, Z80_DE, data);
+
+ data = (snapdata[SNP_OFFSET + 9] << 8) | snapdata[SNP_OFFSET + 8];
+ LOAD_REG(cpu, Z80_HL, data);
+
+
+ data = (snapdata[SNP_OFFSET + 24] << 8) | snapdata[SNP_OFFSET + 23];
+ LOAD_REG(cpu, Z80_AF2, data);
+
+ data = (snapdata[SNP_OFFSET + 26] << 8) | snapdata[SNP_OFFSET + 25];
+ LOAD_REG(cpu, Z80_BC2, data);
+
+ data = (snapdata[SNP_OFFSET + 28] << 8) | snapdata[SNP_OFFSET + 27];
+ LOAD_REG(cpu, Z80_DE2, data);
+
+ data = (snapdata[SNP_OFFSET + 30] << 8) | snapdata[SNP_OFFSET + 29];
+ LOAD_REG(cpu, Z80_HL2, data);
+
+
+ data = (snapdata[SNP_OFFSET + 15] << 8) | snapdata[SNP_OFFSET + 14];
+ LOAD_REG(cpu, Z80_IX, data);
+
+ data = (snapdata[SNP_OFFSET + 17] << 8) | snapdata[SNP_OFFSET + 16];
+ LOAD_REG(cpu, Z80_IY, data);
+
+
+ data = snapdata[SNP_OFFSET + 21];
+ LOAD_REG(cpu, Z80_R, data);
+
+ data = snapdata[SNP_OFFSET + 22];
+ LOAD_REG(cpu, Z80_I, data);
+
+
+ data = (snapdata[SNP_OFFSET + 13] << 8) | snapdata[SNP_OFFSET + 12];
+ LOAD_REG(cpu, Z80_SP, data);
+
+ data = (snapdata[SNP_OFFSET + 11] << 8) | snapdata[SNP_OFFSET + 10];
+ LOAD_REG(cpu, Z80_PC, data);
+
+
+ data = snapdata[SNP_OFFSET + 20] & 0x03;
+ LOAD_REG(cpu, Z80_IM, data);
+
+ data = BIT(snapdata[SNP_OFFSET + 19], 0);
+ LOAD_REG(cpu, Z80_IFF1, data);
+ LOAD_REG(cpu, Z80_IFF2, data);
+
+ intr = BIT(snapdata[SNP_OFFSET + 19], 0) ? CLEAR_LINE : ASSERT_LINE;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, intr);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ /* Memory dump */
+ logerror("Loading %04X bytes of RAM at %04X\n", 3*SPECTRUM_BANK, BASE_RAM);
+ for (i = 0; i < 3*SPECTRUM_BANK; i++)
+ space->write_byte(BASE_RAM + i, snapdata[i]);
+
+ /* Set border color */
+ data = snapdata[SNP_OFFSET + 2] & 0x07;
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ spectrum_page_basicrom(machine);
+
+ //logerror("Snapshot loaded.\nExecution resuming at %s\n", cpu_get_reg_string(cpu, Z80_PC));
+}
+
+/*******************************************************************
+ *
+ * Load a .SNX file.
+ *
+ * .SNX files were produced by an Atari ST emulator called Specci
+ * written by Christian Gandler
+ *
+ * http://cd.textfiles.com/crawlycrypt1/apps/misc/zx_sp207/
+ *
+ * The header is an extension of the .SNA format and the RAM dump
+ * is compressed with a simple run-length algorithm.
+ *
+ * Offset Size Description (all registers stored with LSB first
+ * except when noted with *BE*)
+ * ------- ------- -------------------------------------------------
+ * 0 4 "XSNA" (signature)
+ * 4 2 Header length *BE*
+ * 6 1 I
+ * 7 2 HL'
+ * 9 2 DE'
+ * 11 2 BC'
+ * 13 2 AF'
+ * 15 2 HL
+ * 17 2 DE
+ * 19 2 BC
+ * 21 2 IY
+ * 23 2 IX
+ * 25 1 IFF1/2: bit 0 contains IFF1, bit 2 contains IFF2 (0=DI/1=EI)
+ * 26 1 R
+ * 27 2 AF
+ * 29 2 SP
+ * 31 1 Interrupt Mode (0=IM0/1=IM1/2=IM2)
+ * 32 1 Border color
+ * 33 1 Specci settings: Interface 1 (0=no/1=yes)
+ * 34 1 Specci settings: FLASH emulation (0=no/1=yes)
+ * 35 1 Specci settings: Attributes emulation (0=no/1=yes)
+ * 36 1 Specci settings: Bit 7 - Keyboard (0=QWERTY/1=QWERTZ)
+ * Bit 6 - ULA emulation (0=no/1=yes)
+ * Bit 0,1 - Joystick interface
+ * 00 = Kempston
+ * 01 = IF2 Left
+ * 10 = IF2 Right
+ * 11 = Cursor/AGF/Protek
+ * 37 1 Specci settings: R register emulation (0=no/1=yes)
+ * Bit 7 - EAR bit (0=Issue 3/1=Issue 2)
+ * 38 1 Specci settings: Interrupt frequency (0=50 Hz/1=100 Hz)
+ * 39 1 Specci settings: RS232 redirection (0=RS232/1=Centronics)
+ * 40 1 Specci settings: Sound emulation
+ * Bit 4,7 - Frequency (0..4) for mode 2
+ * Bit 0,3 - Mode (0=off/1=direct/2=interrupt)
+ * 41 1 Specci settings: Border emulation (0=off/1=direct/2=interrupt)
+ * 42 1 Specci settings: IM2 hardware vector (0..255)
+ * 43 ????? RAM dump
+ *
+ * PC is stored on stack.
+ *
+ * The RAM dump is divided into short or long datablocks:
+ * if the block is composed of the same byte, it is replaced by
+ * a compressed version. The format of the various blocks follows:
+ *
+ * Uncompressed short block
+ * ------------------------
+ * Offset Size Description
+ * ------- ------- -------------------------------------------------
+ * 0 1 Marker byte. Values between 0xe0 and 0xef.
+ * Low nibble is (block length - 1).
+ * 1 ????? Data block
+ *
+ * Compressed short block
+ * ----------------------
+ * Offset Size Description
+ * ------- ------- -------------------------------------------------
+ * 0 1 Marker byte. Values between 0xf0 and 0xff.
+ * Low nibble is (block length - 1).
+ * 1 1 Filler byte. This byte is repeated for the whole
+ * length of the block.
+ *
+ * Uncompressed long block
+ * -----------------------
+ * Offset Size Description
+ * ------- ------- -------------------------------------------------
+ * 0 2 Block length in big endian format.
+ * Values between 0x0000 and 0xdfff.
+ * 2 1 Uncompressed block flag: 0xff.
+ * 3 ????? Data block
+ *
+ * Compressed long block
+ * ---------------------
+ * Offset Size Description
+ * ------- ------- -------------------------------------------------
+ * 0 2 Block length in big endian format.
+ * Values between 0x0000 and 0xdfff.
+ * 2 1 Compressed block flag: 0x00.
+ * 3 1 Filler byte. This byte is repeated for the whole
+ * length of the block.
+ *
+ *******************************************************************/
+static void spectrum_snx_decompress_block(running_machine &machine, UINT8 *source, UINT16 dest, UINT16 size)
+{
+ UINT8 counthi, countlo, compress, fill;
+ UINT16 block = 0, count, i, j, numbytes;
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ i = SNX_HDR - 1;
+ numbytes = 0;
+
+ while (numbytes < size)
+ {
+ counthi = source[++i];
+ if (counthi >= 0xe0)
+ {
+ count = (counthi & 0x0f) + 1; // Short block
+ if ((counthi & 0xf0) == 0xf0)
+ compress = SNX_COMPRESSED;
+ else
+ compress = SNX_UNCOMPRESSED;
+ logerror("Block:%05d Type:Short Compr:%s Offset:%04X Len:%04X ", block++, compress == SNX_COMPRESSED ? "Y" : "N", i-1, count);
+ }
+ else
+ {
+ countlo = source[++i];
+ count = (counthi << 8) | countlo; // Long block
+ compress = source[++i];
+ logerror("Block:%05d Type:Long Compr:%s Offset:%04X Len:%04X ", block++, compress == SNX_COMPRESSED ? "Y" : "N", i-3, count);
+ }
+
+ if (compress == SNX_COMPRESSED)
+ {
+ fill = source[++i];
+ logerror("Dest:%04X Filler:%02X\n", BASE_RAM + numbytes, fill);
+ for(j = 0; j < count; j++)
+ space->write_byte(BASE_RAM + numbytes + j, fill);
+ numbytes += count;
+ }
+ else
+ {
+ logerror("Dest:%04X\n", BASE_RAM + numbytes);
+ j = 0;
+ while (j < count)
+ space->write_byte(BASE_RAM + numbytes + j++, source[++i]);
+ numbytes += count;
+ }
+ }
+}
+
+void spectrum_setup_snx(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ UINT8 intr;
+ UINT16 data, addr;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ device_t *cpu = machine.device("maincpu");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ data = (snapdata[SNX_OFFSET + 4] << 8) | snapdata[SNX_OFFSET + 5];
+ if (data != 0x25)
+ logerror("Corrupted header length: %02X instead of 0x25\n", data);
+
+ data = (snapdata[SNX_OFFSET + 28] << 8) | snapdata[SNX_OFFSET + 27];
+ LOAD_REG(cpu, Z80_AF, data);
+
+ data = (snapdata[SNX_OFFSET + 20] << 8) | snapdata[SNX_OFFSET + 19];
+ LOAD_REG(cpu, Z80_BC, data);
+
+ data = (snapdata[SNX_OFFSET + 18] << 8) | snapdata[SNX_OFFSET + 17];
+ LOAD_REG(cpu, Z80_DE, data);
+
+ data = (snapdata[SNX_OFFSET + 16] << 8) | snapdata[SNX_OFFSET + 15];
+ LOAD_REG(cpu, Z80_HL, data);
+
+
+ data = (snapdata[SNX_OFFSET + 14] << 8) | snapdata[SNX_OFFSET + 13];
+ LOAD_REG(cpu, Z80_AF2, data);
+
+ data = (snapdata[SNX_OFFSET + 12] << 8) | snapdata[SNX_OFFSET + 11];
+ LOAD_REG(cpu, Z80_BC2, data);
+
+ data = (snapdata[SNX_OFFSET + 10] << 8) | snapdata[SNX_OFFSET + 9];
+ LOAD_REG(cpu, Z80_DE2, data);
+
+ data = (snapdata[SNX_OFFSET + 8] << 8) | snapdata[SNX_OFFSET + 7];
+ LOAD_REG(cpu, Z80_HL2, data);
+
+
+ data = (snapdata[SNX_OFFSET + 24] << 8) | snapdata[SNX_OFFSET + 23];
+ LOAD_REG(cpu, Z80_IX, data);
+
+ data = (snapdata[SNX_OFFSET + 22] << 8) | snapdata[SNX_OFFSET + 21];
+ LOAD_REG(cpu, Z80_IY, data);
+
+
+ data = snapdata[SNX_OFFSET + 26];
+ LOAD_REG(cpu, Z80_R, data);
+
+ data = snapdata[SNX_OFFSET + 6];
+ LOAD_REG(cpu, Z80_I, data);
+
+
+ data = (snapdata[SNX_OFFSET + 30] << 8) | snapdata[SNX_OFFSET + 29];
+ LOAD_REG(cpu, Z80_SP, data);
+
+
+ data = snapdata[SNX_OFFSET + 31] & 0x03;
+ if (data == 3)
+ data = 2;
+ LOAD_REG(cpu, Z80_IM, data);
+
+ data = snapdata[SNX_OFFSET + 25];
+ LOAD_REG(cpu, Z80_IFF1, BIT(data, 0));
+ LOAD_REG(cpu, Z80_IFF2, BIT(data, 2));
+
+ intr = BIT(data, 0) ? CLEAR_LINE : ASSERT_LINE;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, intr);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ /* Memory dump */
+ logerror("Uncompressing %04X bytes of RAM at %04X\n", 3*SPECTRUM_BANK, BASE_RAM);
+ spectrum_snx_decompress_block(machine, snapdata, BASE_RAM, 3*SPECTRUM_BANK);
+
+ /* get pc from stack */
+ addr = cpu_get_reg(cpu, Z80_SP);
+
+ if (addr < BASE_RAM || addr > 4*SPECTRUM_BANK - 2)
+ logerror("Corrupted SP out of range:%04X", addr);
+ else
+ logerror("Fetching PC from the stack at SP:%04X\n", addr);
+
+ LOAD_REG(cpu, Z80_PC, (space->read_byte(addr + 1) << 8) | space->read_byte(addr + 0));
+
+#if 0
+ space->write_byte(addr + 0, 0); // It's been reported that zeroing these locations fixes the loading
+ space->write_byte(addr + 1, 0); // of a few images that were snapshot at a "wrong" instant
+#endif
+
+ addr += 2;
+ logerror("Fixed the stack at SP:%04X\n", addr);
+ cpu_set_reg(cpu, Z80_SP, addr);
+
+ /* Set border color */
+ data = snapdata[SNX_OFFSET + 32] & 0x07;
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ spectrum_page_basicrom(machine);
+
+/* TODO: Enable/disable IF1 as per snapdata[SNX_OFFSET + 33] */
+
+/* TODO: Enable/disable joysticks as per snapdata[SNX_OFFSET + 36] */
+
+/* TODO: Enable selection of Issue 2/3 config switch as per snapdata[SNX_OFFSET + 37] */
+
+ //logerror("Snapshot loaded.\nExecution resuming at %s\n", cpu_get_reg_string(cpu, Z80_PC));
+}
+
+/*******************************************************************
+ *
+ * Load a .FRZ file.
+ *
+ * .FRZ files were produced by the czech Amiga emulator CBSpeccy
+ * written by the CodeBusters. Kudos to Dmitriy Zhivilov and
+ * Ian Greenway for having reverse-engineered and shared the
+ * description of this format.
+ *
+ * The original specs of this format were published on a
+ * russian electronics magazine.
+ *
+ * The format is always 131114 bytes long and supports only
+ * Spectrum 128K images.
+ *
+ * Offset Size Description (all registers stored with MSB first)
+ * ------- ------- -------------------------------------------------
+ * 0 1 0x00 (reserved for future use)
+ * 1 1 Port 0x7FFD data
+ * 2 2 HL'
+ * 4 2 HL
+ * 6 2 DE'
+ * 8 2 DE
+ * 10 2 BC'
+ * 12 2 BC
+ * 14 2 AF'
+ * 16 2 AF
+ * 18 7 Emulation disk registers and T-states
+ * 25 1 R
+ * 26 2 PC
+ * 28 2 SP
+ * 30 1 I
+ * 31 1 0xFF (reserved for future use)
+ * 32 1 0x00 (reserved for future use)
+ * 33 1 Interrupt mode (0=IM0/1=IM1/2=IM2)
+ * 34 3 0x00 (reserved for future use)
+ * 37 1 IFF1: bit 2 contains IFF1 (0=DI/1=EI)
+ * 38 2 IY
+ * 40 2 IX
+ * 42 131072 RAM dump
+ *
+ * The 8 16K banks are stored in the order 5, 2, 0, 1, 3, 4, 6, 7
+ *
+ *******************************************************************/
+void spectrum_setup_frz(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ int i, j;
+ UINT8 intr;
+ UINT16 addr, data;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ device_t *cpu = machine.device("maincpu");
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ if (state->m_port_7ffd_data == -1)
+ {
+ logerror("Can't load 128K .FRZ file into 48K machine\n");
+ return;
+ }
+
+ data = (snapdata[FRZ_OFFSET + 16] << 8) | snapdata[FRZ_OFFSET + 17];
+ LOAD_REG(cpu, Z80_AF, data);
+
+ data = (snapdata[FRZ_OFFSET + 12] << 8) | snapdata[FRZ_OFFSET + 13];
+ LOAD_REG(cpu, Z80_BC, data);
+
+ data = (snapdata[FRZ_OFFSET + 8] << 8) | snapdata[FRZ_OFFSET + 9];
+ LOAD_REG(cpu, Z80_DE, data);
+
+ data = (snapdata[FRZ_OFFSET + 4] << 8) | snapdata[FRZ_OFFSET + 5];
+ LOAD_REG(cpu, Z80_HL, data);
+
+
+ data = (snapdata[FRZ_OFFSET + 14] << 8) | snapdata[FRZ_OFFSET + 15];
+ LOAD_REG(cpu, Z80_AF2, data);
+
+ data = (snapdata[FRZ_OFFSET + 10] << 8) | snapdata[FRZ_OFFSET + 11];
+ LOAD_REG(cpu, Z80_BC2, data);
+
+ data = (snapdata[FRZ_OFFSET + 6] << 8) | snapdata[FRZ_OFFSET + 7];
+ LOAD_REG(cpu, Z80_DE2, data);
+
+ data = (snapdata[FRZ_OFFSET + 2] << 8) | snapdata[FRZ_OFFSET + 3];
+ LOAD_REG(cpu, Z80_HL2, data);
+
+
+ data = (snapdata[FRZ_OFFSET + 40] << 8) | snapdata[FRZ_OFFSET + 41];
+ LOAD_REG(cpu, Z80_IX, data);
+
+ data = (snapdata[FRZ_OFFSET + 38] << 8) | snapdata[FRZ_OFFSET + 39];
+ LOAD_REG(cpu, Z80_IY, data);
+
+
+ data = snapdata[FRZ_OFFSET + 25];
+ LOAD_REG(cpu, Z80_R, data);
+
+ data = snapdata[FRZ_OFFSET + 30];
+ LOAD_REG(cpu, Z80_I, data);
+
+
+ data = (snapdata[FRZ_OFFSET + 28] << 8) | snapdata[FRZ_OFFSET + 29];
+ LOAD_REG(cpu, Z80_SP, data);
+
+ data = (snapdata[FRZ_OFFSET + 26] << 8) | snapdata[FRZ_OFFSET + 27];
+ LOAD_REG(cpu, Z80_PC, data);
+
+
+ data = snapdata[FRZ_OFFSET + 33];
+ LOAD_REG(cpu, Z80_IM, data);
+
+ data = snapdata[FRZ_OFFSET + 37];
+ LOAD_REG(cpu, Z80_IFF1, BIT(data, 2));
+ LOAD_REG(cpu, Z80_IFF2, BIT(data, 2));
+
+ intr = BIT(data, 2) ? CLEAR_LINE : ASSERT_LINE;
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, intr);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ /* Memory dump */
+ addr = 0;
+ static const UINT8 banks[] = { 5, 2, 0, 1, 3, 4, 6, 7 };
+ logerror("Loading %05X bytes of RAM at %04X\n", 8*SPECTRUM_BANK, BASE_RAM);
+ for (i = 0; i < 8; i++)
+ {
+ switch (banks[i])
+ {
+ case 5: addr = SPECTRUM_BANK;
+ break;
+ case 2: addr = 2*SPECTRUM_BANK;
+ break;
+ case 0:
+ case 1:
+ case 3:
+ case 4:
+ case 6:
+ case 7: addr = 3*SPECTRUM_BANK;
+ state->m_port_7ffd_data &= 0xf8;
+ state->m_port_7ffd_data += banks[i];
+ spectrum_update_paging(machine);
+ break;
+ };
+ logerror("Loading bank %d from offset:%05X\n", banks[i], FRZ_HDR + i*SPECTRUM_BANK);
+ for (j = 0; j < SPECTRUM_BANK; j++)
+ space->write_byte(j + addr, snapdata[j + FRZ_HDR + i*SPECTRUM_BANK]);
+ }
+ state->m_port_7ffd_data = snapdata[FRZ_OFFSET + 1];
+ logerror ("Port 7FFD:%02X\n", state->m_port_7ffd_data);
+ logerror ("Paging bank:%d\n", state->m_port_7ffd_data & 0x07);
+ spectrum_update_paging(machine);
+
+ /* Set border color */
+ data = (space->read_byte(0x5c48) >> 3) & 0x07; // Get the current border color from BORDCR system variable.
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ //logerror("Snapshot loaded.\nExecution resuming at bank:%d %s\n", state->m_port_7ffd_data & 0x07, cpu_get_reg_string(cpu, Z80_PC));
+}
+
+static void spectrum_z80_decompress_block(running_machine &machine,UINT8 *source, UINT16 dest, UINT16 size)
+{
+ UINT8 ch;
+ int i;
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ do
+ {
+ /* get byte */
+ ch = source[0];
+
+ /* either start 0f 0x0ed, 0x0ed, xx yy or single 0x0ed */
+ if (ch == 0x0ed)
+ {
+ if (source[1] == 0x0ed)
+ {
+ /* 0x0ed, 0x0ed, xx yy - repetition */
+ UINT8 count;
+ UINT8 data;
+
+ count = source[2];
+
+ if (count == 0)
+ return;
+
+ data = source[3];
+
+ source += 4;
+
+ if (count > size)
+ count = size;
+
+ size -= count;
+
+ for (i = 0; i < count; i++)
+ {
+ space->write_byte(dest, data);
+ dest++;
+ }
+ }
+ else
+ {
+ /* single 0x0ed */
+ space->write_byte(dest, ch);
+ dest++;
+ source++;
+ size--;
+ }
+ }
+ else
+ {
+ /* not 0x0ed */
+ space->write_byte(dest, ch);
+ dest++;
+ source++;
+ size--;
+ }
+ }
+ while (size > 0);
+}
+
+static SPECTRUM_Z80_SNAPSHOT_TYPE spectrum_identify_z80 (UINT8 *snapdata, UINT32 snapsize)
+{
+ UINT8 lo, hi, data;
+
+ if (snapsize < 30)
+ return SPECTRUM_Z80_SNAPSHOT_INVALID; /* Invalid file */
+
+ lo = snapdata[6] & 0x0ff;
+ hi = snapdata[7] & 0x0ff;
+ if (hi || lo)
+ return SPECTRUM_Z80_SNAPSHOT_48K_OLD; /* V1.45 - 48K only */
+
+ lo = snapdata[30] & 0x0ff;
+ hi = snapdata[31] & 0x0ff;
+ data = snapdata[34] & 0x0ff; /* Hardware mode */
+
+ if ((hi == 0) && (lo == 23))
+ { /* V2.01 */ /* V2.01 format */
+ switch (data)
+ {
+ case 0:
+ case 1: return SPECTRUM_Z80_SNAPSHOT_48K;
+ case 2: return SPECTRUM_Z80_SNAPSHOT_SAMRAM;
+ case 3:
+ case 4: return SPECTRUM_Z80_SNAPSHOT_128K;
+ case 128: return SPECTRUM_Z80_SNAPSHOT_TS2068;
+ }
+ }
+
+ if ((hi == 0) && (lo == 54))
+ { /* V3.0x */ /* V2.01 format */
+ switch (data)
+ {
+ case 0:
+ case 1:
+ case 3: return SPECTRUM_Z80_SNAPSHOT_48K;
+ case 2: return SPECTRUM_Z80_SNAPSHOT_SAMRAM;
+ case 4:
+ case 5:
+ case 6: return SPECTRUM_Z80_SNAPSHOT_128K;
+ case 128: return SPECTRUM_Z80_SNAPSHOT_TS2068;
+ }
+ }
+
+ return SPECTRUM_Z80_SNAPSHOT_INVALID;
+}
+
+/* now supports 48k & 128k .Z80 files */
+void spectrum_setup_z80(running_machine &machine, UINT8 *snapdata, UINT32 snapsize)
+{
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ int i;
+ UINT8 lo, hi, data;
+ SPECTRUM_Z80_SNAPSHOT_TYPE z80_type;
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ z80_type = spectrum_identify_z80(snapdata, snapsize);
+
+ switch (z80_type)
+ {
+ case SPECTRUM_Z80_SNAPSHOT_INVALID:
+ logerror("Invalid .Z80 file\n");
+ return;
+ case SPECTRUM_Z80_SNAPSHOT_48K_OLD:
+ case SPECTRUM_Z80_SNAPSHOT_48K:
+ logerror("48K .Z80 file\n");
+ if (!strcmp(machine.system().name,"ts2068"))
+ logerror("48K .Z80 file in TS2068\n");
+ break;
+ case SPECTRUM_Z80_SNAPSHOT_128K:
+ logerror("128K .Z80 file\n");
+ if (state->m_port_7ffd_data == -1)
+ {
+ logerror("Not a 48K .Z80 file\n");
+ return;
+ }
+ if (!strcmp(machine.system().name,"ts2068"))
+ {
+ logerror("Not a TS2068 .Z80 file\n");
+ return;
+ }
+ break;
+ case SPECTRUM_Z80_SNAPSHOT_TS2068:
+ logerror("TS2068 .Z80 file\n");
+ if (strcmp(machine.system().name,"ts2068"))
+ logerror("Not a TS2068 machine\n");
+ break;
+ case SPECTRUM_Z80_SNAPSHOT_SAMRAM:
+ logerror("Hardware not supported - .Z80 file\n");
+ return;
+ }
+
+ /* AF */
+ hi = snapdata[0] & 0x0ff;
+ lo = snapdata[1] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_AF, (hi << 8) | lo);
+ /* BC */
+ lo = snapdata[2] & 0x0ff;
+ hi = snapdata[3] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_BC, (hi << 8) | lo);
+ /* HL */
+ lo = snapdata[4] & 0x0ff;
+ hi = snapdata[5] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_HL, (hi << 8) | lo);
+
+ /* SP */
+ lo = snapdata[8] & 0x0ff;
+ hi = snapdata[9] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_SP, (hi << 8) | lo);
+
+ /* I */
+ cpu_set_reg(machine.device("maincpu"), Z80_I, (snapdata[10] & 0x0ff));
+
+ /* R */
+ data = (snapdata[11] & 0x07f) | ((snapdata[12] & 0x01) << 7);
+ cpu_set_reg(machine.device("maincpu"), Z80_R, data);
+
+ /* Set border color */
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | ((snapdata[12] & 0x0e) >> 1);
+ spectrum_border_update(machine, (snapdata[12] & 0x0e) >> 1);
+
+ lo = snapdata[13] & 0x0ff;
+ hi = snapdata[14] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_DE, (hi << 8) | lo);
+
+ lo = snapdata[15] & 0x0ff;
+ hi = snapdata[16] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_BC2, (hi << 8) | lo);
+
+ lo = snapdata[17] & 0x0ff;
+ hi = snapdata[18] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_DE2, (hi << 8) | lo);
+
+ lo = snapdata[19] & 0x0ff;
+ hi = snapdata[20] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_HL2, (hi << 8) | lo);
+
+ hi = snapdata[21] & 0x0ff;
+ lo = snapdata[22] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_AF2, (hi << 8) | lo);
+
+ lo = snapdata[23] & 0x0ff;
+ hi = snapdata[24] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_IY, (hi << 8) | lo);
+
+ lo = snapdata[25] & 0x0ff;
+ hi = snapdata[26] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_IX, (hi << 8) | lo);
+
+ /* Interrupt Flip/Flop */
+ if (snapdata[27] == 0)
+ {
+ cpu_set_reg(machine.device("maincpu"), Z80_IFF1, (UINT64)0);
+ /* cpu_set_reg(machine.device("maincpu"), Z80_IRQ_STATE, 0); */
+ }
+ else
+ {
+ cpu_set_reg(machine.device("maincpu"), Z80_IFF1, 1);
+ /* cpu_set_reg(machine.device("maincpu"), Z80_IRQ_STATE, 1); */
+ }
+
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_IRQ0, CLEAR_LINE);
+// cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, data);
+ cputag_set_input_line(machine, "maincpu", INPUT_LINE_HALT, CLEAR_LINE);
+
+ /* IFF2 */
+ if (snapdata[28] != 0)
+ {
+ data = 1;
+ }
+ else
+ {
+ data = 0;
+ }
+ cpu_set_reg(machine.device("maincpu"), Z80_IFF2, data);
+
+ /* Interrupt Mode */
+ cpu_set_reg(machine.device("maincpu"), Z80_IM, (snapdata[29] & 0x03));
+
+ if (z80_type == SPECTRUM_Z80_SNAPSHOT_48K_OLD)
+ {
+ lo = snapdata[6] & 0x0ff;
+ hi = snapdata[7] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_PC, (hi << 8) | lo);
+
+ spectrum_page_basicrom(machine);
+
+ if ((snapdata[12] & 0x020) == 0)
+ {
+ logerror("Not compressed\n"); /* not compressed */
+ for (i = 0; i < 49152; i++)
+ space->write_byte(i + 16384, snapdata[30 + i]);
+ }
+ else
+ {
+ logerror("Compressed\n"); /* compressed */
+ spectrum_z80_decompress_block(machine, snapdata + 30, 16384, 49152);
+ }
+ }
+ else
+ {
+ UINT8 *pSource;
+ int header_size;
+
+ header_size = 30 + 2 + ((snapdata[30] & 0x0ff) | ((snapdata[31] & 0x0ff) << 8));
+
+ lo = snapdata[32] & 0x0ff;
+ hi = snapdata[33] & 0x0ff;
+ cpu_set_reg(machine.device("maincpu"), Z80_PC, (hi << 8) | lo);
+
+ if ((z80_type == SPECTRUM_Z80_SNAPSHOT_128K) || ((z80_type == SPECTRUM_Z80_SNAPSHOT_TS2068) && !strcmp(machine.system().name,"ts2068")))
+ {
+ device_t *ay8912 = machine.device("ay8912");
+
+ /* Only set up sound registers for 128K machine or TS2068! */
+ for (i = 0; i < 16; i++)
+ {
+ ay8910_address_w(ay8912, 0, i);
+ ay8910_data_w(ay8912, 0, snapdata[39 + i]);
+ }
+ ay8910_address_w(ay8912, 0, snapdata[38]);
+ }
+
+ pSource = snapdata + header_size;
+
+ if (z80_type == SPECTRUM_Z80_SNAPSHOT_48K)
+ /* Ensure 48K Basic ROM is used */
+ spectrum_page_basicrom(machine);
+
+ do
+ {
+ unsigned short length;
+ UINT8 page;
+ int Dest = 0;
+
+ length = (pSource[0] & 0x0ff) | ((pSource[1] & 0x0ff) << 8);
+ page = pSource[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;
+ }
+ }
+ else
+ {
+ /* 3 = bank 0, 4 = bank 1 ... 10 = bank 7 */
+ if ((page >= 3) && (page <= 10))
+ {
+ /* Page the appropriate bank into 0xc000 - 0xfff */
+ state->m_port_7ffd_data = page - 3;
+ spectrum_update_paging(machine);
+ Dest = 0x0c000;
+ }
+ else
+ /* Other values correspond to ROM pages */
+ Dest = 0x0;
+ }
+
+ if (Dest != 0)
+ {
+ if (length == 0x0ffff)
+ {
+ /* block is uncompressed */
+ logerror("Not compressed\n");
+
+ /* not compressed */
+ for (i = 0; i < 16384; i++)
+ space->write_byte(i + Dest, pSource[i]);
+ }
+ else
+ {
+ logerror("Compressed\n");
+
+ /* block is compressed */
+ spectrum_z80_decompress_block(machine,&pSource[3], Dest, 16384);
+ }
+ }
+
+ /* go to next block */
+ pSource += (3 + length);
+ }
+ while ((pSource - snapdata) < snapsize);
+
+ if ((state->m_port_7ffd_data != -1) && (z80_type != SPECTRUM_Z80_SNAPSHOT_48K))
+ {
+ /* Set up paging */
+ state->m_port_7ffd_data = (snapdata[35] & 0x0ff);
+ spectrum_update_paging(machine);
+ }
+ if ((z80_type == SPECTRUM_Z80_SNAPSHOT_48K) && !strcmp(machine.system().name,"ts2068"))
+ {
+ state->m_port_f4_data = 0x03;
+ state->m_port_ff_data = 0x00;
+ ts2068_update_memory(machine);
+ }
+ if (z80_type == SPECTRUM_Z80_SNAPSHOT_TS2068 && !strcmp(machine.system().name,"ts2068"))
+ {
+ state->m_port_f4_data = snapdata[35];
+ state->m_port_ff_data = snapdata[36];
+ ts2068_update_memory(machine);
+ }
+ }
+}
+
+QUICKLOAD_LOAD(spectrum)
+{
+ UINT8 *quickload_data = NULL;
+
+ quickload_data = (UINT8*)malloc(quickload_size);
+ if (!quickload_data)
+ goto error;
+
+ image.fread(quickload_data, quickload_size);
+
+ if (!mame_stricmp(file_type, "scr"))
+ {
+ if ((quickload_size != SCR_SIZE) && (quickload_size != SCR_BITMAP))
+ {
+ logerror("Invalid .SCR file size.\n");
+ goto error;
+ }
+ spectrum_setup_scr(image.device().machine(), quickload_data, quickload_size);
+ }
+ else if (!mame_stricmp(file_type, "raw"))
+ {
+ if (quickload_size != RAW_SIZE)
+ {
+ logerror("Invalid .RAW file size.\n");
+ goto error;
+ }
+ spectrum_setup_raw(image.device().machine(), quickload_data, quickload_size);
+ }
+
+ free(quickload_data);
+
+ return IMAGE_INIT_PASS;
+
+error:
+ if (quickload_data)
+ free(quickload_data);
+ return IMAGE_INIT_FAIL;
+}
+
+/*******************************************************************
+ *
+ * Load a .SCR file.
+ *
+ * .SCR files are just a binary dump of the ZX Spectrum's
+ * display file, which is 256x192 pixels large.
+ *
+ * These file are created using the Sinclair BASIC command
+ *
+ * SAVE "filename" SCREEN$
+ *
+ * where the keyword "SCREEN$" is a shortcut for "CODE 16384,6912"
+ * i.e. the loading address and the length of the data.
+ *
+ * The format is organized as follows:
+ *
+ * Offset Size Description
+ * -------- ------- -------------------------------------------------
+ * 0 6144 Screen bitmap
+ * 6144 768 Screen attributes
+ *
+ * Some utilities and emulators support a B&W version of this
+ * format, which stores only the bitmap. These files can't be
+ * produced using the SAVE SCREEN$ command - rather they're
+ * created by the command
+ *
+ * SAVE "filename" CODE 16384,6144
+ *
+ *******************************************************************/
+void spectrum_setup_scr(running_machine &machine, UINT8 *quickdata, UINT32 quicksize)
+{
+ int i;
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ for (i = 0; i < quicksize; i++)
+ space->write_byte(i + BASE_RAM, quickdata[i]);
+
+ log_quickload(quicksize == SCR_SIZE ? "SCREEN$" : "SCREEN$ (Mono)", BASE_RAM, quicksize, 0, EXEC_NA);
+}
+
+/*******************************************************************
+ *
+ * Load a .RAW file.
+ *
+ * .RAW files are a binary dump of the ZX Spectrum RAM
+ * and are created using the Sinclair BASIC command
+ *
+ * SAVE *"b" CODE 16384,49152
+ *
+ * which copies the whole RAM to the Interface 1's RS232 interface.
+ * The resulting file is always 49161 bytes long.
+ *
+ * The format is organized as follows:
+ *
+ * Offset Size Description (all registers stored with LSB first)
+ * ------- ------- -------------------------------------------------
+ * 0 1 0x03 (BYTES file type)
+ * 1 2 Image size
+ * 3 2 Image start address
+ * 5 4 0xFF
+ *
+ * Since the size and the start address are encoded in the header,
+ * it would be possible to create .RAW images of any part of the RAM.
+ * However, no image of such type has ever surfaced.
+ *
+ *******************************************************************/
+void spectrum_setup_raw(running_machine &machine, UINT8 *quickdata, UINT32 quicksize)
+{
+ int i;
+ UINT8 data;
+ UINT16 start, len;
+ spectrum_state *state = machine.driver_data<spectrum_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ start = (quickdata[RAW_OFFSET + 4] << 8) | quickdata[RAW_OFFSET + 3];
+ len = (quickdata[RAW_OFFSET + 2] << 8) | quickdata[RAW_OFFSET + 1];
+
+ for (i = 0; i < len; i++)
+ space->write_byte(i + start, quickdata[i + RAW_HDR]);
+
+ /* Set border color */
+ data = (space->read_byte(0x5c48) >> 3) & 0x07; // Get the current border color from BORDCR system variable.
+ state->m_port_fe_data = (state->m_port_fe_data & 0xf8) | data;
+ spectrum_border_update(machine, data);
+ logerror("Border color:%02X\n", data);
+
+ log_quickload("BYTES", start, len, 0, EXEC_NA);
+}
+