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 {
22  z80regpair_8bit<OPENMSX_BIGENDIAN> b;
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 #ifdef WORK_AROUND_GCC40_SEGFAULT
194  else { abort(); return 0; }
195 #else
196  else { UNREACHABLE; return 0; }
197 #endif
198  }
199 
200  inline unsigned getAF() const { return AF_.w; }
201  inline unsigned getBC() const { return BC_.w; }
202  inline unsigned getDE() const { return DE_.w; }
203  inline unsigned getHL() const { return HL_.w; }
204  inline unsigned getAF2() const { return AF2_.w; }
205  inline unsigned getBC2() const { return BC2_.w; }
206  inline unsigned getDE2() const { return DE2_.w; }
207  inline unsigned getHL2() const { return HL2_.w; }
208  inline unsigned getIX() const { return IX_.w; }
209  inline unsigned getIY() const { return IY_.w; }
210  inline unsigned getPC() const { return PC_.w; }
211  inline unsigned getSP() const { return SP_.w; }
212  template <Reg16 R16> inline unsigned get16() const {
213  if (R16 == AF) { return getAF(); }
214  else if (R16 == BC) { return getBC(); }
215  else if (R16 == DE) { return getDE(); }
216  else if (R16 == HL) { return getHL(); }
217  else if (R16 == IX) { return getIX(); }
218  else if (R16 == IY) { return getIY(); }
219  else if (R16 == SP) { return getSP(); }
220  else { UNREACHABLE; return 0; }
221  }
222 
223  inline byte getIM() const { return IM_; }
224  inline byte getI() const { return I_; }
225  inline byte getR() const { return (R_ & Rmask) | (R2_ & ~Rmask); }
226  inline bool getIFF1() const { return IFF1_; }
227  inline bool getIFF2() const { return IFF2_; }
228  inline byte getHALT() const { return HALT_; }
229 
230  inline void setA(byte x) { AF_.b.h = x; }
231  inline void setF(byte x) { AF_.b.l = x; }
232  inline void setB(byte x) { BC_.b.h = x; }
233  inline void setC(byte x) { BC_.b.l = x; }
234  inline void setD(byte x) { DE_.b.h = x; }
235  inline void setE(byte x) { DE_.b.l = x; }
236  inline void setH(byte x) { HL_.b.h = x; }
237  inline void setL(byte x) { HL_.b.l = x; }
238  inline void setA2(byte x) { AF2_.b.h = x; }
239  inline void setF2(byte x) { AF2_.b.l = x; }
240  inline void setB2(byte x) { BC2_.b.h = x; }
241  inline void setC2(byte x) { BC2_.b.l = x; }
242  inline void setD2(byte x) { DE2_.b.h = x; }
243  inline void setE2(byte x) { DE2_.b.l = x; }
244  inline void setH2(byte x) { HL2_.b.h = x; }
245  inline void setL2(byte x) { HL2_.b.l = x; }
246  inline void setIXh(byte x) { IX_.b.h = x; }
247  inline void setIXl(byte x) { IX_.b.l = x; }
248  inline void setIYh(byte x) { IY_.b.h = x; }
249  inline void setIYl(byte x) { IY_.b.l = x; }
250  inline void setPCh(byte x) { PC_.b.h = x; }
251  inline void setPCl(byte x) { PC_.b.l = x; }
252  inline void setSPh(byte x) { SP_.b.h = x; }
253  inline void setSPl(byte x) { SP_.b.l = x; }
254  template <Reg8 R8> inline void set8(byte x) {
255  if (R8 == A) { setA(x); }
256  else if (R8 == F) { setF(x); }
257  else if (R8 == B) { setB(x); }
258  else if (R8 == C) { setC(x); }
259  else if (R8 == D) { setD(x); }
260  else if (R8 == E) { setE(x); }
261  else if (R8 == H) { setH(x); }
262  else if (R8 == L) { setL(x); }
263  else if (R8 == IXH) { setIXh(x); }
264  else if (R8 == IXL) { setIXl(x); }
265  else if (R8 == IYH) { setIYh(x); }
266  else if (R8 == IYL) { setIYl(x); }
267  else if (R8 == REG_I) { setI(x); }
268  else if (R8 == REG_R) { setR(x); }
269  else if (R8 == DUMMY) { /* nothing */ }
270  else { UNREACHABLE; }
271  }
272 
273  inline void setAF(unsigned x) { AF_.w = x; }
274  inline void setBC(unsigned x) { BC_.w = x; }
275  inline void setDE(unsigned x) { DE_.w = x; }
276  inline void setHL(unsigned x) { HL_.w = x; }
277  inline void setAF2(unsigned x) { AF2_.w = x; }
278  inline void setBC2(unsigned x) { BC2_.w = x; }
279  inline void setDE2(unsigned x) { DE2_.w = x; }
280  inline void setHL2(unsigned x) { HL2_.w = x; }
281  inline void setIX(unsigned x) { IX_.w = x; }
282  inline void setIY(unsigned x) { IY_.w = x; }
283  inline void setPC(unsigned x) { PC_.w = x; }
284  inline void setSP(unsigned x) { SP_.w = x; }
285  template <Reg16 R16> inline void set16(unsigned x) {
286  if (R16 == AF) { setAF(x); }
287  else if (R16 == BC) { setBC(x); }
288  else if (R16 == DE) { setDE(x); }
289  else if (R16 == HL) { setHL(x); }
290  else if (R16 == IX) { setIX(x); }
291  else if (R16 == IY) { setIY(x); }
292  else if (R16 == SP) { setSP(x); }
293  else { UNREACHABLE; }
294  }
295 
296  inline void setIM(byte x) { IM_ = x; }
297  inline void setI(byte x) { I_ = x; }
298  inline void setR(byte x) { R_ = x; R2_ = x; }
299  inline void setIFF1(bool x) { IFF1_ = x; }
300  inline void setIFF2(bool x) { IFF2_ = x; }
301  inline void setHALT(bool x) { HALT_ = (HALT_ & ~1) | (x ? 1 : 0); }
302  inline void setExtHALT(bool x) { HALT_ = (HALT_ & ~2) | (x ? 2 : 0); }
303 
304  inline void incR(byte x) { R_ += x; }
305 
306  // These methods are used to set/query whether the previously
307  // executed instruction was a 'EI' or 'LD A,{I,R}' instruction.
308  // Initially this could only be queried between two
309  // instructions, so e.g. after the EI instruction was executed
310  // but before the next one has started, for emulation this is
311  // good enough. But for debugging we still want to be able to
312  // query this info during the execution of the next
313  // instruction: e.g. a IO-watchpoint is triggered during the
314  // execution of some OUT instruction, at the time we evaluate
315  // the condition for that watchpoint, we still want to be able
316  // to query whether the previous instruction was a EI
317  // instruction.
318  inline bool isSameAfter() const {
319  // Between two instructions these two should be the same
320  return after_ == afterNext_;
321  }
322  inline bool getAfterEI() const {
323  assert(isSameAfter());
324  return (after_ & 0x01) != 0;
325  }
326  inline bool getAfterLDAI() const {
327  assert(isSameAfter());
328  return (after_ & 0x02) != 0;
329  }
330  inline bool debugGetAfterEI() const {
331  // Can be called during execution of an instruction
332  return (after_ & 0x01) != 0;
333  }
334  inline void clearNextAfter() {
335  // Right before executing an instruction this should be
336  // cleared
337  afterNext_ = 0x00;
338  }
339  inline bool isNextAfterClear() const {
340  // In the fast code path we avoid calling clearNextAfter()
341  // before every instruction. But in debug mode we want
342  // to verify that this optimzation is valid.
343  return afterNext_ == 0;
344  }
345  inline void setAfterEI() {
346  // Set both after_ and afterNext_. Can only be called
347  // at the end of an instruction (status of prev
348  // instruction can't be queried anymore)
349  assert(isNextAfterClear());
350  afterNext_ = after_ = 0x01;
351  }
352  inline void setAfterLDAI() {
353  // Set both, see above.
354  assert(isNextAfterClear());
355  afterNext_ = after_ = 0x02;
356  }
357  inline void copyNextAfter() {
358  // At the end of an instruction, the next flags become
359  // the current flags. setAfterEI/LDAI() already sets
360  // both after_ and afterNext_, thus calling this method
361  // is only required to clear the flags. Instructions
362  // right after a EI or LD A,I/R instruction are always
363  // executed in the slow code path. So this means that
364  // in the fast code path we don't need to call
365  // copyNextAfter().
366  after_ = afterNext_;
367  }
368 
369  template<typename Archive>
370  void serialize(Archive& ar, unsigned version);
371 
372  private:
373  z80regpair AF_, BC_, DE_, HL_;
374  z80regpair AF2_, BC2_, DE2_, HL2_;
375  z80regpair IX_, IY_, PC_, SP_;
376  bool IFF1_, IFF2_;
377  byte after_, afterNext_;
378  byte HALT_;
379  byte IM_, I_;
380  byte R_, R2_; // refresh = R & Rmask | R2 & ~Rmask
381  const byte Rmask; // 0x7F for Z80, 0xFF for R800
382  };
383 #endif
384 
388  virtual void execute(bool fastForward) = 0;
389 
395  virtual void exitCPULoopSync() = 0;
396 
400  virtual void exitCPULoopAsync() = 0;
401 
406  virtual void warp(EmuTime::param time) = 0;
407 
411  virtual EmuTime::param getCurrentTime() const = 0;
412 
417  virtual void wait(EmuTime::param time) = 0;
418 
423  virtual void waitCycles(unsigned cycles) = 0;
424 
427  virtual void setNextSyncPoint(EmuTime::param time) = 0;
428 
433  virtual void invalidateMemCache(unsigned start, unsigned num) = 0;
434 
436  virtual bool isM1Cycle(unsigned address) const = 0;
437 
440  virtual void disasmCommand(const std::vector<TclObject>& tokens,
441  TclObject& result) const = 0;
442 
445  CPURegs& getRegisters() { return R; }
446 
451  void setPaused(bool paused);
452 
453 protected:
454  CPU(bool r800);
455  virtual ~CPU();
456 
457  // flag-register tables, initialized at run-time
458  static byte ZSTable[256];
459  static byte ZSXYTable[256];
460  static byte ZSPTable[256];
461  static byte ZSPXYTable[256];
462  static byte ZSPHTable[256];
463  static const byte ZS0 = Z_FLAG;
464  static const byte ZSXY0 = Z_FLAG;
465  static const byte ZSP0 = Z_FLAG | V_FLAG;
466  static const byte ZSPXY0 = Z_FLAG | V_FLAG;
467  static const byte ZS255 = S_FLAG;
468  static const byte ZSXY255 = S_FLAG | X_FLAG | Y_FLAG;
469 
471 };
473 
474 } // namespace openmsx
475 
476 #endif