diff options
Diffstat (limited to 'src/mess/formats/spec_snqk.c')
-rw-r--r-- | src/mess/formats/spec_snqk.c | 2579 |
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); +} + |