openMSX
CPURegs.hh
Go to the documentation of this file.
1#ifndef CPUREGS_HH
2#define CPUREGS_HH
3
4#include "serialize_meta.hh"
5#include "openmsx.hh"
6#include <bit>
7#include <cassert>
8
9namespace openmsx {
10
11template<std::endian> struct z80regPair_8bit;
12template<> struct z80regPair_8bit<std::endian::little> { byte l, h; };
13template<> struct z80regPair_8bit<std::endian::big > { byte h, l; };
18
20{
21public:
22 explicit CPURegs(bool r800) : Rmask(r800 ? 0xff : 0x7f) {}
23 [[nodiscard]] inline byte getA() const { return AF_.b.h; }
24 [[nodiscard]] inline byte getF() const { return AF_.b.l; }
25 [[nodiscard]] inline byte getB() const { return BC_.b.h; }
26 [[nodiscard]] inline byte getC() const { return BC_.b.l; }
27 [[nodiscard]] inline byte getD() const { return DE_.b.h; }
28 [[nodiscard]] inline byte getE() const { return DE_.b.l; }
29 [[nodiscard]] inline byte getH() const { return HL_.b.h; }
30 [[nodiscard]] inline byte getL() const { return HL_.b.l; }
31 [[nodiscard]] inline byte getA2() const { return AF2_.b.h; }
32 [[nodiscard]] inline byte getF2() const { return AF2_.b.l; }
33 [[nodiscard]] inline byte getB2() const { return BC2_.b.h; }
34 [[nodiscard]] inline byte getC2() const { return BC2_.b.l; }
35 [[nodiscard]] inline byte getD2() const { return DE2_.b.h; }
36 [[nodiscard]] inline byte getE2() const { return DE2_.b.l; }
37 [[nodiscard]] inline byte getH2() const { return HL2_.b.h; }
38 [[nodiscard]] inline byte getL2() const { return HL2_.b.l; }
39 [[nodiscard]] inline byte getIXh() const { return IX_.b.h; }
40 [[nodiscard]] inline byte getIXl() const { return IX_.b.l; }
41 [[nodiscard]] inline byte getIYh() const { return IY_.b.h; }
42 [[nodiscard]] inline byte getIYl() const { return IY_.b.l; }
43 [[nodiscard]] inline byte getPCh() const { return PC_.b.h; }
44 [[nodiscard]] inline byte getPCl() const { return PC_.b.l; }
45 [[nodiscard]] inline byte getSPh() const { return SP_.b.h; }
46 [[nodiscard]] inline byte getSPl() const { return SP_.b.l; }
47
48 [[nodiscard]] inline word getAF() const { return AF_.w; }
49 [[nodiscard]] inline word getBC() const { return BC_.w; }
50 [[nodiscard]] inline word getDE() const { return DE_.w; }
51 [[nodiscard]] inline word getHL() const { return HL_.w; }
52 [[nodiscard]] inline word getAF2() const { return AF2_.w; }
53 [[nodiscard]] inline word getBC2() const { return BC2_.w; }
54 [[nodiscard]] inline word getDE2() const { return DE2_.w; }
55 [[nodiscard]] inline word getHL2() const { return HL2_.w; }
56 [[nodiscard]] inline word getIX() const { return IX_.w; }
57 [[nodiscard]] inline word getIY() const { return IY_.w; }
58 [[nodiscard]] inline word getPC() const { return PC_.w; }
59 [[nodiscard]] inline word getSP() const { return SP_.w; }
60
61 [[nodiscard]] inline byte getIM() const { return IM_; }
62 [[nodiscard]] inline byte getI() const { return I_; }
63 [[nodiscard]] inline byte getR() const { return (R_ & Rmask) | (R2_ & ~Rmask); }
64 [[nodiscard]] inline bool getIFF1() const { return IFF1_; }
65 [[nodiscard]] inline bool getIFF2() const { return IFF2_; }
66 [[nodiscard]] inline byte getHALT() const { return HALT_; }
67
68 inline void setA(byte x) { AF_.b.h = x; }
69 inline void setF(byte x) { AF_.b.l = x; }
70 inline void setB(byte x) { BC_.b.h = x; }
71 inline void setC(byte x) { BC_.b.l = x; }
72 inline void setD(byte x) { DE_.b.h = x; }
73 inline void setE(byte x) { DE_.b.l = x; }
74 inline void setH(byte x) { HL_.b.h = x; }
75 inline void setL(byte x) { HL_.b.l = x; }
76 inline void setA2(byte x) { AF2_.b.h = x; }
77 inline void setF2(byte x) { AF2_.b.l = x; }
78 inline void setB2(byte x) { BC2_.b.h = x; }
79 inline void setC2(byte x) { BC2_.b.l = x; }
80 inline void setD2(byte x) { DE2_.b.h = x; }
81 inline void setE2(byte x) { DE2_.b.l = x; }
82 inline void setH2(byte x) { HL2_.b.h = x; }
83 inline void setL2(byte x) { HL2_.b.l = x; }
84 inline void setIXh(byte x) { IX_.b.h = x; }
85 inline void setIXl(byte x) { IX_.b.l = x; }
86 inline void setIYh(byte x) { IY_.b.h = x; }
87 inline void setIYl(byte x) { IY_.b.l = x; }
88 inline void setPCh(byte x) { PC_.b.h = x; }
89 inline void setPCl(byte x) { PC_.b.l = x; }
90 inline void setSPh(byte x) { SP_.b.h = x; }
91 inline void setSPl(byte x) { SP_.b.l = x; }
92
93 inline void setAF(word x) { AF_.w = x; }
94 inline void setBC(word x) { BC_.w = x; }
95 inline void setDE(word x) { DE_.w = x; }
96 inline void setHL(word x) { HL_.w = x; }
97 inline void setAF2(word x) { AF2_.w = x; }
98 inline void setBC2(word x) { BC2_.w = x; }
99 inline void setDE2(word x) { DE2_.w = x; }
100 inline void setHL2(word x) { HL2_.w = x; }
101 inline void setIX(word x) { IX_.w = x; }
102 inline void setIY(word x) { IY_.w = x; }
103 inline void setPC(word x) { PC_.w = x; }
104 inline void setSP(word x) { SP_.w = x; }
105
106 inline void setIM(byte x) { IM_ = x; }
107 inline void setI(byte x) { I_ = x; }
108 inline void setR(byte x) { R_ = x; R2_ = x; }
109 inline void setIFF1(bool x) { IFF1_ = x; }
110 inline void setIFF2(bool x) { IFF2_ = x; }
111 inline void setHALT(bool x) { HALT_ = (HALT_ & ~1) | (x ? 1 : 0); }
112 inline void setExtHALT(bool x) { HALT_ = (HALT_ & ~2) | (x ? 2 : 0); }
113
114 inline void incR(byte x) { R_ += x; }
115
116 // Sometimes we need to look at sequences of instructions/actions
117 // instead of only individual instructions. The most obvious example is
118 // the non-acceptance of IRQs directly after an EI instruction. But
119 // also on R800, the timing of the CALL instruction is different when
120 // it's directly followed by a POP or RET instruction.
121 //
122 // The following methods implement this:
123 // - setCurrentXXX(): set flag for currently executing instruction
124 // - prevWasXXX(): check whether the last executed instruction had
125 // a specific flag
126 // - prev2WasXXX(): same but for the 2nd-to-last instruction
127 // - endInstruction(): this shifts the flags of the current instruction
128 // into the last, last into 2nd-to-last, ...
129 //
130 // Optimizations: these sequence flags are relatively infrequently
131 // needed. So most of the time we want to avoid the (small) overhead of
132 // maintaining these flags. (CPU emulation is still to most heavy part
133 // of the total emulation, so every cycle we can save counts). Therefor
134 // the flags are only shifted in the 'slow' emulation path. This means:
135 // - After setting a flag we should enter the slow emulation path for a
136 // few instructions.
137 // - Querying the flags should only be done in the slow emulation path.
138
139 // Set EI-flag on current instruction.
140 inline void setCurrentEI() {
141 prev_ |= 1;
142 }
143 // Set LDAI-flag on current instruction.
144 inline void setCurrentLDAI() {
145 prev_ |= 2;
146 }
147 // Set CALL-flag on current instruction.
148 inline void setCurrentCall() {
149 prev_ |= 4;
150 }
151 // Set POP-RET-flag on current instruction.
152 inline void setCurrentPopRet() {
153 prev_ |= 8;
154 }
155
156 // Previous instruction was EI?
157 [[nodiscard]] inline bool prevWasEI() const {
158 return (prev_ & (1 << 8)) != 0;
159 }
160 // Previous instruction was LD A,I or LD A,R? (only set for Z80)
161 [[nodiscard]] inline bool prevWasLDAI() const {
162 return (prev_ & (2 << 8)) != 0;
163 }
164 // Previous-previous instruction was a CALL? (only set for R800)
165 [[nodiscard]] inline bool prev2WasCall() const {
166 return (prev_ & (4 << (2 * 8))) != 0;
167 }
168 // Previous instruction was a POP or RET? (only set for R800)
169 [[nodiscard]] inline bool prevWasPopRet() const {
170 return (prev_ & (8 << 8)) != 0;
171 }
172
173 // Shift flags to the previous instruction positions.
174 // Clear flags for current instruction.
175 inline void endInstruction() {
176 prev_ <<= 8;
177 }
178
179 // Clear all previous-flags (called on reset).
180 inline void clearPrevious() {
181 prev_ = 0;
182 }
183
184 // (for debug-only) At the start of an instruction(-block) no flags
185 // should be set.
186 inline void checkNoCurrentFlags() const {
187 // Exception: we do allow a sloppy POP/RET flag, it only needs
188 // to be correct after a CALL instruction.
189 assert((prev_ & 0xF7) == 0);
190 }
191
192
193 template<typename Archive>
194 void serialize(Archive& ar, unsigned version);
195
196private:
197 z80regPair PC_;
198 z80regPair AF_, BC_, DE_, HL_;
199 z80regPair AF2_, BC2_, DE2_, HL2_;
200 z80regPair IX_, IY_, SP_;
201 bool IFF1_, IFF2_;
202 byte HALT_ = 0;
203 byte IM_, I_;
204 byte R_, R2_; // refresh = R & Rmask | R2 & ~Rmask
205 const byte Rmask; // 0x7F for Z80, 0xFF for R800
206 unsigned prev_;
207};
209
210
211/* The above implementation uses a union to access the upper/lower 8 bits in a
212 * 16 bit value. At some point in the past I replaced this with the
213 * implementation below because it generated faster code. Though when I measure
214 * it now, the original version is faster again.
215 * TODO need to investigate this further.
216 */
217#if 0
218class CPURegs {
219public:
220 [[nodiscard]] inline byte getA() const { return AF >> 8; }
221 [[nodiscard]] inline byte getF() const { return AF & 255; }
222 [[nodiscard]] inline byte getB() const { return BC >> 8; }
223 [[nodiscard]] inline byte getC() const { return BC & 255; }
224 [[nodiscard]] inline byte getD() const { return DE >> 8; }
225 [[nodiscard]] inline byte getE() const { return DE & 255; }
226 [[nodiscard]] inline byte getH() const { return HL >> 8; }
227 [[nodiscard]] inline byte getL() const { return HL & 255; }
228 [[nodiscard]] inline byte getA2() const { return AF2 >> 8; }
229 [[nodiscard]] inline byte getF2() const { return AF2 & 255; }
230 [[nodiscard]] inline byte getB2() const { return BC2 >> 8; }
231 [[nodiscard]] inline byte getC2() const { return BC2 & 255; }
232 [[nodiscard]] inline byte getD2() const { return DE2 >> 8; }
233 [[nodiscard]] inline byte getE2() const { return DE2 & 255; }
234 [[nodiscard]] inline byte getH2() const { return HL2 >> 8; }
235 [[nodiscard]] inline byte getL2() const { return HL2 & 255; }
236 [[nodiscard]] inline byte getIXh() const { return IX >> 8; }
237 [[nodiscard]] inline byte getIXl() const { return IX & 255; }
238 [[nodiscard]] inline byte getIYh() const { return IY >> 8; }
239 [[nodiscard]] inline byte getIYl() const { return IY & 255; }
240 [[nodiscard]] inline byte getPCh() const { return PC >> 8; }
241 [[nodiscard]] inline byte getPCl() const { return PC & 255; }
242 [[nodiscard]] inline byte getSPh() const { return SP >> 8; }
243 [[nodiscard]] inline byte getSPl() const { return SP & 255; }
244 [[nodiscard]] inline word getAF() const { return AF; }
245 [[nodiscard]] inline word getBC() const { return BC; }
246 [[nodiscard]] inline word getDE() const { return DE; }
247 [[nodiscard]] inline word getHL() const { return HL; }
248 [[nodiscard]] inline word getAF2() const { return AF2; }
249 [[nodiscard]] inline word getBC2() const { return BC2; }
250 [[nodiscard]] inline word getDE2() const { return DE2; }
251 [[nodiscard]] inline word getHL2() const { return HL2; }
252 [[nodiscard]] inline word getIX() const { return IX; }
253 [[nodiscard]] inline word getIY() const { return IY; }
254 [[nodiscard]] inline word getPC() const { return PC; }
255 [[nodiscard]] inline word getSP() const { return SP; }
256 [[nodiscard]] inline byte getIM() const { return IM; }
257 [[nodiscard]] inline byte getI() const { return I; }
258 [[nodiscard]] inline byte getR() const { return (R & 0x7F) | (R2 & 0x80); }
259 [[nodiscard]] inline bool getIFF1() const { return IFF1; }
260 [[nodiscard]] inline bool getIFF2() const { return IFF2; }
261 [[nodiscard]] inline bool getHALT() const { return HALT; }
262
263 inline void setA(byte x) { AF = (AF & 0x00FF) | (x << 8); }
264 inline void setF(byte x) { AF = (AF & 0xFF00) | x; }
265 inline void setB(byte x) { BC = (BC & 0x00FF) | (x << 8); }
266 inline void setC(byte x) { BC = (BC & 0xFF00) | x; }
267 inline void setD(byte x) { DE = (DE & 0x00FF) | (x << 8); }
268 inline void setE(byte x) { DE = (DE & 0xFF00) | x; }
269 inline void setH(byte x) { HL = (HL & 0x00FF) | (x << 8); }
270 inline void setL(byte x) { HL = (HL & 0xFF00) | x; }
271 inline void setA2(byte x) { AF2 = (AF2 & 0x00FF) | (x << 8); }
272 inline void setF2(byte x) { AF2 = (AF2 & 0xFF00) | x; }
273 inline void setB2(byte x) { BC2 = (BC2 & 0x00FF) | (x << 8); }
274 inline void setC2(byte x) { BC2 = (BC2 & 0xFF00) | x; }
275 inline void setD2(byte x) { DE2 = (DE2 & 0x00FF) | (x << 8); }
276 inline void setE2(byte x) { DE2 = (DE2 & 0xFF00) | x; }
277 inline void setH2(byte x) { HL2 = (HL2 & 0x00FF) | (x << 8); }
278 inline void setL2(byte x) { HL2 = (HL2 & 0xFF00) | x; }
279 inline void setIXh(byte x) { IX = (IX & 0x00FF) | (x << 8); }
280 inline void setIXl(byte x) { IX = (IX & 0xFF00) | x; }
281 inline void setIYh(byte x) { IY = (IY & 0x00FF) | (x << 8); }
282 inline void setIYl(byte x) { IY = (IY & 0xFF00) | x; }
283 inline void setPCh(byte x) { PC = (PC & 0x00FF) | (x << 8); }
284 inline void setPCl(byte x) { PC = (PC & 0xFF00) | x; }
285 inline void setSPh(byte x) { SP = (SP & 0x00FF) | (x << 8); }
286 inline void setSPl(byte x) { SP = (SP & 0xFF00) | x; }
287 inline void setAF(word x) { AF = x; }
288 inline void setBC(word x) { BC = x; }
289 inline void setDE(word x) { DE = x; }
290 inline void setHL(word x) { HL = x; }
291 inline void setAF2(word x) { AF2 = x; }
292 inline void setBC2(word x) { BC2 = x; }
293 inline void setDE2(word x) { DE2 = x; }
294 inline void setHL2(word x) { HL2 = x; }
295 inline void setIX(word x) { IX = x; }
296 inline void setIY(word x) { IY = x; }
297 inline void setPC(word x) { PC = x; }
298 inline void setSP(word x) { SP = x; }
299 inline void setIM(byte x) { IM = x; }
300 inline void setI(byte x) { I = x; }
301 inline void setR(byte x) { R = x; R2 = x; }
302 inline void setIFF1(bool x) { IFF1 = x; }
303 inline void setIFF2(bool x) { IFF2 = x; }
304 inline void setHALT(bool x) { HALT = x; }
305
306 inline void incR(byte x) { R += x; }
307
308private:
309 word AF, BC, DE, HL;
310 word AF2, BC2, DE2, HL2;
311 word IX, IY, PC, SP;
312 bool IFF1, IFF2, HALT;
313 byte IM, I;
314 byte R, R2; // refresh = R&127 | R2&128
315};
316#endif
317
318} // namespace openmsx
319
320#endif
word getBC() const
Definition CPURegs.hh:49
void setF(byte x)
Definition CPURegs.hh:69
void setBC(word x)
Definition CPURegs.hh:94
void setH2(byte x)
Definition CPURegs.hh:82
word getDE2() const
Definition CPURegs.hh:54
byte getE() const
Definition CPURegs.hh:28
void serialize(Archive &ar, unsigned version)
Definition CPURegs.cc:10
byte getHALT() const
Definition CPURegs.hh:66
void endInstruction()
Definition CPURegs.hh:175
void setB2(byte x)
Definition CPURegs.hh:78
byte getB2() const
Definition CPURegs.hh:33
void setAF2(word x)
Definition CPURegs.hh:97
byte getIM() const
Definition CPURegs.hh:61
byte getD2() const
Definition CPURegs.hh:35
bool getIFF1() const
Definition CPURegs.hh:64
bool getIFF2() const
Definition CPURegs.hh:65
void setF2(byte x)
Definition CPURegs.hh:77
void setC2(byte x)
Definition CPURegs.hh:79
void setHL(word x)
Definition CPURegs.hh:96
byte getB() const
Definition CPURegs.hh:25
void setB(byte x)
Definition CPURegs.hh:70
void setR(byte x)
Definition CPURegs.hh:108
void setDE(word x)
Definition CPURegs.hh:95
void setSPh(byte x)
Definition CPURegs.hh:90
word getHL() const
Definition CPURegs.hh:51
void setPC(word x)
Definition CPURegs.hh:103
word getDE() const
Definition CPURegs.hh:50
void setA(byte x)
Definition CPURegs.hh:68
byte getF2() const
Definition CPURegs.hh:32
void setIFF1(bool x)
Definition CPURegs.hh:109
byte getL2() const
Definition CPURegs.hh:38
void incR(byte x)
Definition CPURegs.hh:114
void setPCh(byte x)
Definition CPURegs.hh:88
void setA2(byte x)
Definition CPURegs.hh:76
bool prevWasEI() const
Definition CPURegs.hh:157
byte getIYl() const
Definition CPURegs.hh:42
byte getC() const
Definition CPURegs.hh:26
byte getH2() const
Definition CPURegs.hh:37
byte getA() const
Definition CPURegs.hh:23
byte getPCh() const
Definition CPURegs.hh:43
void setHL2(word x)
Definition CPURegs.hh:100
bool prevWasPopRet() const
Definition CPURegs.hh:169
word getIY() const
Definition CPURegs.hh:57
void setIXh(byte x)
Definition CPURegs.hh:84
void setBC2(word x)
Definition CPURegs.hh:98
word getAF() const
Definition CPURegs.hh:48
byte getH() const
Definition CPURegs.hh:29
word getHL2() const
Definition CPURegs.hh:55
word getPC() const
Definition CPURegs.hh:58
bool prev2WasCall() const
Definition CPURegs.hh:165
void setE2(byte x)
Definition CPURegs.hh:81
byte getIXh() const
Definition CPURegs.hh:39
void setL2(byte x)
Definition CPURegs.hh:83
void setPCl(byte x)
Definition CPURegs.hh:89
void setAF(word x)
Definition CPURegs.hh:93
word getSP() const
Definition CPURegs.hh:59
void setSPl(byte x)
Definition CPURegs.hh:91
void setH(byte x)
Definition CPURegs.hh:74
void setI(byte x)
Definition CPURegs.hh:107
void setDE2(word x)
Definition CPURegs.hh:99
void setE(byte x)
Definition CPURegs.hh:73
void setCurrentPopRet()
Definition CPURegs.hh:152
void setCurrentEI()
Definition CPURegs.hh:140
byte getIXl() const
Definition CPURegs.hh:40
word getIX() const
Definition CPURegs.hh:56
void setL(byte x)
Definition CPURegs.hh:75
byte getIYh() const
Definition CPURegs.hh:41
void checkNoCurrentFlags() const
Definition CPURegs.hh:186
byte getD() const
Definition CPURegs.hh:27
void setIYl(byte x)
Definition CPURegs.hh:87
void setIYh(byte x)
Definition CPURegs.hh:86
void setHALT(bool x)
Definition CPURegs.hh:111
byte getC2() const
Definition CPURegs.hh:34
byte getSPh() const
Definition CPURegs.hh:45
void setIXl(byte x)
Definition CPURegs.hh:85
void setCurrentLDAI()
Definition CPURegs.hh:144
void setD(byte x)
Definition CPURegs.hh:72
byte getSPl() const
Definition CPURegs.hh:46
void setSP(word x)
Definition CPURegs.hh:104
void setIX(word x)
Definition CPURegs.hh:101
byte getI() const
Definition CPURegs.hh:62
void setIFF2(bool x)
Definition CPURegs.hh:110
word getAF2() const
Definition CPURegs.hh:52
byte getL() const
Definition CPURegs.hh:30
byte getA2() const
Definition CPURegs.hh:31
void setIY(word x)
Definition CPURegs.hh:102
byte getF() const
Definition CPURegs.hh:24
void clearPrevious()
Definition CPURegs.hh:180
CPURegs(bool r800)
Definition CPURegs.hh:22
void setD2(byte x)
Definition CPURegs.hh:80
void setExtHALT(bool x)
Definition CPURegs.hh:112
bool prevWasLDAI() const
Definition CPURegs.hh:161
void setCurrentCall()
Definition CPURegs.hh:148
byte getE2() const
Definition CPURegs.hh:36
void setIM(byte x)
Definition CPURegs.hh:106
void setC(byte x)
Definition CPURegs.hh:71
word getBC2() const
Definition CPURegs.hh:53
byte getPCl() const
Definition CPURegs.hh:44
byte getR() const
Definition CPURegs.hh:63
This file implemented 3 utility functions:
Definition Autofire.cc:11
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
RegFunction R
STL namespace.
#define SERIALIZE_CLASS_VERSION(CLASS, VERSION)
z80regPair_8bit< std::endian::native > b
Definition CPURegs.hh:15