-
Notifications
You must be signed in to change notification settings - Fork 1
/
z80snapshot_loader.h
147 lines (126 loc) · 4.5 KB
/
z80snapshot_loader.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//==============================================================================
// PROJECT: zqloader
// FILE: z80snapshotloader.h
// DESCRIPTION: Definition of class Z80SnapShotLoader.
//
// Copyright (c) 2023 Daan Scherft [Oxidaan]
// This project uses the MIT license. See LICENSE.txt for details.
//==============================================================================
#pragma once
#include "datablock.h"
#include <cstdint>
#include <iosfwd>
#include <filesystem>
class TurboBlocks;
class Symbols;
/// Loads Z80 snapshot files.
/// See https://worldofspectrum.org/faq/reference/z80format.htm
class Z80SnapShotLoader
{
#pragma pack(push, 1)
// z80 snapshot header https://worldofspectrum.org/faq/reference/z80format.htm
struct Z80SnapShotHeader
{
uint8_t A_reg;
uint8_t F_reg;
uint16_t BC_reg; // BC register pair(LSB, i.e.C, first)
uint16_t HL_reg;
uint16_t PC_reg;
uint16_t SP_reg;
uint8_t I_reg;
uint8_t R_reg;
uint8_t flags_and_border;
uint16_t DE_reg;
uint16_t BCa_reg;
uint16_t DEa_reg;
uint16_t HLa_reg;
uint8_t Aa_reg;
uint8_t Fa_reg;
uint16_t IY_reg; // IY first!
uint16_t IX_reg;
uint8_t ei_di; // Interrupt flipflop, 0=DI, otherwise EI
uint8_t iff2; // (not particularly important...)
uint8_t flags_and_imode; // Interrupt mode (0, 1 or 2)
};
// z80 v2 snapshot header
struct Z80SnapShotHeader2
{
uint16_t length_and_version;
uint16_t PC_reg;
uint8_t hardware_mode;
uint8_t out_mode;
uint8_t out_mode_intf1;
uint8_t simulator_flags;
uint8_t soundchip_reg_number;
uint8_t soundchip_registers[16];
};
// z80 v3 snapshot header
struct Z80SnapShotHeader3
{
uint16_t low_tstate_counter;
uint8_t high_tstate_counter;
uint8_t reserved_for_spectator;
uint8_t mgt_rom_paged;
uint8_t multiface_rom_paged;
uint8_t rom_is_ram1;
uint8_t rom_is_ram2;
uint8_t keyboard_joystick_mappings1[10];
uint8_t keyboard_joystick_mappings2[10];
uint8_t mgt_type;
uint8_t inhibit_button_status;
uint8_t inhibit_flag_rom;
//uint8_t last_out_0x1ffd;
};
struct Z80SnapShotDataHeader
{
uint16_t length;
uint8_t page_num;
};
#pragma pack(pop)
static_assert(sizeof(Z80SnapShotHeader) == 30, "Sizeof Z80SnapShotHeader must be 30");
static_assert(sizeof(Z80SnapShotHeader2) == 25, "Sizeof Z80SnapShotHeader2 must be 23");
static_assert(sizeof(Z80SnapShotHeader) + sizeof(Z80SnapShotHeader2) + sizeof(Z80SnapShotHeader3) == 86, "Sizeof Z80SnapShotHeaders must be 86");
public:
Z80SnapShotLoader()
{}
/// Load Z80 snapshot file from given filename.
Z80SnapShotLoader& Load(const std::filesystem::path &p_filename);
/// Load Z80 snapshot file from given stream.
Z80SnapShotLoader& Load(std::istream& p_stream);
/// The given datablock should be a sjasmplus generated block with
/// some Z80 code to set all registers.
/// Typically would be snapshotregs.bin.
/// Together with Symbols will replace data there with actual snapshot register values.
Z80SnapShotLoader& SetRegBlock(DataBlock p_snapshot_regs_block)
{
m_reg_block = std::move(p_snapshot_regs_block);
return *this;
}
/// Move data as loaded from Z80 snapshot file to given TurboBlocks.
/// Will replace register data as read by this class (from z80 snapshot) in the block as
/// given in SetRegBlock, using the symbols as known by TurboBlocks.
void MoveToTurboBlocks(TurboBlocks& p_turbo_blocks);
/// This is the start addres at register load code (snapshotregs.bin)
/// When jumping to that address will load all registers, including PC,
/// thus activating the snapshot.
uint16_t GetUsrAddress() const
{
return m_usr;
}
/// Get entire (48kb) snapshot but expluding registers.
DataBlock GetData()
{
return std::move(m_mem48k);
}
private:
void Z80SnapShotHeaderToSnapShotRegs(const Symbols& p_symbols);
// Z80 decompress
// see https://worldofspectrum.org/faq/reference/z80format.htm
DataBlock DeCompress(const DataBlock& p_block);
private:
Z80SnapShotHeader m_z80_snapshot_header;
DataBlock m_mem48k;
DataBlock m_reg_block;
uint16_t m_usr;
std::string m_name;
};