openMSX
CPU.hh
Go to the documentation of this file.
1 #ifndef CPU_HH
2 #define CPU_HH
3 
4 #include "EmuTime.hh"
5 #include "serialize_meta.hh"
6 #include "openmsx.hh"
7 #include "noncopyable.hh"
8 #include "unreachable.hh"
9 #include "build-info.hh"
10 #include <vector>
11 #include <memory>
12 #include <cassert>
13 
14 namespace openmsx {
15 
16 class TclObject;
17 
18 template <bool bigEndian> struct z80regpair_8bit;
19 template <> struct z80regpair_8bit<false> { byte l, h; };
20 template <> struct z80regpair_8bit<true> { byte h, l; };
21 typedef union {
24 } z80regpair;
25 
26 class CPU : private noncopyable
27 {
28 public:
29  // flag positions
30  static const byte S_FLAG = 0x80;
31  static const byte Z_FLAG = 0x40;
32  static const byte Y_FLAG = 0x20;
33  static const byte H_FLAG = 0x10;
34  static const byte X_FLAG = 0x08;
35  static const byte V_FLAG = 0x04;
36  static const byte P_FLAG = V_FLAG;
37  static const byte N_FLAG = 0x02;
38  static const byte C_FLAG = 0x01;
39 
40 /*
41  * Below are two different implementations for the CPURegs class:
42  * 1) use arithmetic to extract the upper/lower byte from a word
43  * 2) use a union to directly access the bytes in the word
44  * At some time in the past I replaced 2) with 1) because 1) was faster,
45  * but when I measure it now again 2) is faster.
46  * TODO need to investigate this further.
47  */
48 #if 0
49  class CPURegs {
50  public:
51  inline byte getA() const { return AF >> 8; }
52  inline byte getF() const { return AF & 255; }
53  inline byte getB() const { return BC >> 8; }
54  inline byte getC() const { return BC & 255; }
55  inline byte getD() const { return DE >> 8; }
56  inline byte getE() const { return DE & 255; }
57  inline byte getH() const { return HL >> 8; }
58  inline byte getL() const { return HL & 255; }
59  inline byte getA2() const { return AF2 >> 8; }
60  inline byte getF2() const { return AF2 & 255; }
61  inline byte getB2() const { return BC2 >> 8; }
62  inline byte getC2() const { return BC2 & 255; }
63  inline byte getD2() const { return DE2 >> 8; }
64  inline byte getE2() const { return DE2 & 255; }
65  inline byte getH2() const { return HL2 >> 8; }
66  inline byte getL2() const { return HL2 & 255; }
67  inline byte getIXh() const { return IX >> 8; }
68  inline byte getIXl() const { return IX & 255; }
69  inline byte getIYh() const { return IY >> 8; }
70  inline byte getIYl() const { return IY & 255; }
71  inline byte getPCh() const { return PC >> 8; }
72  inline byte getPCl() const { return PC & 255; }
73  inline byte getSPh() const { return SP >> 8; }
74  inline byte getSPl() const { return SP & 255; }
75  inline word getAF() const { return AF; }
76  inline word getBC() const { return BC; }
77  inline word getDE() const { return DE; }
78  inline word getHL() const { return HL; }
79  inline word getAF2() const { return AF2; }
80  inline word getBC2() const { return BC2; }
81  inline word getDE2() const { return DE2; }
82  inline word getHL2() const { return HL2; }
83  inline word getIX() const { return IX; }
84  inline word getIY() const { return IY; }
85  inline word getPC() const { return PC; }
86  inline word getSP() const { return SP; }
87  inline byte getIM() const { return IM; }
88  inline byte getI() const { return I; }
89  inline byte getR() const { return (R & 0x7F) | (R2 & 0x80); }
90  inline bool getIFF1() const { return IFF1; }
91  inline bool getIFF2() const { return IFF2; }
92  inline bool getHALT() const { return HALT; }
93 
94  inline void setA(byte x) { AF = (AF & 0x00FF) | (x << 8); }
95  inline void setF(byte x) { AF = (AF & 0xFF00) | x; }
96  inline void setB(byte x) { BC = (BC & 0x00FF) | (x << 8); }
97  inline void setC(byte x) { BC = (BC & 0xFF00) | x; }
98  inline void setD(byte x) { DE = (DE & 0x00FF) | (x << 8); }
99  inline void setE(byte x) { DE = (DE & 0xFF00) | x; }
100  inline void setH(byte x) { HL = (HL & 0x00FF) | (x << 8); }
101  inline void setL(byte x) { HL = (HL & 0xFF00) | x; }
102  inline void setA2(byte x) { AF2 = (AF2 & 0x00FF) | (x << 8); }
103  inline void setF2(byte x) { AF2 = (AF2 & 0xFF00) | x; }
104  inline void setB2(byte x) { BC2 = (BC2 & 0x00FF) | (x << 8); }
105  inline void setC2(byte x) { BC2 = (BC2 & 0xFF00) | x; }
106  inline void setD2(byte x) { DE2 = (DE2 & 0x00FF) | (x << 8); }
107  inline void setE2(byte x) { DE2 = (DE2 & 0xFF00) | x; }
108  inline void setH2(byte x) { HL2 = (HL2 & 0x00FF) | (x << 8); }
109  inline void setL2(byte x) { HL2 = (HL2 & 0xFF00) | x; }
110  inline void setIXh(byte x) { IX = (IX & 0x00FF) | (x << 8); }
111  inline void setIXl(byte x) { IX = (IX & 0xFF00) | x; }
112  inline void setIYh(byte x) { IY = (IY & 0x00FF) | (x << 8); }
113  inline void setIYl(byte x) { IY = (IY & 0xFF00) | x; }
114  inline void setPCh(byte x) { PC = (PC & 0x00FF) | (x << 8); }
115  inline void setPCl(byte x) { PC = (PC & 0xFF00) | x; }
116  inline void setSPh(byte x) { SP = (SP & 0x00FF) | (x << 8); }
117  inline void setSPl(byte x) { SP = (SP & 0xFF00) | x; }
118  inline void setAF(word x) { AF = x; }
119  inline void setBC(word x) { BC = x; }
120  inline void setDE(word x) { DE = x; }
121  inline void setHL(word x) { HL = x; }
122  inline void setAF2(word x) { AF2 = x; }
123  inline void setBC2(word x) { BC2 = x; }
124  inline void setDE2(word x) { DE2 = x; }
125  inline void setHL2(word x) { HL2 = x; }
126  inline void setIX(word x) { IX = x; }
127  inline void setIY(word x) { IY = x; }
128  inline void setPC(word x) { PC = x; }
129  inline void setSP(word x) { SP = x; }
130  inline void setIM(byte x) { IM = x; }
131  inline void setI(byte x) { I = x; }
132  inline void setR(byte x) { R = x; R2 = x; }
133  inline void setIFF1(bool x) { IFF1 = x; }
134  inline void setIFF2(bool x) { IFF2 = x; }
135  inline void setHALT(bool x) { HALT = x; }
136 
137  inline void incR(byte x) { R += x; }
138 
139  private:
140  word AF, BC, DE, HL;
141  word AF2, BC2, DE2, HL2;
142  word IX, IY, PC, SP;
143  bool IFF1, IFF2, HALT;
144  byte IM, I;
145  byte R, R2; // refresh = R&127 | R2&128
146  };
147 #else
148  enum Reg8 { A, F, B, C, D, E, H, L, IXH, IXL, IYH, IYL, REG_I, REG_R, DUMMY };
149  enum Reg16 { AF, BC, DE, HL, IX, IY, SP };
150  class CPURegs {
151  public:
152  CPURegs(bool r800) : HALT_(0), Rmask(r800 ? 0xff : 0x7f) {}
153  inline byte getA() const { return AF_.b.h; }
154  inline byte getF() const { return AF_.b.l; }
155  inline byte getB() const { return BC_.b.h; }
156  inline byte getC() const { return BC_.b.l; }
157  inline byte getD() const { return DE_.b.h; }
158  inline byte getE() const { return DE_.b.l; }
159  inline byte getH() const { return HL_.b.h; }
160  inline byte getL() const { return HL_.b.l; }
161  inline byte getA2() const { return AF2_.b.h; }
162  inline byte getF2() const { return AF2_.b.l; }
163  inline byte getB2() const { return BC2_.b.h; }
164  inline byte getC2() const { return BC2_.b.l; }
165  inline byte getD2() const { return DE2_.b.h; }
166  inline byte getE2() const { return DE2_.b.l; }
167  inline byte getH2() const { return HL2_.b.h; }
168  inline byte getL2() const { return HL2_.b.l; }
169  inline byte getIXh() const { return IX_.b.h; }
170  inline byte getIXl() const { return IX_.b.l; }
171  inline byte getIYh() const { return IY_.b.h; }
172  inline byte getIYl() const { return IY_.b.l; }
173  inline byte getPCh() const { return PC_.b.h; }
174  inline byte getPCl() const { return PC_.b.l; }
175  inline byte getSPh() const { return SP_.b.h; }
176  inline byte getSPl() const { return SP_.b.l; }
177  template <Reg8 R8> inline byte get8() const {
178  if (R8 == A) { return getA(); }
179  else if (R8 == F) { return getF(); }
180  else if (R8 == B) { return getB(); }
181  else if (R8 == C) { return getC(); }
182  else if (R8 == D) { return getD(); }
183  else if (R8 == E) { return getE(); }
184  else if (R8 == H) { return getH(); }
185  else if (R8 == L) { return getL(); }
186  else if (R8 == IXH) { return getIXh(); }
187  else if (R8 == IXL) { return getIXl(); }
188  else if (R8 == IYH) { return getIYh(); }
189  else if (R8 == IYL) { return getIYl(); }
190  else if (R8 == REG_I) { return getI(); }
191  else if (R8 == REG_R) { return getR(); }
192  else if (R8 == DUMMY) { return 0; }
193  else { UNREACHABLE; return 0; }
194  }
195 
196  inline unsigned getAF() const { return AF_.w; }
197  inline unsigned getBC() const { return BC_.w; }
198  inline unsigned getDE() const { return DE_.w; }
199  inline unsigned getHL() const { return HL_.w; }
200  inline unsigned getAF2() const { return AF2_.w; }
201  inline unsigned getBC2() const { return BC2_.w; }
202  inline unsigned getDE2() const { return DE2_.w; }
203  inline unsigned getHL2() const { return HL2_.w; }
204  inline unsigned getIX() const { return IX_.w; }
205  inline unsigned getIY() const { return IY_.w; }
206  inline unsigned getPC() const { return PC_.w; }
207  inline unsigned getSP() const { return SP_.w; }
208  template <Reg16 R16> inline unsigned get16() const {
209  if (R16 == AF) { return getAF(); }
210  else if (R16 == BC) { return getBC(); }
211  else if (R16 == DE) { return getDE(); }
212  else if (R16 == HL) { return getHL(); }
213  else if (R16 == IX) { return getIX(); }
214  else if (R16 == IY) { return getIY(); }
215  else if (R16 == SP) { return getSP(); }
216  else { UNREACHABLE; return 0; }
217  }
218 
219  inline byte getIM() const { return IM_; }
220  inline byte getI() const { return I_; }
221  inline byte getR() const { return (R_ & Rmask) | (R2_ & ~Rmask); }
222  inline bool getIFF1() const { return IFF1_; }
223  inline bool getIFF2() const { return IFF2_; }
224  inline byte getHALT() const { return HALT_; }
225 
226  inline void setA(byte x) { AF_.b.h = x; }
227  inline void setF(byte x) { AF_.b.l = x; }
228  inline void setB(byte x) { BC_.b.h = x; }
229  inline void setC(byte x) { BC_.b.l = x; }
230  inline void setD(byte x) { DE_.b.h = x; }
231  inline void setE(byte x) { DE_.b.l = x; }
232  inline void setH(byte x) { HL_.b.h = x; }
233  inline void setL(byte x) { HL_.b.l = x; }
234  inline void setA2(byte x) { AF2_.b.h = x; }
235  inline void setF2(byte x) { AF2_.b.l = x; }
236  inline void setB2(byte x) { BC2_.b.h = x; }
237  inline void setC2(byte x) { BC2_.b.l = x; }
238  inline void setD2(byte x) { DE2_.b.h = x; }
239  inline void setE2(byte x) { DE2_.b.l = x; }
240  inline void setH2(byte x) { HL2_.b.h = x; }
241  inline void setL2(byte x) { HL2_.b.l = x; }
242  inline void setIXh(byte x) { IX_.b.h = x; }
243  inline void setIXl(byte x) { IX_.b.l = x; }
244  inline void setIYh(byte x) { IY_.b.h = x; }
245  inline void setIYl(byte x) { IY_.b.l = x; }
246  inline void setPCh(byte x) { PC_.b.h = x; }
247  inline void setPCl(byte x) { PC_.b.l = x; }
248  inline void setSPh(byte x) { SP_.b.h = x; }
249  inline void setSPl(byte x) { SP_.b.l = x; }
250  template <Reg8 R8> inline void set8(byte x) {
251  if (R8 == A) { setA(x); }
252  else if (R8 == F) { setF(x); }
253  else if (R8 == B) { setB(x); }
254  else if (R8 == C) { setC(x); }
255  else if (R8 == D) { setD(x); }
256  else if (R8 == E) { setE(x); }
257  else if (R8 == H) { setH(x); }
258  else if (R8 == L) { setL(x); }
259  else if (R8 == IXH) { setIXh(x); }
260  else if (R8 == IXL) { setIXl(x); }
261  else if (R8 == IYH) { setIYh(x); }
262  else if (R8 == IYL) { setIYl(x); }
263  else if (R8 == REG_I) { setI(x); }
264  else if (R8 == REG_R) { setR(x); }
265  else if (R8 == DUMMY) { /* nothing */ }
266  else { UNREACHABLE; }
267  }
268 
269  inline void setAF(unsigned x) { AF_.w = x; }
270  inline void setBC(unsigned x) { BC_.w = x; }
271  inline void setDE(unsigned x) { DE_.w = x; }
272  inline void setHL(unsigned x) { HL_.w = x; }
273  inline void setAF2(unsigned x) { AF2_.w = x; }
274  inline void setBC2(unsigned x) { BC2_.w = x; }
275  inline void setDE2(unsigned x) { DE2_.w = x; }
276  inline void setHL2(unsigned x) { HL2_.w = x; }
277  inline void setIX(unsigned x) { IX_.w = x; }
278  inline void setIY(unsigned x) { IY_.w = x; }
279  inline void setPC(unsigned x) { PC_.w = x; }
280  inline void setSP(unsigned x) { SP_.w = x; }
281  template <Reg16 R16> inline void set16(unsigned x) {
282  if (R16 == AF) { setAF(x); }
283  else if (R16 == BC) { setBC(x); }
284  else if (R16 == DE) { setDE(x); }
285  else if (R16 == HL) { setHL(x); }
286  else if (R16 == IX) { setIX(x); }
287  else if (R16 == IY) { setIY(x); }
288  else if (R16 == SP) { setSP(x); }
289  else { UNREACHABLE; }
290  }
291 
292  inline void setIM(byte x) { IM_ = x; }
293  inline void setI(byte x) { I_ = x; }
294  inline void setR(byte x) { R_ = x; R2_ = x; }
295  inline void setIFF1(bool x) { IFF1_ = x; }
296  inline void setIFF2(bool x) { IFF2_ = x; }
297  inline void setHALT(bool x) { HALT_ = (HALT_ & ~1) | (x ? 1 : 0); }
298  inline void setExtHALT(bool x) { HALT_ = (HALT_ & ~2) | (x ? 2 : 0); }
299 
300  inline void incR(byte x) { R_ += x; }
301 
302  // These methods are used to set/query whether the previously
303  // executed instruction was a 'EI' or 'LD A,{I,R}' instruction.
304  // Initially this could only be queried between two
305  // instructions, so e.g. after the EI instruction was executed
306  // but before the next one has started, for emulation this is
307  // good enough. But for debugging we still want to be able to
308  // query this info during the execution of the next
309  // instruction: e.g. a IO-watchpoint is triggered during the
310  // execution of some OUT instruction, at the time we evaluate
311  // the condition for that watchpoint, we still want to be able
312  // to query whether the previous instruction was a EI
313  // instruction.
314  inline bool isSameAfter() const {
315  // Between two instructions these two should be the same
316  return after_ == afterNext_;
317  }
318  inline bool getAfterEI() const {
319  assert(isSameAfter());
320  return (after_ & 0x01) != 0;
321  }
322  inline bool getAfterLDAI() const {
323  assert(isSameAfter());
324  return (after_ & 0x02) != 0;
325  }
326  inline bool debugGetAfterEI() const {
327  // Can be called during execution of an instruction
328  return (after_ & 0x01) != 0;
329  }
330  inline void clearNextAfter() {
331  // Right before executing an instruction this should be
332  // cleared
333  afterNext_ = 0x00;
334  }
335  inline bool isNextAfterClear() const {
336  // In the fast code path we avoid calling clearNextAfter()
337  // before every instruction. But in debug mode we want
338  // to verify that this optimzation is valid.
339  return afterNext_ == 0;
340  }
341  inline void setAfterEI() {
342  // Set both after_ and afterNext_. Can only be called
343  // at the end of an instruction (status of prev
344  // instruction can't be queried anymore)
345  assert(isNextAfterClear());
346  afterNext_ = after_ = 0x01;
347  }
348  inline void setAfterLDAI() {
349  // Set both, see above.
350  assert(isNextAfterClear());
351  afterNext_ = after_ = 0x02;
352  }
353  inline void copyNextAfter() {
354  // At the end of an instruction, the next flags become
355  // the current flags. setAfterEI/LDAI() already sets
356  // both after_ and afterNext_, thus calling this method
357  // is only required to clear the flags. Instructions
358  // right after a EI or LD A,I/R instruction are always
359  // executed in the slow code path. So this means that
360  // in the fast code path we don't need to call
361  // copyNextAfter().
362  after_ = afterNext_;
363  }
364 
365  template<typename Archive>
366  void serialize(Archive& ar, unsigned version);
367 
368  private:
369  z80regpair AF_, BC_, DE_, HL_;
370  z80regpair AF2_, BC2_, DE2_, HL2_;
371  z80regpair IX_, IY_, PC_, SP_;
372  bool IFF1_, IFF2_;
373  byte after_, afterNext_;
374  byte HALT_;
375  byte IM_, I_;
376  byte R_, R2_; // refresh = R & Rmask | R2 & ~Rmask
377  const byte Rmask; // 0x7F for Z80, 0xFF for R800
378  };
379 #endif
380 
384  virtual void execute(bool fastForward) = 0;
385 
391  virtual void exitCPULoopSync() = 0;
392 
396  virtual void exitCPULoopAsync() = 0;
397 
402  virtual void warp(EmuTime::param time) = 0;
403 
407  virtual EmuTime::param getCurrentTime() const = 0;
408 
413  virtual void wait(EmuTime::param time) = 0;
414 
419  virtual void waitCycles(unsigned cycles) = 0;
420 
423  virtual void setNextSyncPoint(EmuTime::param time) = 0;
424 
429  virtual void invalidateMemCache(unsigned start, unsigned num) = 0;
430 
432  virtual bool isM1Cycle(unsigned address) const = 0;
433 
436  virtual void disasmCommand(const std::vector<TclObject>& tokens,
437  TclObject& result) const = 0;
438 
441  CPURegs& getRegisters() { return R; }
442 
447  void setPaused(bool paused);
448 
449 protected:
450  CPU(bool r800);
451  virtual ~CPU();
452 
453  // flag-register tables, initialized at run-time
454  static byte ZSTable[256];
455  static byte ZSXYTable[256];
456  static byte ZSPTable[256];
457  static byte ZSPXYTable[256];
458  static byte ZSPHTable[256];
459  static const byte ZS0 = Z_FLAG;
460  static const byte ZSXY0 = Z_FLAG;
461  static const byte ZSP0 = Z_FLAG | V_FLAG;
462  static const byte ZSPXY0 = Z_FLAG | V_FLAG;
463  static const byte ZS255 = S_FLAG;
464  static const byte ZSXY255 = S_FLAG | X_FLAG | Y_FLAG;
465 
467 };
469 
470 } // namespace openmsx
471 
472 #endif