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 "build-info.hh"
7 #include <cassert>
8 
9 namespace openmsx {
10 
11 template<bool BigEndian> struct z80regpair_8bit;
12 template<> struct z80regpair_8bit<false> { byte l, h; };
13 template<> struct z80regpair_8bit<true> { byte h, l; };
14 union z80regpair {
17 };
18 
19 class CPURegs
20 {
21 public:
22  explicit CPURegs(bool r800) : HALT_(0), Rmask(r800 ? 0xff : 0x7f) {}
23  inline byte getA() const { return AF_.b.h; }
24  inline byte getF() const { return AF_.b.l; }
25  inline byte getB() const { return BC_.b.h; }
26  inline byte getC() const { return BC_.b.l; }
27  inline byte getD() const { return DE_.b.h; }
28  inline byte getE() const { return DE_.b.l; }
29  inline byte getH() const { return HL_.b.h; }
30  inline byte getL() const { return HL_.b.l; }
31  inline byte getA2() const { return AF2_.b.h; }
32  inline byte getF2() const { return AF2_.b.l; }
33  inline byte getB2() const { return BC2_.b.h; }
34  inline byte getC2() const { return BC2_.b.l; }
35  inline byte getD2() const { return DE2_.b.h; }
36  inline byte getE2() const { return DE2_.b.l; }
37  inline byte getH2() const { return HL2_.b.h; }
38  inline byte getL2() const { return HL2_.b.l; }
39  inline byte getIXh() const { return IX_.b.h; }
40  inline byte getIXl() const { return IX_.b.l; }
41  inline byte getIYh() const { return IY_.b.h; }
42  inline byte getIYl() const { return IY_.b.l; }
43  inline byte getPCh() const { return PC_.b.h; }
44  inline byte getPCl() const { return PC_.b.l; }
45  inline byte getSPh() const { return SP_.b.h; }
46  inline byte getSPl() const { return SP_.b.l; }
47 
48  inline unsigned getAF() const { return AF_.w; }
49  inline unsigned getBC() const { return BC_.w; }
50  inline unsigned getDE() const { return DE_.w; }
51  inline unsigned getHL() const { return HL_.w; }
52  inline unsigned getAF2() const { return AF2_.w; }
53  inline unsigned getBC2() const { return BC2_.w; }
54  inline unsigned getDE2() const { return DE2_.w; }
55  inline unsigned getHL2() const { return HL2_.w; }
56  inline unsigned getIX() const { return IX_.w; }
57  inline unsigned getIY() const { return IY_.w; }
58  inline unsigned getPC() const { return PC_.w; }
59  inline unsigned getSP() const { return SP_.w; }
60 
61  inline byte getIM() const { return IM_; }
62  inline byte getI() const { return I_; }
63  inline byte getR() const { return (R_ & Rmask) | (R2_ & ~Rmask); }
64  inline bool getIFF1() const { return IFF1_; }
65  inline bool getIFF2() const { return IFF2_; }
66  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(unsigned x) { AF_.w = x; }
94  inline void setBC(unsigned x) { BC_.w = x; }
95  inline void setDE(unsigned x) { DE_.w = x; }
96  inline void setHL(unsigned x) { HL_.w = x; }
97  inline void setAF2(unsigned x) { AF2_.w = x; }
98  inline void setBC2(unsigned x) { BC2_.w = x; }
99  inline void setDE2(unsigned x) { DE2_.w = x; }
100  inline void setHL2(unsigned x) { HL2_.w = x; }
101  inline void setIX(unsigned x) { IX_.w = x; }
102  inline void setIY(unsigned x) { IY_.w = x; }
103  inline void setPC(unsigned x) { PC_.w = x; }
104  inline void setSP(unsigned 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 POPRET-flag on current instruction.
152  inline void setCurrentPopRet() {
153  prev_ |= 8;
154  }
155 
156  // Previous instruction was EI?
157  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  inline bool prevWasLDAI() const {
162  return (prev_ & (2 << 8)) != 0;
163  }
164  // Previous-previous instruction was a CALL? (only set for R800)
165  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  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 
196 private:
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_;
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
218 class CPURegs {
219 public:
220  inline byte getA() const { return AF >> 8; }
221  inline byte getF() const { return AF & 255; }
222  inline byte getB() const { return BC >> 8; }
223  inline byte getC() const { return BC & 255; }
224  inline byte getD() const { return DE >> 8; }
225  inline byte getE() const { return DE & 255; }
226  inline byte getH() const { return HL >> 8; }
227  inline byte getL() const { return HL & 255; }
228  inline byte getA2() const { return AF2 >> 8; }
229  inline byte getF2() const { return AF2 & 255; }
230  inline byte getB2() const { return BC2 >> 8; }
231  inline byte getC2() const { return BC2 & 255; }
232  inline byte getD2() const { return DE2 >> 8; }
233  inline byte getE2() const { return DE2 & 255; }
234  inline byte getH2() const { return HL2 >> 8; }
235  inline byte getL2() const { return HL2 & 255; }
236  inline byte getIXh() const { return IX >> 8; }
237  inline byte getIXl() const { return IX & 255; }
238  inline byte getIYh() const { return IY >> 8; }
239  inline byte getIYl() const { return IY & 255; }
240  inline byte getPCh() const { return PC >> 8; }
241  inline byte getPCl() const { return PC & 255; }
242  inline byte getSPh() const { return SP >> 8; }
243  inline byte getSPl() const { return SP & 255; }
244  inline word getAF() const { return AF; }
245  inline word getBC() const { return BC; }
246  inline word getDE() const { return DE; }
247  inline word getHL() const { return HL; }
248  inline word getAF2() const { return AF2; }
249  inline word getBC2() const { return BC2; }
250  inline word getDE2() const { return DE2; }
251  inline word getHL2() const { return HL2; }
252  inline word getIX() const { return IX; }
253  inline word getIY() const { return IY; }
254  inline word getPC() const { return PC; }
255  inline word getSP() const { return SP; }
256  inline byte getIM() const { return IM; }
257  inline byte getI() const { return I; }
258  inline byte getR() const { return (R & 0x7F) | (R2 & 0x80); }
259  inline bool getIFF1() const { return IFF1; }
260  inline bool getIFF2() const { return IFF2; }
261  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 
308 private:
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
bool getIFF2() const
Definition: CPURegs.hh:65
unsigned getBC() const
Definition: CPURegs.hh:49
void setI(byte x)
Definition: CPURegs.hh:107
byte getL() const
Definition: CPURegs.hh:30
byte getA2() const
Definition: CPURegs.hh:31
byte getH2() const
Definition: CPURegs.hh:37
void setBC2(unsigned x)
Definition: CPURegs.hh:98
void setC(byte x)
Definition: CPURegs.hh:71
unsigned getBC2() const
Definition: CPURegs.hh:53
unsigned getIX() const
Definition: CPURegs.hh:56
void setH2(byte x)
Definition: CPURegs.hh:82
void setR(byte x)
Definition: CPURegs.hh:108
byte getIXl() const
Definition: CPURegs.hh:40
bool prev2WasCall() const
Definition: CPURegs.hh:165
void setExtHALT(bool x)
Definition: CPURegs.hh:112
void setB(byte x)
Definition: CPURegs.hh:70
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
void setD2(byte x)
Definition: CPURegs.hh:80
void setIM(byte x)
Definition: CPURegs.hh:106
void setF2(byte x)
Definition: CPURegs.hh:77
byte getIYl() const
Definition: CPURegs.hh:42
unsigned getPC() const
Definition: CPURegs.hh:58
void setE(byte x)
Definition: CPURegs.hh:73
void setPCh(byte x)
Definition: CPURegs.hh:88
unsigned getHL2() const
Definition: CPURegs.hh:55
byte getC2() const
Definition: CPURegs.hh:34
void setIFF1(bool x)
Definition: CPURegs.hh:109
void setIY(unsigned x)
Definition: CPURegs.hh:102
void setIYh(byte x)
Definition: CPURegs.hh:86
z80regpair_8bit< OPENMSX_BIGENDIAN > b
Definition: CPURegs.hh:15
byte getSPl() const
Definition: CPURegs.hh:46
byte getF() const
Definition: CPURegs.hh:24
void checkNoCurrentFlags() const
Definition: CPURegs.hh:186
byte getPCl() const
Definition: CPURegs.hh:44
unsigned getAF2() const
Definition: CPURegs.hh:52
void endInstruction()
Definition: CPURegs.hh:175
bool prevWasEI() const
Definition: CPURegs.hh:157
void setA2(byte x)
Definition: CPURegs.hh:76
void setPCl(byte x)
Definition: CPURegs.hh:89
void setPC(unsigned x)
Definition: CPURegs.hh:103
byte getI() const
Definition: CPURegs.hh:62
bool prevWasLDAI() const
Definition: CPURegs.hh:161
void setIX(unsigned x)
Definition: CPURegs.hh:101
void setIYl(byte x)
Definition: CPURegs.hh:87
void setDE(unsigned x)
Definition: CPURegs.hh:95
void incR(byte x)
Definition: CPURegs.hh:114
byte getF2() const
Definition: CPURegs.hh:32
SERIALIZE_CLASS_VERSION(CassettePlayer, 2)
byte getB() const
Definition: CPURegs.hh:25
byte getIYh() const
Definition: CPURegs.hh:41
void setSPl(byte x)
Definition: CPURegs.hh:91
void setCurrentLDAI()
Definition: CPURegs.hh:144
void setDE2(unsigned x)
Definition: CPURegs.hh:99
byte getH() const
Definition: CPURegs.hh:29
void clearPrevious()
Definition: CPURegs.hh:180
byte getIM() const
Definition: CPURegs.hh:61
byte getD2() const
Definition: CPURegs.hh:35
void setA(byte x)
Definition: CPURegs.hh:68
void setL(byte x)
Definition: CPURegs.hh:75
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
void setH(byte x)
Definition: CPURegs.hh:74
unsigned getDE() const
Definition: CPURegs.hh:50
byte getPCh() const
Definition: CPURegs.hh:43
void setAF(unsigned x)
Definition: CPURegs.hh:93
void setE2(byte x)
Definition: CPURegs.hh:81
void setHALT(bool x)
Definition: CPURegs.hh:111
void setB2(byte x)
Definition: CPURegs.hh:78
byte getD() const
Definition: CPURegs.hh:27
byte getL2() const
Definition: CPURegs.hh:38
unsigned getHL() const
Definition: CPURegs.hh:51
void setHL2(unsigned x)
Definition: CPURegs.hh:100
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
unsigned getSP() const
Definition: CPURegs.hh:59
byte getSPh() const
Definition: CPURegs.hh:45
void setCurrentEI()
Definition: CPURegs.hh:140
byte getHALT() const
Definition: CPURegs.hh:66
void setL2(byte x)
Definition: CPURegs.hh:83
void setIXl(byte x)
Definition: CPURegs.hh:85
void setSPh(byte x)
Definition: CPURegs.hh:90
byte getE2() const
Definition: CPURegs.hh:36
void setF(byte x)
Definition: CPURegs.hh:69
bool getIFF1() const
Definition: CPURegs.hh:64
void setD(byte x)
Definition: CPURegs.hh:72
byte getA() const
Definition: CPURegs.hh:23
byte getC() const
Definition: CPURegs.hh:26
byte getE() const
Definition: CPURegs.hh:28
unsigned getAF() const
Definition: CPURegs.hh:48
void setBC(unsigned x)
Definition: CPURegs.hh:94
unsigned getIY() const
Definition: CPURegs.hh:57
void setIFF2(bool x)
Definition: CPURegs.hh:110
void setC2(byte x)
Definition: CPURegs.hh:79
void setAF2(unsigned x)
Definition: CPURegs.hh:97
void setHL(unsigned x)
Definition: CPURegs.hh:96
unsigned getDE2() const
Definition: CPURegs.hh:54
void setIXh(byte x)
Definition: CPURegs.hh:84
byte getR() const
Definition: CPURegs.hh:63
void setCurrentPopRet()
Definition: CPURegs.hh:152
byte getB2() const
Definition: CPURegs.hh:33
void serialize(Archive &ar, T &t, unsigned version)
byte getIXh() const
Definition: CPURegs.hh:39
CPURegs(bool r800)
Definition: CPURegs.hh:22
bool prevWasPopRet() const
Definition: CPURegs.hh:169
void setCurrentCall()
Definition: CPURegs.hh:148
void setSP(unsigned x)
Definition: CPURegs.hh:104