Browse code

fix mingw build, clean up new warnings

Adam Higerd authored on 2021/02/11 17:42:05
Showing 1 changed files
... ...
@@ -129,8 +129,8 @@ private:
129 129
 	enum { ASSOCIATIVITY = 1 << ASSOCIATIVESHIFT };
130 130
 	enum { BLOCKSIZE = 1 << BLOCKSIZESHIFT };
131 131
 	enum { TAGSHIFT = SIZESHIFT - ASSOCIATIVESHIFT };
132
-	enum { TAGMASK = ~0 << TAGSHIFT };
133
-	enum { BLOCKMASK = (~0 >> (32 - TAGSHIFT)) & (~0 << BLOCKSIZESHIFT) };
132
+	enum { TAGMASK = ~0U << TAGSHIFT };
133
+	enum { BLOCKMASK = (~0U >> (32 - TAGSHIFT)) & (~0U << BLOCKSIZESHIFT) };
134 134
 	enum { WORDSIZE = sizeof(uint32_t) };
135 135
 	enum { WORDSPERBLOCK = (1 << BLOCKSIZESHIFT) / WORDSIZE };
136 136
 	enum { DATAPERWORD = WORDSIZE * ASSOCIATIVITY };
Browse code

* Fixes for gcc and clang (while they can compile the code, the DLLs made aren't functional, but oh well).

* [2SF] Used more up-to-date asmjit, despite the ugly looking code.

Naram Qashat authored on 2014/09/17 19:51:45
Showing 1 changed files
... ...
@@ -226,7 +226,7 @@ extern MMU_struct_timing MMU_timing;
226 226
 // in units of cycles of the current processor.
227 227
 // this function replaces what used to be MMU_WAIT16 and MMU_WAIT32.
228 228
 // this may have side effects, so don't call it more than necessary.
229
-template<int PROCNUM, MMU_ACCESS_TYPE AT, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING> inline uint32_t _MMU_accesstime(uint32_t addr, bool sequential)
229
+template<int PROCNUM, MMU_ACCESS_TYPE AT, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING> inline uint32_t _MMU_accesstime(uint32_t addr, bool /*sequential*/)
230 230
 {
231 231
 	static const int MC = 1; // cached or tcm memory speed
232 232
 	static const int M32 = PROCNUM == ARMCPU_ARM9 ? 2 : 1; // access through 32-bit bus
Browse code

Use #pragma once instead of include guards.

Naram Qashat authored on 2014/09/08 14:47:36
Showing 1 changed files
... ...
@@ -20,8 +20,7 @@
20 20
 // this file is split from MMU.h for the purpose of avoiding ridiculous recompile times
21 21
 // when changing it, because practically everything includes MMU.h.
22 22
 
23
-#ifndef MMUTIMING_H
24
-#define MMUTIMING_H
23
+#pragma once
25 24
 
26 25
 #include <algorithm>
27 26
 #include <cmath>
... ...
@@ -382,5 +381,3 @@ template<int PROCNUM> inline uint32_t MMU_fetchExecuteCycles(uint32_t executeCyc
382 381
 	}
383 382
 	return executeCycles;
384 383
 }
385
-
386
-#endif // MMUTIMING_H
Browse code

Removed a bunch of casts, they seem to be fine without them in most cases.

Naram Qashat authored on 2013/04/18 23:22:54
Showing 1 changed files
... ...
@@ -130,8 +130,8 @@ private:
130 130
 	enum { ASSOCIATIVITY = 1 << ASSOCIATIVESHIFT };
131 131
 	enum { BLOCKSIZE = 1 << BLOCKSIZESHIFT };
132 132
 	enum { TAGSHIFT = SIZESHIFT - ASSOCIATIVESHIFT };
133
-	enum { TAGMASK = static_cast<uint32_t>(~0 << TAGSHIFT) };
134
-	enum { BLOCKMASK = (static_cast<uint32_t>(~0) >> (32 - TAGSHIFT)) & static_cast<uint32_t>(~0 << BLOCKSIZESHIFT) };
133
+	enum { TAGMASK = ~0 << TAGSHIFT };
134
+	enum { BLOCKMASK = (~0 >> (32 - TAGSHIFT)) & (~0 << BLOCKSIZESHIFT) };
135 135
 	enum { WORDSIZE = sizeof(uint32_t) };
136 136
 	enum { WORDSPERBLOCK = (1 << BLOCKSIZESHIFT) / WORDSIZE };
137 137
 	enum { DATAPERWORD = WORDSIZE * ASSOCIATIVITY };
Browse code

Updating in_2sf to use a newish version of DeSmuME, 0.9.9 from SVN. Somewhat cleaned up as well, but not everything because it's a pain in the ass.

Naram Qashat authored on 2013/04/18 17:22:55
Showing 1 changed files
... ...
@@ -19,12 +19,12 @@
19 19
 
20 20
 // this file is split from MMU.h for the purpose of avoiding ridiculous recompile times
21 21
 // when changing it, because practically everything includes MMU.h.
22
+
22 23
 #ifndef MMUTIMING_H
23 24
 #define MMUTIMING_H
24 25
 
25 26
 #include <algorithm>
26 27
 #include <cmath>
27
-
28 28
 #include "MMU.h"
29 29
 #include "cp15.h"
30 30
 #include "readwrite.h"
... ...
@@ -40,21 +40,21 @@
40 40
 // obviously, these defines don't cover all the variables or features needed,
41 41
 // and in particular, DMA or code+data access bus contention is still missing.
42 42
 
43
-	//disable this to prevent the advanced timing logic from ever running at all
43
+// disable this to prevent the advanced timing logic from ever running at all
44 44
 //#define ENABLE_ADVANCED_TIMING
45 45
 
46 46
 #ifdef ENABLE_ADVANCED_TIMING
47
-	// makes non-sequential accesses slower than sequential ones.
47
+// makes non-sequential accesses slower than sequential ones.
48 48
 #define ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
49
-	//(SOMETIMES THIS IS A BIG SPEED HIT!)
49
+// (SOMETIMES THIS IS A BIG SPEED HIT!)
50 50
 
51
-	// enables emulation of code fetch waits.
51
+// enables emulation of code fetch waits.
52 52
 #define ACCOUNT_FOR_CODE_FETCH_CYCLES
53 53
 
54
-	// makes access to DTCM (arm9 only) fast.
54
+// makes access to DTCM (arm9 only) fast.
55 55
 #define ACCOUNT_FOR_DATA_TCM_SPEED
56 56
 
57
-	// enables simulation of cache hits and cache misses.
57
+// enables simulation of cache hits and cache misses.
58 58
 #define ENABLE_CACHE_CONTROLLER_EMULATION
59 59
 
60 60
 #endif //ENABLE_ADVANCED_TIMING
... ...
@@ -62,7 +62,8 @@
62 62
 //
63 63
 ////////////////////////////////////////////////////////////////
64 64
 
65
-inline bool USE_TIMING() {
65
+inline bool USE_TIMING()
66
+{
66 67
 #ifdef ENABLE_ADVANCED_TIMING
67 68
 	return CommonSettings.advanced_timing;
68 69
 #else
... ...
@@ -70,25 +71,21 @@ inline bool USE_TIMING() {
70 71
 #endif
71 72
 }
72 73
 
73
-
74 74
 enum MMU_ACCESS_DIRECTION
75 75
 {
76 76
 	MMU_AD_READ, MMU_AD_WRITE
77 77
 };
78 78
 
79
-
80 79
 // note that we don't actually emulate the cache contents here,
81 80
 // only enough to guess what would be a cache hit or a cache miss.
82 81
 // this doesn't really get used unless ENABLE_CACHE_CONTROLLER_EMULATION is defined.
83
-template<int SIZESHIFT, int ASSOCIATIVESHIFT, int BLOCKSIZESHIFT>
84
-class CacheController
82
+template<int SIZESHIFT, int ASSOCIATIVESHIFT, int BLOCKSIZESHIFT> class CacheController
85 83
 {
86 84
 public:
87
-	template<MMU_ACCESS_DIRECTION DIR>
88
-	inline bool Cached(uint32_t addr)
85
+	template<MMU_ACCESS_DIRECTION DIR> bool Cached(uint32_t addr)
89 86
 	{
90 87
 		uint32_t blockMasked = addr & BLOCKMASK;
91
-		if(blockMasked == m_cacheCache)
88
+		if (blockMasked == this->m_cacheCache)
92 89
 			return true;
93 90
 		else
94 91
 			return this->CachedInternal<DIR>(addr, blockMasked);
... ...
@@ -96,58 +93,35 @@ public:
96 93
 
97 94
 	void Reset()
98 95
 	{
99
-		for(int blockIndex = 0; blockIndex < NUMBLOCKS; blockIndex++)
100
-			m_blocks[blockIndex].Reset();
101
-		m_cacheCache = ~0;
96
+		for (int blockIndex = 0; blockIndex < NUMBLOCKS; ++blockIndex)
97
+			this->m_blocks[blockIndex].Reset();
98
+		this->m_cacheCache = ~0;
102 99
 	}
103 100
 	CacheController()
104 101
 	{
105
-		Reset();
106
-	}
107
-
108
-	/*void savestate(EMUFILE* os, int)
109
-	{
110
-		write32le(m_cacheCache, os);
111
-		for(int i = 0; i < NUMBLOCKS; i++)
112
-		{
113
-			for(int j = 0; j < ASSOCIATIVITY; j++)
114
-				write32le(m_blocks[i].tag[j],os);
115
-			write32le(m_blocks[i].nextWay,os);
116
-		}
117
-	}*/
118
-	bool loadstate(EMUFILE* is, int)
119
-	{
120
-		read32le(&m_cacheCache, is);
121
-		for(int i = 0; i < NUMBLOCKS; i++)
122
-		{
123
-			for(int j = 0; j < ASSOCIATIVITY; j++)
124
-				read32le(&m_blocks[i].tag[j],is);
125
-			read32le(&m_blocks[i].nextWay,is);
126
-		}
127
-		return true;
102
+		this->Reset();
128 103
 	}
129 104
 
130 105
 private:
131
-	template<MMU_ACCESS_DIRECTION DIR>
132
-	bool CachedInternal(uint32_t addr, uint32_t blockMasked)
106
+	template<MMU_ACCESS_DIRECTION DIR> bool CachedInternal(uint32_t addr, uint32_t blockMasked)
133 107
 	{
134 108
 		uint32_t blockIndex = blockMasked >> BLOCKSIZESHIFT;
135
-		CacheBlock& block = m_blocks[blockIndex];
109
+		CacheBlock &block = this->m_blocks[blockIndex];
136 110
 		addr &= TAGMASK;
137 111
 
138
-		for(int way = 0; way < ASSOCIATIVITY; way++)
139
-			if(addr == block.tag[way])
112
+		for (int way = 0; way < ASSOCIATIVITY; ++way)
113
+			if (addr == block.tag[way])
140 114
 			{
141 115
 				// found it, already allocated
142
-				m_cacheCache = blockMasked;
116
+				this->m_cacheCache = blockMasked;
143 117
 				return true;
144 118
 			}
145
-		if(DIR == MMU_AD_READ)
119
+		if (DIR == MMU_AD_READ)
146 120
 		{
147 121
 			// TODO: support other allocation orders?
148 122
 			block.tag[block.nextWay++] = addr;
149 123
 			block.nextWay %= ASSOCIATIVITY;
150
-			m_cacheCache = blockMasked;
124
+			this->m_cacheCache = blockMasked;
151 125
 		}
152 126
 		return false;
153 127
 	}
... ...
@@ -156,8 +130,8 @@ private:
156 130
 	enum { ASSOCIATIVITY = 1 << ASSOCIATIVESHIFT };
157 131
 	enum { BLOCKSIZE = 1 << BLOCKSIZESHIFT };
158 132
 	enum { TAGSHIFT = SIZESHIFT - ASSOCIATIVESHIFT };
159
-	enum { TAGMASK = (uint32_t)(~0 << TAGSHIFT) };
160
-	enum { BLOCKMASK = ((uint32_t)~0 >> (32 - TAGSHIFT)) & (uint32_t)(~0 << BLOCKSIZESHIFT) };
133
+	enum { TAGMASK = static_cast<uint32_t>(~0 << TAGSHIFT) };
134
+	enum { BLOCKMASK = (static_cast<uint32_t>(~0) >> (32 - TAGSHIFT)) & static_cast<uint32_t>(~0 << BLOCKSIZESHIFT) };
161 135
 	enum { WORDSIZE = sizeof(uint32_t) };
162 136
 	enum { WORDSPERBLOCK = (1 << BLOCKSIZESHIFT) / WORDSIZE };
163 137
 	enum { DATAPERWORD = WORDSIZE * ASSOCIATIVITY };
... ...
@@ -166,58 +140,48 @@ private:
166 140
 
167 141
 	struct CacheBlock
168 142
 	{
169
-		uint32_t tag [ASSOCIATIVITY];
143
+		uint32_t tag[ASSOCIATIVITY];
170 144
 		uint32_t nextWay;
171 145
 
172 146
 		void Reset()
173 147
 		{
174
-			nextWay = 0;
175
-			for(int way = 0; way < ASSOCIATIVITY; way++)
176
-				tag[way] = 0;
148
+			this->nextWay = 0;
149
+			for (int way = 0; way < ASSOCIATIVITY; ++way)
150
+				this->tag[way] = 0;
177 151
 		}
178 152
 	};
179 153
 
180 154
 	uint32_t m_cacheCache; // optimization
181 155
 
182
-	CacheBlock m_blocks [NUMBLOCKS];
156
+	CacheBlock m_blocks[NUMBLOCKS];
183 157
 };
184 158
 
159
+template<int PROCNUM, MMU_ACCESS_TYPE AT, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING> inline uint32_t _MMU_accesstime(uint32_t addr, bool sequential);
185 160
 
186
-template<int PROCNUM, MMU_ACCESS_TYPE AT, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
187
-inline uint32_t _MMU_accesstime(uint32_t addr, bool sequential);
188
-
189
-
190
-template<int PROCNUM, MMU_ACCESS_TYPE AT>
191
-class FetchAccessUnit
161
+template<int PROCNUM, MMU_ACCESS_TYPE AT> class FetchAccessUnit
192 162
 {
193 163
 public:
194
-	template<int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
195
-	inline uint32_t Fetch(uint32_t address)
164
+	template<int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING> uint32_t Fetch(uint32_t address)
196 165
 	{
197
-		#ifdef ACCOUNT_FOR_CODE_FETCH_CYCLES
198
-		const bool prohibit = TIMING;
199
-		#else
200
-		const bool prohibit = false;
201
-		#endif
166
+#ifdef ACCOUNT_FOR_CODE_FETCH_CYCLES
167
+		bool prohibit = TIMING;
168
+#else
169
+		bool prohibit = false;
170
+#endif
202 171
 
203
-		if(AT == MMU_AT_CODE && !prohibit)
204
-		{
172
+		if (AT == MMU_AT_CODE && !prohibit)
205 173
 			return 1;
206
-		}
207 174
 
208 175
 		uint32_t time = _MMU_accesstime<PROCNUM, AT, READSIZE, DIRECTION,TIMING>(address,
209 176
 #ifdef ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
210
-			(TIMING?
211
-				(address == (m_lastAddress + (READSIZE>>3)))
212
-				:true
213
-			)
177
+			TIMING ? (address == m_lastAddress + (READSIZE >> 3)) : true
214 178
 #else
215 179
 			true
216 180
 #endif
217 181
 		);
218 182
 
219 183
 #ifdef ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
220
-		m_lastAddress = address;
184
+		this->m_lastAddress = address;
221 185
 #endif
222 186
 
223 187
 		return time;
... ...
@@ -225,98 +189,81 @@ public:
225 189
 
226 190
 	void Reset()
227 191
 	{
228
-		m_lastAddress = ~0;
192
+		this->m_lastAddress = ~0;
229 193
 	}
230
-	FetchAccessUnit() { this->Reset(); }
231
-
232
-	/*void savestate(EMUFILE* os, int)
233
-	{
234
-		write32le(m_lastAddress,os);
235
-	}*/
236
-	bool loadstate(EMUFILE* is, int)
194
+	FetchAccessUnit()
237 195
 	{
238
-		read32le(&m_lastAddress,is);
239
-		return true;
196
+		this->Reset();
240 197
 	}
241 198
 
242 199
 private:
243 200
 	uint32_t m_lastAddress;
244 201
 };
245 202
 
246
-
247
-
248
-
249
-
250 203
 struct MMU_struct_timing
251 204
 {
252 205
 	// technically part of the cp15, but I didn't want the dereferencing penalty.
253 206
 	// these template values correspond with the value of armcp15->cacheType.
254
-	CacheController<13,2,5> arm9codeCache; // 8192 bytes, 4-way associative, 32-byte blocks
255
-	CacheController<12,2,5> arm9dataCache; // 4096 bytes, 4-way associative, 32-byte blocks
207
+	CacheController<13, 2, 5> arm9codeCache; // 8192 bytes, 4-way associative, 32-byte blocks
208
+	CacheController<12, 2, 5> arm9dataCache; // 4096 bytes, 4-way associative, 32-byte blocks
256 209
 
257 210
 	// technically part of armcpu_t, but that struct isn't templated on PROCNUM
258
-	FetchAccessUnit<0,MMU_AT_CODE> arm9codeFetch;
259
-	FetchAccessUnit<0,MMU_AT_DATA> arm9dataFetch;
260
-	FetchAccessUnit<1,MMU_AT_CODE> arm7codeFetch;
261
-	FetchAccessUnit<1,MMU_AT_DATA> arm7dataFetch;
211
+	FetchAccessUnit<0, MMU_AT_CODE> arm9codeFetch;
212
+	FetchAccessUnit<0, MMU_AT_DATA> arm9dataFetch;
213
+	FetchAccessUnit<1, MMU_AT_CODE> arm7codeFetch;
214
+	FetchAccessUnit<1, MMU_AT_DATA> arm7dataFetch;
262 215
 
263
-	template<int PROCNUM> inline FetchAccessUnit<PROCNUM,MMU_AT_CODE>& armCodeFetch();
264
-	template<int PROCNUM> inline FetchAccessUnit<PROCNUM,MMU_AT_DATA>& armDataFetch();
216
+	template<int PROCNUM> FetchAccessUnit<PROCNUM, MMU_AT_CODE> &armCodeFetch();
217
+	template<int PROCNUM> FetchAccessUnit<PROCNUM, MMU_AT_DATA> &armDataFetch();
265 218
 };
266
-template<> inline FetchAccessUnit<0,MMU_AT_CODE>& MMU_struct_timing::armCodeFetch<0>() { return this->arm9codeFetch; }
267
-template<> inline FetchAccessUnit<1,MMU_AT_CODE>& MMU_struct_timing::armCodeFetch<1>() { return this->arm7codeFetch; }
268
-template<> inline FetchAccessUnit<0,MMU_AT_DATA>& MMU_struct_timing::armDataFetch<0>() { return this->arm9dataFetch; }
269
-template<> inline FetchAccessUnit<1,MMU_AT_DATA>& MMU_struct_timing::armDataFetch<1>() { return this->arm7dataFetch; }
270
-
219
+template<> inline FetchAccessUnit<0, MMU_AT_CODE> &MMU_struct_timing::armCodeFetch<0>() { return this->arm9codeFetch; }
220
+template<> inline FetchAccessUnit<1, MMU_AT_CODE> &MMU_struct_timing::armCodeFetch<1>() { return this->arm7codeFetch; }
221
+template<> inline FetchAccessUnit<0, MMU_AT_DATA> &MMU_struct_timing::armDataFetch<0>() { return this->arm9dataFetch; }
222
+template<> inline FetchAccessUnit<1, MMU_AT_DATA> &MMU_struct_timing::armDataFetch<1>() { return this->arm7dataFetch; }
271 223
 
272 224
 extern MMU_struct_timing MMU_timing;
273 225
 
274
-
275
-
276 226
 // calculates the time a single memory access takes,
277 227
 // in units of cycles of the current processor.
278 228
 // this function replaces what used to be MMU_WAIT16 and MMU_WAIT32.
279 229
 // this may have side effects, so don't call it more than necessary.
280
-template<int PROCNUM, MMU_ACCESS_TYPE AT, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
281
-inline uint32_t _MMU_accesstime(uint32_t addr, bool sequential)
230
+template<int PROCNUM, MMU_ACCESS_TYPE AT, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING> inline uint32_t _MMU_accesstime(uint32_t addr, bool sequential)
282 231
 {
283 232
 	static const int MC = 1; // cached or tcm memory speed
284
-	static const int M32 = (PROCNUM==ARMCPU_ARM9) ? 2 : 1; // access through 32-bit bus
285
-	static const int M16 = M32 * ((READSIZE>16) ? 2 : 1); // access through 16-bit bus
233
+	static const int M32 = PROCNUM == ARMCPU_ARM9 ? 2 : 1; // access through 32-bit bus
234
+	static const int M16 = M32 * (READSIZE > 16 ? 2 : 1); // access through 16-bit bus
286 235
 	static const int MSLW = M16 * 8; // this needs tuning
287 236
 
288
-	if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_CODE && addr < 0x02000000)
237
+	if (PROCNUM == ARMCPU_ARM9 && AT == MMU_AT_CODE && addr < 0x02000000)
289 238
 		return MC; // ITCM
290 239
 
291 240
 #ifdef ACCOUNT_FOR_DATA_TCM_SPEED
292
-	if(TIMING && PROCNUM==ARMCPU_ARM9 && AT==MMU_AT_DATA && (addr&(~0x3FFF)) == MMU.DTCMRegion)
241
+	if (TIMING && PROCNUM == ARMCPU_ARM9 && AT == MMU_AT_DATA && (addr & ~0x3FFF) == MMU.DTCMRegion)
293 242
 		return MC; // DTCM
294 243
 #endif
295 244
 
296 245
 	// for now, assume the cache is always enabled for all of main memory
297
-	if(AT != MMU_AT_DMA && TIMING && PROCNUM==ARMCPU_ARM9 && (addr & 0x0F000000) == 0x02000000)
246
+	if (AT != MMU_AT_DMA && TIMING && PROCNUM == ARMCPU_ARM9 && (addr & 0x0F000000) == 0x02000000)
298 247
 	{
299 248
 #ifdef ENABLE_CACHE_CONTROLLER_EMULATION
300 249
 		bool cached = false;
301
-		if(AT==MMU_AT_CODE)
250
+		if (AT == MMU_AT_CODE)
302 251
 			cached = MMU_timing.arm9codeCache.Cached<DIRECTION>(addr);
303
-		if(AT==MMU_AT_DATA)
252
+		if (AT == MMU_AT_DATA)
304 253
 			cached = MMU_timing.arm9dataCache.Cached<DIRECTION>(addr);
305
-		if(cached)
254
+		if (cached)
306 255
 			return MC;
307 256
 		uint32_t c;
308
-		if(sequential && AT==MMU_AT_DATA)
257
+		if (sequential && AT == MMU_AT_DATA)
309 258
 			c = M16; // bonus for sequential data access
310
-		else if(DIRECTION == MMU_AD_READ)
259
+		else if (DIRECTION == MMU_AD_READ)
311 260
 			c = M16 * 5;
312 261
 		else
313 262
 			c = M16 * 2; // should be 4, but write buffer isn't emulated yet.
314
-		if(DIRECTION == MMU_AD_READ)
315
-		{
263
+		if (DIRECTION == MMU_AD_READ)
316 264
 			// cache miss while reading means it has to fill a whole cache line
317 265
 			// by reading 32 bytes...
318
-			c += 8 * M32*2;
319
-		}
266
+			c += 8 * M32 * 2;
320 267
 		return c;
321 268
 #elif defined(ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS)
322 269
 		// this is the closest approximation I could find
... ...
@@ -326,22 +273,23 @@ inline uint32_t _MMU_accesstime(uint32_t addr, bool sequential)
326 273
 #endif
327 274
 	}
328 275
 
329
-	static const TWaitState MMU_WAIT[16*16] = {
330
-        // ITCM, ITCM, MAIN, SWI, REG, VMEM, LCD, OAM,  ROM,  ROM,  RAM,   U,  U,  U,  U, BIOS
276
+	static const TWaitState MMU_WAIT[] =
277
+	{
278
+		// ITCM, ITCM, MAIN, SWI, REG, VMEM, LCD, OAM,  ROM,  ROM,  RAM,   U,  U,  U,  U, BIOS
331 279
 #define X    MC,   MC,  M16, M32, M32,  M16, M16, M32, MSLW, MSLW, MSLW, M32,M32,M32,M32,  M32,
332 280
 		// duplicate it 16 times (this was somehow faster than using a mask of 0xF)
333 281
 		X X X X  X X X X  X X X X  X X X X
334 282
 #undef X
335 283
 	};
336 284
 
337
-	uint32_t c = MMU_WAIT[(addr >> 24)];
285
+	uint32_t c = MMU_WAIT[addr >> 24];
338 286
 
339 287
 #ifdef ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
340
-	if(TIMING && !sequential)
288
+	if (TIMING && !sequential)
341 289
 	{
342 290
 		//if(c != MC || PROCNUM==ARMCPU_ARM7) // check not needed anymore because ITCM/DTCM return earlier
343 291
 		{
344
-			c += (PROCNUM==ARMCPU_ARM9) ? 3*2 : 1;
292
+			c += PROCNUM == ARMCPU_ARM9 ? 6 : 1;
345 293
 		}
346 294
 	}
347 295
 #endif
... ...
@@ -349,76 +297,64 @@ inline uint32_t _MMU_accesstime(uint32_t addr, bool sequential)
349 297
 	return c;
350 298
 }
351 299
 
352
-
353
-
354
-
355
-
356 300
 // calculates the cycle time of a single memory access in the MEM stage.
357 301
 // to be used to calculate the memCycles argument for MMU_aluMemCycles.
358 302
 // this may have side effects, so don't call it more than necessary.
359
-template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
360
-inline uint32_t MMU_memAccessCycles(uint32_t addr)
303
+template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING> inline uint32_t MMU_memAccessCycles(uint32_t addr)
361 304
 {
362
-	if(TIMING)
363
-		return MMU_timing.armDataFetch<PROCNUM>().template Fetch<READSIZE,DIRECTION,true>((addr)&(~((READSIZE>>3)-1)));
305
+	if (TIMING)
306
+		return MMU_timing.armDataFetch<PROCNUM>().template Fetch<READSIZE, DIRECTION, true>(addr & (~((READSIZE >> 3) - 1)));
364 307
 	else
365
-		return MMU_timing.armDataFetch<PROCNUM>().template Fetch<READSIZE,DIRECTION,false>((addr)&(~((READSIZE>>3)-1)));
308
+		return MMU_timing.armDataFetch<PROCNUM>().template Fetch<READSIZE, DIRECTION, false>(addr & (~((READSIZE >> 3) - 1)));
366 309
 }
367 310
 
368
-template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION>
369
-inline uint32_t MMU_memAccessCycles(uint32_t addr)
311
+template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION> inline uint32_t MMU_memAccessCycles(uint32_t addr)
370 312
 {
371
-	if(USE_TIMING())
372
-		return MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,true>(addr);
313
+	if (USE_TIMING())
314
+		return MMU_memAccessCycles<PROCNUM, READSIZE, DIRECTION, true>(addr);
373 315
 	else
374
-		return MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,false>(addr);
316
+		return MMU_memAccessCycles<PROCNUM, READSIZE, DIRECTION, false>(addr);
375 317
 }
376 318
 
377 319
 // calculates the cycle time of a single code fetch in the FETCH stage
378 320
 // to be used to calculate the fetchCycles argument for MMU_fetchExecuteCycles.
379 321
 // this may have side effects, so don't call it more than necessary.
380
-template<int PROCNUM, int READSIZE>
381
-inline uint32_t MMU_codeFetchCycles(uint32_t addr)
322
+template<int PROCNUM, int READSIZE> inline uint32_t MMU_codeFetchCycles(uint32_t addr)
382 323
 {
383
-	if(USE_TIMING())
384
-		return MMU_timing.armCodeFetch<PROCNUM>().template Fetch<READSIZE,MMU_AD_READ,true>((addr)&(~((READSIZE>>3)-1)));
324
+	if (USE_TIMING())
325
+		return MMU_timing.armCodeFetch<PROCNUM>().template Fetch<READSIZE, MMU_AD_READ, true>(addr & (~((READSIZE >> 3) - 1)));
385 326
 	else
386
-		return MMU_timing.armCodeFetch<PROCNUM>().template Fetch<READSIZE,MMU_AD_READ,false>((addr)&(~((READSIZE>>3)-1)));
327
+		return MMU_timing.armCodeFetch<PROCNUM>().template Fetch<READSIZE, MMU_AD_READ, false>(addr & (~((READSIZE >> 3) - 1)));
387 328
 }
388 329
 
389 330
 // calculates the cycle contribution of ALU + MEM stages (= EXECUTE)
390 331
 // given ALU cycle time and the summation of multiple memory access cycle times.
391 332
 // this function might belong more in armcpu, but I don't think it matters.
392
-template<int PROCNUM>
393
-inline uint32_t MMU_aluMemCycles(uint32_t aluCycles, uint32_t memCycles)
333
+template<int PROCNUM> inline uint32_t MMU_aluMemCycles(uint32_t aluCycles, uint32_t memCycles)
394 334
 {
395
-	if(PROCNUM==ARMCPU_ARM9)
396
-	{
335
+	if (PROCNUM == ARMCPU_ARM9)
397 336
 		// ALU and MEM are different stages of the 5-stage pipeline.
398 337
 		// we approximate the pipeline throughput using max,
399 338
 		// since simply adding the cycles of each instruction together
400 339
 		// fails to take into account the parallelism of the arm pipeline
401 340
 		// and would make the emulated system unnaturally slow.
402 341
 		return std::max(aluCycles, memCycles);
403
-	}
404 342
 	else
405
-	{
406 343
 		// ALU and MEM are part of the same stage of the 3-stage pipeline,
407 344
 		// thus they occur in sequence and we can simply add the counts together.
408 345
 		return aluCycles + memCycles;
409
-	}
410 346
 }
411 347
 
412 348
 // calculates the cycle contribution of ALU + MEM stages (= EXECUTE)
413 349
 // given ALU cycle time and the description of a single memory access.
414 350
 // this may have side effects, so don't call it more than necessary.
415
-template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION>
416
-inline uint32_t MMU_aluMemAccessCycles(uint32_t aluCycles, uint32_t addr)
351
+template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION> inline uint32_t MMU_aluMemAccessCycles(uint32_t aluCycles, uint32_t addr)
417 352
 {
418 353
 	uint32_t memCycles;
419
-	if(USE_TIMING())
420
-		memCycles = MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,true>(addr);
421
-	else memCycles = MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,false>(addr);
354
+	if (USE_TIMING())
355
+		memCycles = MMU_memAccessCycles<PROCNUM, READSIZE, DIRECTION, true>(addr);
356
+	else
357
+		memCycles = MMU_memAccessCycles<PROCNUM, READSIZE, DIRECTION, false>(addr);
422 358
 	return MMU_aluMemCycles<PROCNUM>(aluCycles, memCycles);
423 359
 }
424 360
 
... ...
@@ -426,16 +362,15 @@ inline uint32_t MMU_aluMemAccessCycles(uint32_t aluCycles, uint32_t addr)
426 362
 // given executeCycles = the combined ALU+MEM cycles
427 363
 //     and fetchCycles = the cycle time of the FETCH stage
428 364
 // this function might belong more in armcpu, but I don't think it matters.
429
-template<int PROCNUM>
430
-inline uint32_t MMU_fetchExecuteCycles(uint32_t executeCycles, uint32_t fetchCycles)
365
+template<int PROCNUM> inline uint32_t MMU_fetchExecuteCycles(uint32_t executeCycles, uint32_t fetchCycles)
431 366
 {
432
-	#ifdef ACCOUNT_FOR_CODE_FETCH_CYCLES
433
-	const bool allow = true;
434
-	#else
435
-	const bool allow = false;
436
-	#endif
367
+#ifdef ACCOUNT_FOR_CODE_FETCH_CYCLES
368
+	bool allow = true;
369
+#else
370
+	bool allow = false;
371
+#endif
437 372
 
438
-	if(USE_TIMING() && allow)
373
+	if (USE_TIMING() && allow)
439 374
 	{
440 375
 		// execute and fetch are different stages of the pipeline for both arm7 and arm9.
441 376
 		// again, we approximate the pipeline throughput using max.
... ...
@@ -448,4 +383,4 @@ inline uint32_t MMU_fetchExecuteCycles(uint32_t executeCycles, uint32_t fetchCyc
448 383
 	return executeCycles;
449 384
 }
450 385
 
451
-#endif //MMUTIMING_H
386
+#endif // MMUTIMING_H
Browse code

Import actual code.

Naram Qashat authored on 2013/03/26 02:41:19
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,451 @@
1
+/*
2
+	Copyright (C) 2006 yopyop
3
+	Copyright (C) 2007 shash
4
+	Copyright (C) 2007-2011 DeSmuME team
5
+
6
+	This file is free software: you can redistribute it and/or modify
7
+	it under the terms of the GNU General Public License as published by
8
+	the Free Software Foundation, either version 2 of the License, or
9
+	(at your option) any later version.
10
+
11
+	This file is distributed in the hope that it will be useful,
12
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+	GNU General Public License for more details.
15
+
16
+	You should have received a copy of the GNU General Public License
17
+	along with the this software.  If not, see <http://www.gnu.org/licenses/>.
18
+*/
19
+
20
+// this file is split from MMU.h for the purpose of avoiding ridiculous recompile times
21
+// when changing it, because practically everything includes MMU.h.
22
+#ifndef MMUTIMING_H
23
+#define MMUTIMING_H
24
+
25
+#include <algorithm>
26
+#include <cmath>
27
+
28
+#include "MMU.h"
29
+#include "cp15.h"
30
+#include "readwrite.h"
31
+#include "NDSSystem.h"
32
+
33
+////////////////////////////////////////////////////////////////
34
+// MEMORY TIMING ACCURACY CONFIGURATION
35
+//
36
+// the more of these are enabled,
37
+// the more accurate memory access timing _should_ become.
38
+// they should be listed roughly in order of most to least important.
39
+// it's reasonable to disable some of these as a speed hack.
40
+// obviously, these defines don't cover all the variables or features needed,
41
+// and in particular, DMA or code+data access bus contention is still missing.
42
+
43
+	//disable this to prevent the advanced timing logic from ever running at all
44
+//#define ENABLE_ADVANCED_TIMING
45
+
46
+#ifdef ENABLE_ADVANCED_TIMING
47
+	// makes non-sequential accesses slower than sequential ones.
48
+#define ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
49
+	//(SOMETIMES THIS IS A BIG SPEED HIT!)
50
+
51
+	// enables emulation of code fetch waits.
52
+#define ACCOUNT_FOR_CODE_FETCH_CYCLES
53
+
54
+	// makes access to DTCM (arm9 only) fast.
55
+#define ACCOUNT_FOR_DATA_TCM_SPEED
56
+
57
+	// enables simulation of cache hits and cache misses.
58
+#define ENABLE_CACHE_CONTROLLER_EMULATION
59
+
60
+#endif //ENABLE_ADVANCED_TIMING
61
+
62
+//
63
+////////////////////////////////////////////////////////////////
64
+
65
+inline bool USE_TIMING() {
66
+#ifdef ENABLE_ADVANCED_TIMING
67
+	return CommonSettings.advanced_timing;
68
+#else
69
+	return false;
70
+#endif
71
+}
72
+
73
+
74
+enum MMU_ACCESS_DIRECTION
75
+{
76
+	MMU_AD_READ, MMU_AD_WRITE
77
+};
78
+
79
+
80
+// note that we don't actually emulate the cache contents here,
81
+// only enough to guess what would be a cache hit or a cache miss.
82
+// this doesn't really get used unless ENABLE_CACHE_CONTROLLER_EMULATION is defined.
83
+template<int SIZESHIFT, int ASSOCIATIVESHIFT, int BLOCKSIZESHIFT>
84
+class CacheController
85
+{
86
+public:
87
+	template<MMU_ACCESS_DIRECTION DIR>
88
+	inline bool Cached(uint32_t addr)
89
+	{
90
+		uint32_t blockMasked = addr & BLOCKMASK;
91
+		if(blockMasked == m_cacheCache)
92
+			return true;
93
+		else
94
+			return this->CachedInternal<DIR>(addr, blockMasked);
95
+	}
96
+
97
+	void Reset()
98
+	{
99
+		for(int blockIndex = 0; blockIndex < NUMBLOCKS; blockIndex++)
100
+			m_blocks[blockIndex].Reset();
101
+		m_cacheCache = ~0;
102
+	}
103
+	CacheController()
104
+	{
105
+		Reset();
106
+	}
107
+
108
+	/*void savestate(EMUFILE* os, int)
109
+	{
110
+		write32le(m_cacheCache, os);
111
+		for(int i = 0; i < NUMBLOCKS; i++)
112
+		{
113
+			for(int j = 0; j < ASSOCIATIVITY; j++)
114
+				write32le(m_blocks[i].tag[j],os);
115
+			write32le(m_blocks[i].nextWay,os);
116
+		}
117
+	}*/
118
+	bool loadstate(EMUFILE* is, int)
119
+	{
120
+		read32le(&m_cacheCache, is);
121
+		for(int i = 0; i < NUMBLOCKS; i++)
122
+		{
123
+			for(int j = 0; j < ASSOCIATIVITY; j++)
124
+				read32le(&m_blocks[i].tag[j],is);
125
+			read32le(&m_blocks[i].nextWay,is);
126
+		}
127
+		return true;
128
+	}
129
+
130
+private:
131
+	template<MMU_ACCESS_DIRECTION DIR>
132
+	bool CachedInternal(uint32_t addr, uint32_t blockMasked)
133
+	{
134
+		uint32_t blockIndex = blockMasked >> BLOCKSIZESHIFT;
135
+		CacheBlock& block = m_blocks[blockIndex];
136
+		addr &= TAGMASK;
137
+
138
+		for(int way = 0; way < ASSOCIATIVITY; way++)
139
+			if(addr == block.tag[way])
140
+			{
141
+				// found it, already allocated
142
+				m_cacheCache = blockMasked;
143
+				return true;
144
+			}
145
+		if(DIR == MMU_AD_READ)
146
+		{
147
+			// TODO: support other allocation orders?
148
+			block.tag[block.nextWay++] = addr;
149
+			block.nextWay %= ASSOCIATIVITY;
150
+			m_cacheCache = blockMasked;
151
+		}
152
+		return false;
153
+	}
154
+
155
+	enum { SIZE = 1 << SIZESHIFT };
156
+	enum { ASSOCIATIVITY = 1 << ASSOCIATIVESHIFT };
157
+	enum { BLOCKSIZE = 1 << BLOCKSIZESHIFT };
158
+	enum { TAGSHIFT = SIZESHIFT - ASSOCIATIVESHIFT };
159
+	enum { TAGMASK = (uint32_t)(~0 << TAGSHIFT) };
160
+	enum { BLOCKMASK = ((uint32_t)~0 >> (32 - TAGSHIFT)) & (uint32_t)(~0 << BLOCKSIZESHIFT) };
161
+	enum { WORDSIZE = sizeof(uint32_t) };
162
+	enum { WORDSPERBLOCK = (1 << BLOCKSIZESHIFT) / WORDSIZE };
163
+	enum { DATAPERWORD = WORDSIZE * ASSOCIATIVITY };
164
+	enum { DATAPERBLOCK = DATAPERWORD * WORDSPERBLOCK };
165
+	enum { NUMBLOCKS = SIZE / DATAPERBLOCK };
166
+
167
+	struct CacheBlock
168
+	{
169
+		uint32_t tag [ASSOCIATIVITY];
170
+		uint32_t nextWay;
171
+
172
+		void Reset()
173
+		{
174
+			nextWay = 0;
175
+			for(int way = 0; way < ASSOCIATIVITY; way++)
176
+				tag[way] = 0;
177
+		}
178
+	};
179
+
180
+	uint32_t m_cacheCache; // optimization
181
+
182
+	CacheBlock m_blocks [NUMBLOCKS];
183
+};
184
+
185
+
186
+template<int PROCNUM, MMU_ACCESS_TYPE AT, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
187
+inline uint32_t _MMU_accesstime(uint32_t addr, bool sequential);
188
+
189
+
190
+template<int PROCNUM, MMU_ACCESS_TYPE AT>
191
+class FetchAccessUnit
192
+{
193
+public:
194
+	template<int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
195
+	inline uint32_t Fetch(uint32_t address)
196
+	{
197
+		#ifdef ACCOUNT_FOR_CODE_FETCH_CYCLES
198
+		const bool prohibit = TIMING;
199
+		#else
200
+		const bool prohibit = false;
201
+		#endif
202
+
203
+		if(AT == MMU_AT_CODE && !prohibit)
204
+		{
205
+			return 1;
206
+		}
207
+
208
+		uint32_t time = _MMU_accesstime<PROCNUM, AT, READSIZE, DIRECTION,TIMING>(address,
209
+#ifdef ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
210
+			(TIMING?
211
+				(address == (m_lastAddress + (READSIZE>>3)))
212
+				:true
213
+			)
214
+#else
215
+			true
216
+#endif
217
+		);
218
+
219
+#ifdef ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
220
+		m_lastAddress = address;
221
+#endif
222
+
223
+		return time;
224
+	}
225
+
226
+	void Reset()
227
+	{
228
+		m_lastAddress = ~0;
229
+	}
230
+	FetchAccessUnit() { this->Reset(); }
231
+
232
+	/*void savestate(EMUFILE* os, int)
233
+	{
234
+		write32le(m_lastAddress,os);
235
+	}*/
236
+	bool loadstate(EMUFILE* is, int)
237
+	{
238
+		read32le(&m_lastAddress,is);
239
+		return true;
240
+	}
241
+
242
+private:
243
+	uint32_t m_lastAddress;
244
+};
245
+
246
+
247
+
248
+
249
+
250
+struct MMU_struct_timing
251
+{
252
+	// technically part of the cp15, but I didn't want the dereferencing penalty.
253
+	// these template values correspond with the value of armcp15->cacheType.
254
+	CacheController<13,2,5> arm9codeCache; // 8192 bytes, 4-way associative, 32-byte blocks
255
+	CacheController<12,2,5> arm9dataCache; // 4096 bytes, 4-way associative, 32-byte blocks
256
+
257
+	// technically part of armcpu_t, but that struct isn't templated on PROCNUM
258
+	FetchAccessUnit<0,MMU_AT_CODE> arm9codeFetch;
259
+	FetchAccessUnit<0,MMU_AT_DATA> arm9dataFetch;
260
+	FetchAccessUnit<1,MMU_AT_CODE> arm7codeFetch;
261
+	FetchAccessUnit<1,MMU_AT_DATA> arm7dataFetch;
262
+
263
+	template<int PROCNUM> inline FetchAccessUnit<PROCNUM,MMU_AT_CODE>& armCodeFetch();
264
+	template<int PROCNUM> inline FetchAccessUnit<PROCNUM,MMU_AT_DATA>& armDataFetch();
265
+};
266
+template<> inline FetchAccessUnit<0,MMU_AT_CODE>& MMU_struct_timing::armCodeFetch<0>() { return this->arm9codeFetch; }
267
+template<> inline FetchAccessUnit<1,MMU_AT_CODE>& MMU_struct_timing::armCodeFetch<1>() { return this->arm7codeFetch; }
268
+template<> inline FetchAccessUnit<0,MMU_AT_DATA>& MMU_struct_timing::armDataFetch<0>() { return this->arm9dataFetch; }
269
+template<> inline FetchAccessUnit<1,MMU_AT_DATA>& MMU_struct_timing::armDataFetch<1>() { return this->arm7dataFetch; }
270
+
271
+
272
+extern MMU_struct_timing MMU_timing;
273
+
274
+
275
+
276
+// calculates the time a single memory access takes,
277
+// in units of cycles of the current processor.
278
+// this function replaces what used to be MMU_WAIT16 and MMU_WAIT32.
279
+// this may have side effects, so don't call it more than necessary.
280
+template<int PROCNUM, MMU_ACCESS_TYPE AT, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
281
+inline uint32_t _MMU_accesstime(uint32_t addr, bool sequential)
282
+{
283
+	static const int MC = 1; // cached or tcm memory speed
284
+	static const int M32 = (PROCNUM==ARMCPU_ARM9) ? 2 : 1; // access through 32-bit bus
285
+	static const int M16 = M32 * ((READSIZE>16) ? 2 : 1); // access through 16-bit bus
286
+	static const int MSLW = M16 * 8; // this needs tuning
287
+
288
+	if(PROCNUM==ARMCPU_ARM9 && AT == MMU_AT_CODE && addr < 0x02000000)
289
+		return MC; // ITCM
290
+
291
+#ifdef ACCOUNT_FOR_DATA_TCM_SPEED
292
+	if(TIMING && PROCNUM==ARMCPU_ARM9 && AT==MMU_AT_DATA && (addr&(~0x3FFF)) == MMU.DTCMRegion)
293
+		return MC; // DTCM
294
+#endif
295
+
296
+	// for now, assume the cache is always enabled for all of main memory
297
+	if(AT != MMU_AT_DMA && TIMING && PROCNUM==ARMCPU_ARM9 && (addr & 0x0F000000) == 0x02000000)
298
+	{
299
+#ifdef ENABLE_CACHE_CONTROLLER_EMULATION
300
+		bool cached = false;
301
+		if(AT==MMU_AT_CODE)
302
+			cached = MMU_timing.arm9codeCache.Cached<DIRECTION>(addr);
303
+		if(AT==MMU_AT_DATA)
304
+			cached = MMU_timing.arm9dataCache.Cached<DIRECTION>(addr);
305
+		if(cached)
306
+			return MC;
307
+		uint32_t c;
308
+		if(sequential && AT==MMU_AT_DATA)
309
+			c = M16; // bonus for sequential data access
310
+		else if(DIRECTION == MMU_AD_READ)
311
+			c = M16 * 5;
312
+		else
313
+			c = M16 * 2; // should be 4, but write buffer isn't emulated yet.
314
+		if(DIRECTION == MMU_AD_READ)
315
+		{
316
+			// cache miss while reading means it has to fill a whole cache line
317
+			// by reading 32 bytes...
318
+			c += 8 * M32*2;
319
+		}
320
+		return c;
321
+#elif defined(ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS)
322
+		// this is the closest approximation I could find
323
+		// to the with-cache-controller timing
324
+		// that doesn't do any actual caching logic.
325
+		return sequential ? MC : M16;
326
+#endif
327
+	}
328
+
329
+	static const TWaitState MMU_WAIT[16*16] = {
330
+        // ITCM, ITCM, MAIN, SWI, REG, VMEM, LCD, OAM,  ROM,  ROM,  RAM,   U,  U,  U,  U, BIOS
331
+#define X    MC,   MC,  M16, M32, M32,  M16, M16, M32, MSLW, MSLW, MSLW, M32,M32,M32,M32,  M32,
332
+		// duplicate it 16 times (this was somehow faster than using a mask of 0xF)
333
+		X X X X  X X X X  X X X X  X X X X
334
+#undef X
335
+	};
336
+
337
+	uint32_t c = MMU_WAIT[(addr >> 24)];
338
+
339
+#ifdef ACCOUNT_FOR_NON_SEQUENTIAL_ACCESS
340
+	if(TIMING && !sequential)
341
+	{
342
+		//if(c != MC || PROCNUM==ARMCPU_ARM7) // check not needed anymore because ITCM/DTCM return earlier
343
+		{
344
+			c += (PROCNUM==ARMCPU_ARM9) ? 3*2 : 1;
345
+		}
346
+	}
347
+#endif
348
+
349
+	return c;
350
+}
351
+
352
+
353
+
354
+
355
+
356
+// calculates the cycle time of a single memory access in the MEM stage.
357
+// to be used to calculate the memCycles argument for MMU_aluMemCycles.
358
+// this may have side effects, so don't call it more than necessary.
359
+template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION, bool TIMING>
360
+inline uint32_t MMU_memAccessCycles(uint32_t addr)
361
+{
362
+	if(TIMING)
363
+		return MMU_timing.armDataFetch<PROCNUM>().template Fetch<READSIZE,DIRECTION,true>((addr)&(~((READSIZE>>3)-1)));
364
+	else
365
+		return MMU_timing.armDataFetch<PROCNUM>().template Fetch<READSIZE,DIRECTION,false>((addr)&(~((READSIZE>>3)-1)));
366
+}
367
+
368
+template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION>
369
+inline uint32_t MMU_memAccessCycles(uint32_t addr)
370
+{
371
+	if(USE_TIMING())
372
+		return MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,true>(addr);
373
+	else
374
+		return MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,false>(addr);
375
+}
376
+
377
+// calculates the cycle time of a single code fetch in the FETCH stage
378
+// to be used to calculate the fetchCycles argument for MMU_fetchExecuteCycles.
379
+// this may have side effects, so don't call it more than necessary.
380
+template<int PROCNUM, int READSIZE>
381
+inline uint32_t MMU_codeFetchCycles(uint32_t addr)
382
+{
383
+	if(USE_TIMING())
384
+		return MMU_timing.armCodeFetch<PROCNUM>().template Fetch<READSIZE,MMU_AD_READ,true>((addr)&(~((READSIZE>>3)-1)));
385
+	else
386
+		return MMU_timing.armCodeFetch<PROCNUM>().template Fetch<READSIZE,MMU_AD_READ,false>((addr)&(~((READSIZE>>3)-1)));
387
+}
388
+
389
+// calculates the cycle contribution of ALU + MEM stages (= EXECUTE)
390
+// given ALU cycle time and the summation of multiple memory access cycle times.
391
+// this function might belong more in armcpu, but I don't think it matters.
392
+template<int PROCNUM>
393
+inline uint32_t MMU_aluMemCycles(uint32_t aluCycles, uint32_t memCycles)
394
+{
395
+	if(PROCNUM==ARMCPU_ARM9)
396
+	{
397
+		// ALU and MEM are different stages of the 5-stage pipeline.
398
+		// we approximate the pipeline throughput using max,
399
+		// since simply adding the cycles of each instruction together
400
+		// fails to take into account the parallelism of the arm pipeline
401
+		// and would make the emulated system unnaturally slow.
402
+		return std::max(aluCycles, memCycles);
403
+	}
404
+	else
405
+	{
406
+		// ALU and MEM are part of the same stage of the 3-stage pipeline,
407
+		// thus they occur in sequence and we can simply add the counts together.
408
+		return aluCycles + memCycles;
409
+	}
410
+}
411
+
412
+// calculates the cycle contribution of ALU + MEM stages (= EXECUTE)
413
+// given ALU cycle time and the description of a single memory access.
414
+// this may have side effects, so don't call it more than necessary.
415
+template<int PROCNUM, int READSIZE, MMU_ACCESS_DIRECTION DIRECTION>
416
+inline uint32_t MMU_aluMemAccessCycles(uint32_t aluCycles, uint32_t addr)
417
+{
418
+	uint32_t memCycles;
419
+	if(USE_TIMING())
420
+		memCycles = MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,true>(addr);
421
+	else memCycles = MMU_memAccessCycles<PROCNUM,READSIZE,DIRECTION,false>(addr);
422
+	return MMU_aluMemCycles<PROCNUM>(aluCycles, memCycles);
423
+}
424
+
425
+// calculates the cycle contribution of FETCH + EXECUTE stages
426
+// given executeCycles = the combined ALU+MEM cycles
427
+//     and fetchCycles = the cycle time of the FETCH stage
428
+// this function might belong more in armcpu, but I don't think it matters.
429
+template<int PROCNUM>
430
+inline uint32_t MMU_fetchExecuteCycles(uint32_t executeCycles, uint32_t fetchCycles)
431
+{
432
+	#ifdef ACCOUNT_FOR_CODE_FETCH_CYCLES
433
+	const bool allow = true;
434
+	#else
435
+	const bool allow = false;
436
+	#endif
437
+
438
+	if(USE_TIMING() && allow)
439
+	{
440
+		// execute and fetch are different stages of the pipeline for both arm7 and arm9.
441
+		// again, we approximate the pipeline throughput using max.
442
+		return std::max(executeCycles, fetchCycles);
443
+		// TODO: add an option to support conflict between MEM and FETCH cycles
444
+		//  if they're both using the same data bus.
445
+		//  in the case of a conflict this should be:
446
+		//  return std::max(aluCycles, memCycles + fetchCycles);
447
+	}
448
+	return executeCycles;
449
+}
450
+
451
+#endif //MMUTIMING_H