openMSX
R800.hh
Go to the documentation of this file.
1 #ifndef R800_HH
2 #define R800_HH
3 
4 #include "CPUClock.hh"
5 #include "CPURegs.hh"
6 #include "Clock.hh"
7 #include "likely.hh"
8 #include "inline.hh"
9 #include "one_of.hh"
10 #include "xrange.hh"
11 
12 namespace openmsx {
13 
14 class R800TYPE : public CPUClock
15 {
16 public:
17  void updateVisiblePage(byte page, byte primarySlot, byte secondarySlot)
18  {
19  extraMemoryDelay[page] =
20  extraMemoryDelays[page][primarySlot][secondarySlot];
21  }
22  void setDRAMmode(bool dram)
23  {
24  // TODO currently hardcoded, move to config file?
25  unsigned val = dram ? 0 : 1;
26  extraMemoryDelays[0][0][0] = val; // BIOS
27  extraMemoryDelays[1][0][0] = val; // BASIC
28  extraMemoryDelays[0][3][1] = val; // SUB-ROM
29  extraMemoryDelays[1][3][1] = val; // KANJI-DRIVER
30  }
31 
32 protected:
33  template<bool B> struct Normalize { static constexpr bool value = B; };
34 
35  static constexpr int CLOCK_FREQ = 7159090;
36 
37  [[nodiscard]] ALWAYS_INLINE unsigned haltStates() const { return 1; } // TODO check this
38  [[nodiscard]] ALWAYS_INLINE bool isR800() const { return true; }
39 
40  R800TYPE(EmuTime::param time, Scheduler& scheduler_)
41  : CPUClock(time, scheduler_)
42  , lastRefreshTime(time)
43  {
45 
46  // TODO currently hardcoded, move to config file?
47  for (auto page : xrange(4)) {
48  for (auto prim : xrange(4)) {
49  for (auto sec : xrange(4)) {
50  extraMemoryDelays[page][prim][sec] = [&] {
51  if (prim == one_of(1, 2)) {
52  // external slot
53  return 2;
54  } else if ((prim == 3) && (sec == 0)) {
55  // internal RAM
56  return 0;
57  } else {
58  // internal ROM
59  return 1;
60  }
61  }();
62  }
63  }
64  }
65  for (auto page : xrange(4)) {
66  extraMemoryDelay[page] = extraMemoryDelays[page][0][0];
67  }
68  }
69 
71  {
72  lastPage = -1;
73  }
74 
75  template<bool PRE_PB, bool POST_PB>
76  ALWAYS_INLINE void PRE_MEM(unsigned address)
77  {
78  int newPage = address >> 8;
79  if (PRE_PB) {
80  // there is a statically predictable page break at this
81  // point -> 'add(1)' moved to static cost table
82  } else {
83  if (unlikely(newPage != lastPage) ||
84  unlikely(extraMemoryDelay[address >> 14])) {
85  add(1);
86  }
87  }
88  if (!POST_PB) {
89  lastPage = newPage;
90  }
91  }
92  template<bool POST_PB>
93  ALWAYS_INLINE void POST_MEM(unsigned address)
94  {
95  add(extraMemoryDelay[address >> 14]);
96  if (POST_PB) {
98  }
99  }
100  template<bool PRE_PB, bool POST_PB>
101  ALWAYS_INLINE void PRE_WORD(unsigned address)
102  {
103  int newPage = address >> 8;
104  if (PRE_PB) {
105  // there is a statically predictable page break at this
106  // point -> 'add(1)' moved to static cost table
107  if (unlikely(extraMemoryDelay[address >> 14])) {
108  add(1);
109  }
110  } else {
111  if (unlikely(extraMemoryDelay[address >> 14])) {
112  add(2);
113  } else if (unlikely(newPage != lastPage)) {
114  add(1);
115  }
116  }
117  if (!POST_PB) {
118  lastPage = newPage;
119  }
120  }
121  template<bool POST_PB>
122  ALWAYS_INLINE void POST_WORD(unsigned address)
123  {
124  add(2 * extraMemoryDelay[address >> 14]);
125  if (POST_PB) {
127  }
128  }
129 
131  {
132  // atoc documentation says refresh every 222 clocks
133  // duration: 256/1024KB 13.5 clocks
134  // 512KB 21.5 clocks
135  // But 26/210 matches measurements much better
136  // (loosly based on old measurements by Jon on his analogue scope)
137  EmuTime time = getTimeFast();
138  if (unlikely(lastRefreshTime.getTicksTill_fast(time) >= 210)) {
139  R800RefreshSlow(time, R); // slow-path not inline
140  }
141  }
142  NEVER_INLINE void R800RefreshSlow(EmuTime::param time, CPURegs& R)
143  {
144  do {
145  lastRefreshTime += 210;
146  } while (unlikely(lastRefreshTime.getTicksTill_fast(time) >= 210));
147  waitForEvenCycle(0);
148  add(25);
149  R800ForcePageBreak(); // TODO check this
150  R.incR(1);
151  }
152 
153  void setTime(EmuTime::param time)
154  {
155  // Base class implementation.
156  CPUClock::setTime(time);
157 
158  // Otherwise advance_fast() in R800Refresh() above, gets a too
159  // large time interval.
160  lastRefreshTime.reset(time);
161  }
162 
163  ALWAYS_INLINE void setMemPtr(unsigned /*x*/) { /* nothing*/ }
164  [[nodiscard]] ALWAYS_INLINE unsigned getMemPtr() const { return 0; } // dummy value
165 
166  static constexpr int I = 6; // cycles for an I/O operation
167  static constexpr int O = 1; // wait for one cycle and wait for next even
168  // clock cycle (to sync with slower IO bus)
169  // the latter part must be implemented
170  // dynamically (not here in static tables)
171  static constexpr int P = 1; // cycles for a (statically known) page-break
172 
173  static constexpr int
180  CC_LD_R_XIX = 3+P+1, CC_LD_R_XIX_1 = 1, CC_LD_R_XIX_2 = 3+P, // +1
185  CC_LD_XIX_R = 3+P+1, CC_LD_XIX_R_1 = 1, CC_LD_XIX_R_2 = 3+P, // +1
186  CC_LD_XIX_N = 3+P+1, CC_LD_XIX_N_1 = 1, CC_LD_XIX_N_2 = 3+P, // +1
191 
192  CC_CP_R = 1,
193  CC_CP_N = 2, CC_CP_N_1 = 1,
194  CC_CP_XHL = 1+P+1, CC_CP_XHL_1 = 1+P,
195  CC_CP_XIX = 3+P+1, CC_CP_XIX_1 = 1, CC_CP_XIX_2 = 3+P, // +1
196  CC_INC_R = 1,
197  CC_INC_XHL = 1+P+2+P+1, CC_INC_XHL_1 = 1, CC_INC_XHL_2 = 1+P+2+P,
198  CC_INC_XIX = 3+P+2+P+1, CC_INC_XIX_1 = 1, EE_INC_XIX = 2, // +1
202 
203  CC_LDI = 2+P+1+P+1, CC_LDI_1 = 2+P, CC_LDI_2 = 2+P+1+P,
204  CC_LDIR = 2+P+1+P+1,
205  CC_CPI = 2+P+2, CC_CPI_1 = 2+P,
206  CC_CPIR = 2+P+3, // TODO check
207 
208  CC_PUSH = 2+P+2, CC_PUSH_1 = 2+P,
209  CC_POP = 1+P+2, CC_POP_1 = 1+P,
210  CC_CALL = 3+P+2, CC_CALL_1 = 1, EE_CALL = 1,
211  CC_CALL_A = 3+P+2, CC_CALL_B = 3,
212  CC_RST = 2+P+2, // TODO check
213  CC_RET_A = 1+P+2, CC_RET_B = 1, EE_RET_C = 0,
214  CC_RETN = 2+P+2, EE_RETN = 1, // TODO check
215  CC_JP_A = 4, CC_JP_B = 3, CC_JP_1 = 1,
216  CC_JP_HL = 2,
217  CC_JR_A = 3, CC_JR_B = 2, CC_JR_1 = 1,
218  CC_DJNZ = 3, EE_DJNZ = 0,
219 
221 
222  CC_BIT_R = 2,
224  CC_BIT_XIX = 3+P+1, CC_BIT_XIX_1 = 3+P, // +1
225  CC_SET_R = 2,
226  CC_SET_XHL = 2+P+2+P+1, CC_SET_XHL_1 = 2+P, CC_SET_XHL_2 = 2+P+2+P,
227  CC_SET_XIX = 3+P+2+P+1, EE_SET_XIX = 1, // +1
228 
229  CC_RLA = 1,
230  CC_RLD = 2+P+2+P+1, CC_RLD_1 = 2+P, CC_RLD_2 = 2+P+2+P,
231 
234  CC_INI = 2+O+I+P+1, CC_INI_1 = 2+O, CC_INI_2 = 2+O+I+P,
235  CC_INIR = 2+O+I+P+1, // TODO check
238  CC_OUTI = 2+P+1+O+I, CC_OUTI_1 = 2+P, CC_OUTI_2 = 2+P+1+O,
239  CC_OTIR = 2+P+1+O+I, // TODO check
240 
241  CC_EX = 1,
242  CC_NOP = 1,
243  CC_CCF = 1,
244  CC_SCF = 1,
245  CC_DAA = 1,
246  CC_NEG = 2,
247  CC_CPL = 1,
248  CC_DI = 2,
249  CC_EI = 1,
250  CC_HALT = 1, // TODO check
251  CC_IM = 3,
252 
253  CC_MULUB = 14,
254  CC_MULUW = 36,
255 
256  CC_NMI = 1+P+2, EE_NMI_1 = -1, // TODO check
257  CC_IRQ0 = 1+P+2, EE_IRQ0_1 = -1, // TODO check
258  CC_IRQ1 = 1+P+2, EE_IRQ1_1 = -1, // TODO check
259  CC_IRQ2 = 1+P+2+P+2, EE_IRQ2_1 = -1, CC_IRQ2_2 = 1+P+2+P, // TODO check
260 
261  CC_MAIN = 0,
262  CC_DD = 1,
264  CC_DD_CB = 1, // +1
265  EE_ED = 1,
266  CC_RDMEM = 1,
267  CC_WRMEM = 2;
268 
269  template<typename Archive>
270  void serialize(Archive& ar, unsigned version)
271  {
272  CPUClock::serialize(ar, version);
273  ar.serialize("lastRefreshTime", lastRefreshTime,
274  "lastPage", lastPage,
275  "extraMemoryDelay", extraMemoryDelay);
276 
277  // don't serialize 'extraMemoryDelays', is initialized in
278  // constructor and setDRAMmode()
279  }
280 
281 private:
282  Clock<CLOCK_FREQ> lastRefreshTime;
283  int lastPage;
284 
285  unsigned extraMemoryDelays[4][4][4];
286  unsigned extraMemoryDelay[4];
287 };
288 
289 } // namespace openmsx
290 
291 #endif
Definition: one_of.hh:7
void add(unsigned ticks)
Definition: CPUClock.hh:27
void serialize(Archive &ar, unsigned version)
Definition: CPUClock.cc:21
EmuTime getTimeFast() const
Definition: CPUClock.hh:36
void setTime(EmuTime::param time)
Definition: CPUClock.hh:40
void waitForEvenCycle(int cc)
R800 runs at 7MHz, but I/O is done over a slower 3.5MHz bus.
Definition: CPUClock.hh:64
constexpr void reset(EmuTime::param e)
Reset the clock to start ticking at the given time.
Definition: Clock.hh:102
constexpr unsigned getTicksTill_fast(EmuTime::param e) const
Same as above, only faster, Though the time interval may not be too large.
Definition: Clock.hh:70
static constexpr int CC_MULUB
Definition: R800.hh:253
static constexpr int CC_CPI
Definition: R800.hh:205
static constexpr int CC_LD_R_R
Definition: R800.hh:177
static constexpr int CC_NEG
Definition: R800.hh:246
static constexpr int CC_LD_HL_N_2
Definition: R800.hh:182
ALWAYS_INLINE void PRE_MEM(unsigned address)
Definition: R800.hh:76
static constexpr int CC_RETN
Definition: R800.hh:214
static constexpr int CC_CALL
Definition: R800.hh:210
static constexpr int CC_LD_HL_XX_2
Definition: R800.hh:187
static constexpr int CC_LD_XX_HL_1
Definition: R800.hh:190
static constexpr int CC_IM
Definition: R800.hh:251
static constexpr int CC_LD_R_HL_1
Definition: R800.hh:179
static constexpr int CC_JR_1
Definition: R800.hh:217
static constexpr int CC_LDI_2
Definition: R800.hh:203
static constexpr int CC_CPI_1
Definition: R800.hh:205
static constexpr int CC_LD_NN_A
Definition: R800.hh:184
static constexpr int CC_LD_HL_N_1
Definition: R800.hh:182
static constexpr int CC_PUSH_1
Definition: R800.hh:208
static constexpr int CC_BIT_XIX
Definition: R800.hh:224
static constexpr int CC_INC_XIX_1
Definition: R800.hh:198
static constexpr int CC_JP_A
Definition: R800.hh:215
void serialize(Archive &ar, unsigned version)
Definition: R800.hh:270
static constexpr int CC_BIT_XHL
Definition: R800.hh:223
static constexpr int CC_LD_NN_A_2
Definition: R800.hh:184
static constexpr int CC_LD_HL_XX_1
Definition: R800.hh:187
static constexpr int CC_BIT_XHL_1
Definition: R800.hh:223
static constexpr int CC_LD_XIX_N
Definition: R800.hh:186
static constexpr int CC_WRMEM
Definition: R800.hh:267
static constexpr int CC_NOP
Definition: R800.hh:242
static constexpr int CC_RST
Definition: R800.hh:212
static constexpr int CC_JR_B
Definition: R800.hh:217
ALWAYS_INLINE void PRE_WORD(unsigned address)
Definition: R800.hh:101
static constexpr int CC_LD_SS_NN
Definition: R800.hh:189
static constexpr int CC_LD_NN_A_1
Definition: R800.hh:184
static constexpr int CC_CP_XHL_1
Definition: R800.hh:194
static constexpr int EE_ED
Definition: R800.hh:265
static constexpr int CC_JP_HL
Definition: R800.hh:216
static constexpr int CC_CALL_A
Definition: R800.hh:211
static constexpr int CC_LD_SP_HL
Definition: R800.hh:188
static constexpr int CC_DI
Definition: R800.hh:248
ALWAYS_INLINE unsigned getMemPtr() const
Definition: R800.hh:164
static constexpr int CC_LD_A_NN_1
Definition: R800.hh:175
static constexpr int CC_INC_XIX
Definition: R800.hh:198
static constexpr int EE_IRQ1_1
Definition: R800.hh:258
static constexpr int CC_RLD
Definition: R800.hh:230
static constexpr int CC_LD_XIX_N_1
Definition: R800.hh:186
static constexpr int CC_NMI
Definition: R800.hh:256
static constexpr int CLOCK_FREQ
Definition: R800.hh:35
ALWAYS_INLINE void setMemPtr(unsigned)
Definition: R800.hh:163
static constexpr int CC_CP_XIX_1
Definition: R800.hh:195
static constexpr int CC_INC_SS
Definition: R800.hh:199
void setTime(EmuTime::param time)
Definition: R800.hh:153
static constexpr int CC_LD_A_SS_1
Definition: R800.hh:174
static constexpr int CC_RET_A
Definition: R800.hh:213
static constexpr int CC_IRQ1
Definition: R800.hh:258
static constexpr int CC_LD_HL_XX
Definition: R800.hh:187
static constexpr int EE_RET_C
Definition: R800.hh:213
ALWAYS_INLINE void R800ForcePageBreak()
Definition: R800.hh:70
static constexpr int CC_LD_SS_NN_1
Definition: R800.hh:189
static constexpr int CC_CALL_B
Definition: R800.hh:211
static constexpr int CC_LD_XIX_N_2
Definition: R800.hh:186
static constexpr int CC_RDMEM
Definition: R800.hh:266
static constexpr int CC_SET_XHL_1
Definition: R800.hh:226
static constexpr int CC_ADD_HL_SS
Definition: R800.hh:200
static constexpr int CC_BIT_R
Definition: R800.hh:222
static constexpr int CC_CP_XHL
Definition: R800.hh:194
static constexpr int CC_MULUW
Definition: R800.hh:254
static constexpr int CC_DAA
Definition: R800.hh:245
static constexpr int CC_MAIN
Definition: R800.hh:261
static constexpr int CC_LD_R_N
Definition: R800.hh:178
static constexpr int CC_BIT_XIX_1
Definition: R800.hh:224
static constexpr int P
Definition: R800.hh:171
ALWAYS_INLINE bool isR800() const
Definition: R800.hh:38
static constexpr int CC_EI
Definition: R800.hh:249
static constexpr int CC_JP_B
Definition: R800.hh:215
static constexpr int CC_CCF
Definition: R800.hh:243
static constexpr int CC_LD_HL_N
Definition: R800.hh:182
static constexpr int CC_INC_XHL
Definition: R800.hh:197
static constexpr int CC_EX_SP_HL
Definition: R800.hh:220
static constexpr int CC_OUT_C_R
Definition: R800.hh:237
static constexpr int CC_EX
Definition: R800.hh:241
static constexpr int CC_PUSH
Definition: R800.hh:208
void updateVisiblePage(byte page, byte primarySlot, byte secondarySlot)
Definition: R800.hh:17
ALWAYS_INLINE void R800Refresh(CPURegs &R)
Definition: R800.hh:130
static constexpr int CC_RET_B
Definition: R800.hh:213
static constexpr int CC_SET_XHL
Definition: R800.hh:226
ALWAYS_INLINE void POST_WORD(unsigned address)
Definition: R800.hh:122
R800TYPE(EmuTime::param time, Scheduler &scheduler_)
Definition: R800.hh:40
static constexpr int CC_LD_HL_R
Definition: R800.hh:181
static constexpr int CC_LD_A_NN
Definition: R800.hh:175
static constexpr int CC_LD_R_XIX_1
Definition: R800.hh:180
static constexpr int CC_HALT
Definition: R800.hh:250
static constexpr int CC_EX_SP_HL_1
Definition: R800.hh:220
static constexpr int CC_SCF
Definition: R800.hh:244
static constexpr int CC_LD_XIX_R_2
Definition: R800.hh:185
static constexpr int CC_CP_N_1
Definition: R800.hh:193
static constexpr int CC_LD_R_HL
Definition: R800.hh:179
static constexpr int CC_LD_A_NN_2
Definition: R800.hh:175
static constexpr int CC_LD_SS_A
Definition: R800.hh:183
static constexpr int CC_EX_SP_HL_2
Definition: R800.hh:220
ALWAYS_INLINE void POST_MEM(unsigned address)
Definition: R800.hh:93
static constexpr int CC_CP_R
Definition: R800.hh:192
static constexpr int O
Definition: R800.hh:167
static constexpr int CC_LD_HL_R_1
Definition: R800.hh:181
static constexpr int CC_LD_XX_HL_2
Definition: R800.hh:190
static constexpr int CC_INI
Definition: R800.hh:234
static constexpr int CC_OUT_N_A_2
Definition: R800.hh:236
static constexpr int EE_CALL
Definition: R800.hh:210
static constexpr int CC_LD_XIX_R
Definition: R800.hh:185
NEVER_INLINE void R800RefreshSlow(EmuTime::param time, CPURegs &R)
Definition: R800.hh:142
static constexpr int CC_CALL_1
Definition: R800.hh:210
static constexpr int CC_IRQ2
Definition: R800.hh:259
void setDRAMmode(bool dram)
Definition: R800.hh:22
static constexpr int CC_DJNZ
Definition: R800.hh:218
static constexpr int CC_OUT_C_R_1
Definition: R800.hh:237
static constexpr int CC_OTIR
Definition: R800.hh:239
static constexpr int CC_RLD_1
Definition: R800.hh:230
static constexpr int CC_LD_SS_A_1
Definition: R800.hh:183
static constexpr int CC_POP_1
Definition: R800.hh:209
static constexpr int EE_RETN
Definition: R800.hh:214
static constexpr int CC_LD_XX_HL
Definition: R800.hh:190
static constexpr int CC_SET_XIX
Definition: R800.hh:227
static constexpr int CC_IN_R_C
Definition: R800.hh:233
static constexpr int CC_IRQ0
Definition: R800.hh:257
static constexpr int CC_INC_R
Definition: R800.hh:196
static constexpr int CC_LDI
Definition: R800.hh:203
static constexpr int CC_LD_XIX_R_1
Definition: R800.hh:185
static constexpr int CC_CP_XIX
Definition: R800.hh:195
static constexpr int CC_DD
Definition: R800.hh:262
static constexpr int CC_OUT_N_A_1
Definition: R800.hh:236
static constexpr int CC_OUTI_1
Definition: R800.hh:238
static constexpr int CC_IN_A_N_1
Definition: R800.hh:232
static constexpr int CC_INC_XHL_1
Definition: R800.hh:197
static constexpr int CC_LDIR
Definition: R800.hh:204
static constexpr int CC_RLD_2
Definition: R800.hh:230
static constexpr int CC_IN_A_N
Definition: R800.hh:232
static constexpr int EE_NMI_1
Definition: R800.hh:256
static constexpr int CC_CPIR
Definition: R800.hh:206
static constexpr int CC_JR_A
Definition: R800.hh:217
static constexpr int CC_LD_R_XIX_2
Definition: R800.hh:180
static constexpr int EE_IRQ0_1
Definition: R800.hh:257
static constexpr int CC_LD_A_SS
Definition: R800.hh:174
static constexpr int CC_CPL
Definition: R800.hh:247
static constexpr int CC_IN_R_C_1
Definition: R800.hh:233
static constexpr int I
Definition: R800.hh:166
static constexpr int CC_SET_XHL_2
Definition: R800.hh:226
static constexpr int CC_INIR
Definition: R800.hh:235
static constexpr int CC_SET_R
Definition: R800.hh:225
static constexpr int CC_CP_XIX_2
Definition: R800.hh:195
static constexpr int EE_INC_XIX
Definition: R800.hh:198
static constexpr int CC_JP_1
Definition: R800.hh:215
static constexpr int EE_IRQ2_1
Definition: R800.hh:259
static constexpr int CC_OUTI
Definition: R800.hh:238
static constexpr int CC_LD_R_N_1
Definition: R800.hh:178
static constexpr int EE_DJNZ
Definition: R800.hh:218
static constexpr int CC_ADC_HL_SS
Definition: R800.hh:201
static constexpr int CC_LD_A_I
Definition: R800.hh:176
static constexpr int CC_OUTI_2
Definition: R800.hh:238
static constexpr int CC_CP_N
Definition: R800.hh:193
static constexpr int CC_LD_R_XIX
Definition: R800.hh:180
static constexpr int CC_DD_CB
Definition: R800.hh:264
static constexpr int CC_PREFIX
Definition: R800.hh:263
static constexpr int CC_POP
Definition: R800.hh:209
static constexpr int CC_INI_2
Definition: R800.hh:234
static constexpr int EE_SET_XIX
Definition: R800.hh:227
static constexpr int CC_IRQ2_2
Definition: R800.hh:259
static constexpr int CC_RLA
Definition: R800.hh:229
static constexpr int CC_INC_XHL_2
Definition: R800.hh:197
static constexpr int CC_OUT_N_A
Definition: R800.hh:236
static constexpr int CC_LDI_1
Definition: R800.hh:203
static constexpr int CC_INI_1
Definition: R800.hh:234
static constexpr int CC_IN_A_N_2
Definition: R800.hh:232
ALWAYS_INLINE unsigned haltStates() const
Definition: R800.hh:37
#define NEVER_INLINE
Definition: inline.hh:17
#define ALWAYS_INLINE
Definition: inline.hh:16
#define unlikely(x)
Definition: likely.hh:15
This file implemented 3 utility functions:
Definition: Autofire.cc:5
constexpr auto R
Definition: MSXMixer.cc:299
static constexpr bool value
Definition: R800.hh:33
constexpr auto xrange(T e)
Definition: xrange.hh:155