Add mman wrapper for Win32 and use it for PCSX ReARmed libretro Win32
[pcsx_rearmed.git] / libpcsxcore / psxmem.c
CommitLineData
ef79bbde
P
1/***************************************************************************
2 * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
18 ***************************************************************************/
19
20/*
21* PSX memory functions.
22*/
23
24// TODO: Implement caches & cycle penalty.
25
26#include "psxmem.h"
87e5b45f 27#include "psxmem_map.h"
ef79bbde
P
28#include "r3000a.h"
29#include "psxhw.h"
fc8145b7 30#include "debug.h"
3a92bf0b 31
32#ifdef __LIBRETRO__
33#include "memmap.h"
34#else
ef79bbde 35#include <sys/mman.h>
3a92bf0b 36#endif
ef79bbde
P
37
38#ifndef MAP_ANONYMOUS
39#define MAP_ANONYMOUS MAP_ANON
40#endif
41
87e5b45f 42void *(*psxMapHook)(unsigned long addr, size_t size, int is_fixed,
43 enum psxMapTag tag);
44void (*psxUnmapHook)(void *ptr, size_t size, enum psxMapTag tag);
45
46void *psxMap(unsigned long addr, size_t size, int is_fixed,
47 enum psxMapTag tag)
48{
49 int flags = MAP_PRIVATE | MAP_ANONYMOUS;
b0dd9956 50 int tried_to_align = 0;
51 unsigned long mask;
87e5b45f 52 void *req, *ret;
53
b0dd9956 54retry:
55 if (psxMapHook != NULL) {
56 ret = psxMapHook(addr, size, is_fixed, tag);
57 goto out;
58 }
87e5b45f 59
0069615f 60 /* avoid MAP_FIXED, it overrides existing mappings.. */
61 /* if (is_fixed)
62 flags |= MAP_FIXED; */
87e5b45f 63
64 req = (void *)addr;
65 ret = mmap(req, size, PROT_READ | PROT_WRITE, flags, -1, 0);
66 if (ret == MAP_FAILED)
67 return NULL;
68
b0dd9956 69out:
70 if (addr != 0 && ret != (void *)addr) {
71 SysMessage("psxMap: warning: wanted to map @%08x, got %p\n",
72 addr, ret);
73
0069615f 74 if (is_fixed) {
75 psxUnmap(ret, size, tag);
76 return NULL;
77 }
78
b0dd9956 79 if (ret != NULL && ((addr ^ (long)ret) & 0x00ffffff)
80 && !tried_to_align)
81 {
82 psxUnmap(ret, size, tag);
83
84 // try to use similarly aligned memory instead
85 // (recompiler needs this)
86 mask = (addr - 1) & ~addr & 0x07ffffff;
87 addr = (unsigned long)(ret + mask) & ~mask;
88 tried_to_align = 1;
89 goto retry;
90 }
91 }
87e5b45f 92
93 return ret;
94}
95
96void psxUnmap(void *ptr, size_t size, enum psxMapTag tag)
97{
98 if (psxUnmapHook != NULL) {
99 psxUnmapHook(ptr, size, tag);
100 return;
101 }
102
88901dd2 103 if (ptr)
104 munmap(ptr, size);
87e5b45f 105}
106
ef79bbde
P
107s8 *psxM = NULL; // Kernel & User Memory (2 Meg)
108s8 *psxP = NULL; // Parallel Port (64K)
109s8 *psxR = NULL; // BIOS ROM (512K)
110s8 *psxH = NULL; // Scratch Pad (1K) & Hardware Registers (8K)
111
112u8 **psxMemWLUT = NULL;
113u8 **psxMemRLUT = NULL;
114
115/* Playstation Memory Map (from Playstation doc by Joshua Walker)
1160x0000_0000-0x0000_ffff Kernel (64K)
1170x0001_0000-0x001f_ffff User Memory (1.9 Meg)
118
1190x1f00_0000-0x1f00_ffff Parallel Port (64K)
120
1210x1f80_0000-0x1f80_03ff Scratch Pad (1024 bytes)
122
1230x1f80_1000-0x1f80_2fff Hardware Registers (8K)
124
1250x1fc0_0000-0x1fc7_ffff BIOS (512K)
126
1270x8000_0000-0x801f_ffff Kernel and User Memory Mirror (2 Meg) Cached
1280x9fc0_0000-0x9fc7_ffff BIOS Mirror (512K) Cached
129
1300xa000_0000-0xa01f_ffff Kernel and User Memory Mirror (2 Meg) Uncached
1310xbfc0_0000-0xbfc7_ffff BIOS Mirror (512K) Uncached
132*/
133
134int psxMemInit() {
135 int i;
136
137 psxMemRLUT = (u8 **)malloc(0x10000 * sizeof(void *));
138 psxMemWLUT = (u8 **)malloc(0x10000 * sizeof(void *));
139 memset(psxMemRLUT, 0, 0x10000 * sizeof(void *));
140 memset(psxMemWLUT, 0, 0x10000 * sizeof(void *));
141
87e5b45f 142 psxM = psxMap(0x80000000, 0x00210000, 1, MAP_TAG_RAM);
a327ad27 143#ifndef RAM_FIXED
a4874585
C
144#ifdef __BLACKBERRY_QNX__
145 if (psxM == NULL)
f23d3386 146 psxM = psxMap(0x77000000, 0x00210000, 0, MAP_TAG_RAM);
a4874585 147#else
87e5b45f 148 if (psxM == NULL)
b0dd9956 149 psxM = psxMap(0x78000000, 0x00210000, 0, MAP_TAG_RAM);
a4874585 150#endif
a327ad27 151#endif
87e5b45f 152 if (psxM == NULL) {
a327ad27 153 SysMessage(_("mapping main RAM failed"));
154 return -1;
155 }
ef79bbde
P
156
157 psxP = &psxM[0x200000];
4726dba0 158 psxH = psxMap(0x1f800000, 0x10000, 0, MAP_TAG_OTHER);
87e5b45f 159 psxR = psxMap(0x1fc00000, 0x80000, 0, MAP_TAG_OTHER);
ef79bbde
P
160
161 if (psxMemRLUT == NULL || psxMemWLUT == NULL ||
4726dba0 162 psxR == NULL || psxP == NULL || psxH == NULL) {
ef79bbde 163 SysMessage(_("Error allocating memory!"));
88901dd2 164 psxMemShutdown();
ef79bbde
P
165 return -1;
166 }
167
168// MemR
169 for (i = 0; i < 0x80; i++) psxMemRLUT[i + 0x0000] = (u8 *)&psxM[(i & 0x1f) << 16];
170
171 memcpy(psxMemRLUT + 0x8000, psxMemRLUT, 0x80 * sizeof(void *));
172 memcpy(psxMemRLUT + 0xa000, psxMemRLUT, 0x80 * sizeof(void *));
173
174 psxMemRLUT[0x1f00] = (u8 *)psxP;
175 psxMemRLUT[0x1f80] = (u8 *)psxH;
176
177 for (i = 0; i < 0x08; i++) psxMemRLUT[i + 0x1fc0] = (u8 *)&psxR[i << 16];
178
179 memcpy(psxMemRLUT + 0x9fc0, psxMemRLUT + 0x1fc0, 0x08 * sizeof(void *));
180 memcpy(psxMemRLUT + 0xbfc0, psxMemRLUT + 0x1fc0, 0x08 * sizeof(void *));
181
182// MemW
183 for (i = 0; i < 0x80; i++) psxMemWLUT[i + 0x0000] = (u8 *)&psxM[(i & 0x1f) << 16];
184
185 memcpy(psxMemWLUT + 0x8000, psxMemWLUT, 0x80 * sizeof(void *));
186 memcpy(psxMemWLUT + 0xa000, psxMemWLUT, 0x80 * sizeof(void *));
187
188 psxMemWLUT[0x1f00] = (u8 *)psxP;
189 psxMemWLUT[0x1f80] = (u8 *)psxH;
190
191 return 0;
192}
193
194void psxMemReset() {
195 FILE *f = NULL;
196 char bios[1024];
197
198 memset(psxM, 0, 0x00200000);
199 memset(psxP, 0, 0x00010000);
200
201 if (strcmp(Config.Bios, "HLE") != 0) {
202 sprintf(bios, "%s/%s", Config.BiosDir, Config.Bios);
203 f = fopen(bios, "rb");
204
205 if (f == NULL) {
206 SysMessage(_("Could not open BIOS:\"%s\". Enabling HLE Bios!\n"), bios);
207 memset(psxR, 0, 0x80000);
208 Config.HLE = TRUE;
209 } else {
210 fread(psxR, 1, 0x80000, f);
211 fclose(f);
212 Config.HLE = FALSE;
213 }
214 } else Config.HLE = TRUE;
215}
216
217void psxMemShutdown() {
88901dd2 218 psxUnmap(psxM, 0x00210000, MAP_TAG_RAM); psxM = NULL;
219 psxUnmap(psxH, 0x10000, MAP_TAG_OTHER); psxH = NULL;
220 psxUnmap(psxR, 0x80000, MAP_TAG_OTHER); psxR = NULL;
ef79bbde 221
88901dd2 222 free(psxMemRLUT); psxMemRLUT = NULL;
223 free(psxMemWLUT); psxMemWLUT = NULL;
ef79bbde
P
224}
225
226static int writeok = 1;
227
228u8 psxMemRead8(u32 mem) {
229 char *p;
230 u32 t;
231
232 t = mem >> 16;
9dd7d179 233 if (t == 0x1f80 || t == 0x9f80 || t == 0xbf80) {
234 if ((mem & 0xffff) < 0x400)
ef79bbde
P
235 return psxHu8(mem);
236 else
237 return psxHwRead8(mem);
238 } else {
239 p = (char *)(psxMemRLUT[t]);
240 if (p != NULL) {
241 if (Config.Debug)
242 DebugCheckBP((mem & 0xffffff) | 0x80000000, R1);
243 return *(u8 *)(p + (mem & 0xffff));
244 } else {
245#ifdef PSXMEM_LOG
246 PSXMEM_LOG("err lb %8.8lx\n", mem);
247#endif
248 return 0;
249 }
250 }
251}
252
253u16 psxMemRead16(u32 mem) {
254 char *p;
255 u32 t;
256
257 t = mem >> 16;
9dd7d179 258 if (t == 0x1f80 || t == 0x9f80 || t == 0xbf80) {
259 if ((mem & 0xffff) < 0x400)
ef79bbde
P
260 return psxHu16(mem);
261 else
262 return psxHwRead16(mem);
263 } else {
264 p = (char *)(psxMemRLUT[t]);
265 if (p != NULL) {
266 if (Config.Debug)
267 DebugCheckBP((mem & 0xffffff) | 0x80000000, R2);
268 return SWAPu16(*(u16 *)(p + (mem & 0xffff)));
269 } else {
270#ifdef PSXMEM_LOG
271 PSXMEM_LOG("err lh %8.8lx\n", mem);
272#endif
273 return 0;
274 }
275 }
276}
277
278u32 psxMemRead32(u32 mem) {
279 char *p;
280 u32 t;
281
282 t = mem >> 16;
9dd7d179 283 if (t == 0x1f80 || t == 0x9f80 || t == 0xbf80) {
284 if ((mem & 0xffff) < 0x400)
ef79bbde
P
285 return psxHu32(mem);
286 else
287 return psxHwRead32(mem);
288 } else {
289 p = (char *)(psxMemRLUT[t]);
290 if (p != NULL) {
291 if (Config.Debug)
292 DebugCheckBP((mem & 0xffffff) | 0x80000000, R4);
293 return SWAPu32(*(u32 *)(p + (mem & 0xffff)));
294 } else {
295#ifdef PSXMEM_LOG
296 if (writeok) { PSXMEM_LOG("err lw %8.8lx\n", mem); }
297#endif
298 return 0;
299 }
300 }
301}
302
303void psxMemWrite8(u32 mem, u8 value) {
304 char *p;
305 u32 t;
306
307 t = mem >> 16;
9dd7d179 308 if (t == 0x1f80 || t == 0x9f80 || t == 0xbf80) {
309 if ((mem & 0xffff) < 0x400)
ef79bbde
P
310 psxHu8(mem) = value;
311 else
312 psxHwWrite8(mem, value);
313 } else {
314 p = (char *)(psxMemWLUT[t]);
315 if (p != NULL) {
316 if (Config.Debug)
317 DebugCheckBP((mem & 0xffffff) | 0x80000000, W1);
318 *(u8 *)(p + (mem & 0xffff)) = value;
319#ifdef PSXREC
320 psxCpu->Clear((mem & (~3)), 1);
321#endif
322 } else {
323#ifdef PSXMEM_LOG
324 PSXMEM_LOG("err sb %8.8lx\n", mem);
325#endif
326 }
327 }
328}
329
330void psxMemWrite16(u32 mem, u16 value) {
331 char *p;
332 u32 t;
333
334 t = mem >> 16;
9dd7d179 335 if (t == 0x1f80 || t == 0x9f80 || t == 0xbf80) {
336 if ((mem & 0xffff) < 0x400)
ef79bbde
P
337 psxHu16ref(mem) = SWAPu16(value);
338 else
339 psxHwWrite16(mem, value);
340 } else {
341 p = (char *)(psxMemWLUT[t]);
342 if (p != NULL) {
343 if (Config.Debug)
344 DebugCheckBP((mem & 0xffffff) | 0x80000000, W2);
345 *(u16 *)(p + (mem & 0xffff)) = SWAPu16(value);
346#ifdef PSXREC
3e31e934 347 psxCpu->Clear((mem & (~3)), 1);
ef79bbde
P
348#endif
349 } else {
350#ifdef PSXMEM_LOG
351 PSXMEM_LOG("err sh %8.8lx\n", mem);
352#endif
353 }
354 }
355}
356
357void psxMemWrite32(u32 mem, u32 value) {
358 char *p;
359 u32 t;
360
361// if ((mem&0x1fffff) == 0x71E18 || value == 0x48088800) SysPrintf("t2fix!!\n");
362 t = mem >> 16;
9dd7d179 363 if (t == 0x1f80 || t == 0x9f80 || t == 0xbf80) {
364 if ((mem & 0xffff) < 0x400)
ef79bbde
P
365 psxHu32ref(mem) = SWAPu32(value);
366 else
367 psxHwWrite32(mem, value);
368 } else {
369 p = (char *)(psxMemWLUT[t]);
370 if (p != NULL) {
371 if (Config.Debug)
372 DebugCheckBP((mem & 0xffffff) | 0x80000000, W4);
373 *(u32 *)(p + (mem & 0xffff)) = SWAPu32(value);
374#ifdef PSXREC
375 psxCpu->Clear(mem, 1);
376#endif
377 } else {
378 if (mem != 0xfffe0130) {
379#ifdef PSXREC
380 if (!writeok)
381 psxCpu->Clear(mem, 1);
382#endif
383
384#ifdef PSXMEM_LOG
385 if (writeok) { PSXMEM_LOG("err sw %8.8lx\n", mem); }
386#endif
387 } else {
388 int i;
389
390 switch (value) {
391 case 0x800: case 0x804:
392 if (writeok == 0) break;
393 writeok = 0;
394 memset(psxMemWLUT + 0x0000, 0, 0x80 * sizeof(void *));
395 memset(psxMemWLUT + 0x8000, 0, 0x80 * sizeof(void *));
396 memset(psxMemWLUT + 0xa000, 0, 0x80 * sizeof(void *));
397 break;
398 case 0x00: case 0x1e988:
399 if (writeok == 1) break;
400 writeok = 1;
401 for (i = 0; i < 0x80; i++) psxMemWLUT[i + 0x0000] = (void *)&psxM[(i & 0x1f) << 16];
402 memcpy(psxMemWLUT + 0x8000, psxMemWLUT, 0x80 * sizeof(void *));
403 memcpy(psxMemWLUT + 0xa000, psxMemWLUT, 0x80 * sizeof(void *));
404 break;
405 default:
406#ifdef PSXMEM_LOG
407 PSXMEM_LOG("unk %8.8lx = %x\n", mem, value);
408#endif
409 break;
410 }
411 }
412 }
413 }
414}
415
416void *psxMemPointer(u32 mem) {
417 char *p;
418 u32 t;
419
420 t = mem >> 16;
9dd7d179 421 if (t == 0x1f80 || t == 0x9f80 || t == 0xbf80) {
422 if ((mem & 0xffff) < 0x400)
ef79bbde
P
423 return (void *)&psxH[mem];
424 else
425 return NULL;
426 } else {
427 p = (char *)(psxMemWLUT[t]);
428 if (p != NULL) {
429 return (void *)(p + (mem & 0xffff));
430 }
431 return NULL;
432 }
433}