1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
|
#include "pgxp_mem.h"
#include "pgxp_cpu.h"
#include "pgxp_gte.h"
#include "pgxp_value.h"
PGXP_value Mem[3 * 2048 * 1024 / 4]; // mirror 2MB in 32-bit words * 3
const u32 UserMemOffset = 0;
const u32 ScratchOffset = 2048 * 1024 / 4;
const u32 RegisterOffset = 2 * 2048 * 1024 / 4;
const u32 InvalidAddress = 3 * 2048 * 1024 / 4;
void PGXP_InitMem()
{
memset(Mem, 0, sizeof(Mem));
}
void PGXP_Init()
{
PGXP_InitMem();
PGXP_InitCPU();
PGXP_InitGTE();
}
char* PGXP_GetMem()
{
return (char*)(Mem); // Config.PGXP_GTE ? (char*)(Mem) : NULL;
}
/* Playstation Memory Map (from Playstation doc by Joshua Walker)
0x0000_0000-0x0000_ffff Kernel (64K)
0x0001_0000-0x001f_ffff User Memory (1.9 Meg)
0x1f00_0000-0x1f00_ffff Parallel Port (64K)
0x1f80_0000-0x1f80_03ff Scratch Pad (1024 bytes)
0x1f80_1000-0x1f80_2fff Hardware Registers (8K)
0x1fc0_0000-0x1fc7_ffff BIOS (512K)
0x8000_0000-0x801f_ffff Kernel and User Memory Mirror (2 Meg) Cached
0x9fc0_0000-0x9fc7_ffff BIOS Mirror (512K) Cached
0xa000_0000-0xa01f_ffff Kernel and User Memory Mirror (2 Meg) Uncached
0xbfc0_0000-0xbfc7_ffff BIOS Mirror (512K) Uncached
*/
void ValidateAddress(u32 addr)
{
int* pi = NULL;
if ((addr >= 0x00000000) && (addr <= 0x007fffff)) {} // Kernel + User Memory x 8
else if ((addr >= 0x1f000000) && (addr <= 0x1f00ffff)) {} // Parallel Port
else if ((addr >= 0x1f800000) && (addr <= 0x1f8003ff)) {} // Scratch Pad
else if ((addr >= 0x1f801000) && (addr <= 0x1f802fff)) {} // Hardware Registers
else if ((addr >= 0x1fc00000) && (addr <= 0x1fc7ffff)) {} // Bios
else if ((addr >= 0x80000000) && (addr <= 0x807fffff)) {} // Kernel + User Memory x 8 Cached mirror
else if ((addr >= 0x9fc00000) && (addr <= 0x9fc7ffff)) {} // Bios Cached Mirror
else if ((addr >= 0xa0000000) && (addr <= 0xa07fffff)) {} // Kernel + User Memory x 8 Uncached mirror
else if ((addr >= 0xbfc00000) && (addr <= 0xbfc7ffff)) {} // Bios Uncached Mirror
else if (addr == 0xfffe0130) {} // Used for cache flushing
else
{
// *pi = 5;
}
}
u32 PGXP_ConvertAddress(u32 addr)
{
u32 memOffs = 0;
u32 paddr = addr;
ValidateAddress(addr);
switch (paddr >> 24)
{
case 0x80:
case 0xa0:
case 0x00:
// RAM further mirrored over 8MB
paddr = ((paddr & 0x7FFFFF) % 0x200000) >> 2;
paddr = UserMemOffset + paddr;
break;
default:
if ((paddr >> 20) == 0x1f8)
{
if (paddr >= 0x1f801000)
{
// paddr = ((paddr & 0xFFFF) - 0x1000);
// paddr = (paddr % 0x2000) >> 2;
paddr = ((paddr & 0xFFFF) - 0x1000) >> 2;
paddr = RegisterOffset + paddr;
break;
}
else
{
//paddr = ((paddr & 0xFFF) % 0x400) >> 2;
paddr = (paddr & 0x3FF) >> 2;
paddr = ScratchOffset + paddr;
break;
}
}
paddr = InvalidAddress;
break;
}
#ifdef GTE_LOG
//GTE_LOG("PGXP_Read %x [%x] |", addr, paddr);
#endif
return paddr;
}
PGXP_value* GetPtr(u32 addr)
{
addr = PGXP_ConvertAddress(addr);
if (addr != InvalidAddress)
return &Mem[addr];
return NULL;
}
PGXP_value* ReadMem(u32 addr)
{
return GetPtr(addr);
}
void ValidateAndCopyMem(PGXP_value* dest, u32 addr, u32 value)
{
PGXP_value* pMem = GetPtr(addr);
if (pMem != NULL)
{
Validate(pMem, value);
*dest = *pMem;
return;
}
*dest = PGXP_value_invalid_address;
}
void ValidateAndCopyMem16(PGXP_value* dest, u32 addr, u32 value, int sign)
{
u32 validMask = 0;
psx_value val, mask;
PGXP_value* pMem = GetPtr(addr);
if (pMem != NULL)
{
mask.d = val.d = 0;
// determine if high or low word
if ((addr % 4) == 2)
{
val.w.h = value;
mask.w.h = 0xFFFF;
validMask = VALID_1;
}
else
{
val.w.l = value;
mask.w.l = 0xFFFF;
validMask = VALID_0;
}
// validate and copy whole value
MaskValidate(pMem, val.d, mask.d, validMask);
*dest = *pMem;
// if high word then shift
if ((addr % 4) == 2)
{
dest->x = dest->y;
dest->lFlags = dest->hFlags;
dest->compFlags[0] = dest->compFlags[1];
}
// truncate value
dest->y = (dest->x < 0) ? -1.f * sign : 0.f;// 0.f;
dest->hFlags = 0;
dest->value = value;
dest->compFlags[1] = VALID; // iCB: High word is valid, just 0
return;
}
*dest = PGXP_value_invalid_address;
}
void WriteMem(PGXP_value* value, u32 addr)
{
PGXP_value* pMem = GetPtr(addr);
if (pMem)
*pMem = *value;
}
void WriteMem16(PGXP_value* src, u32 addr)
{
PGXP_value* dest = GetPtr(addr);
psx_value* pVal = NULL;
if (dest)
{
pVal = &dest->value;
// determine if high or low word
if ((addr % 4) == 2)
{
dest->y = src->x;
dest->hFlags = src->lFlags;
dest->compFlags[1] = src->compFlags[0];
pVal->w.h = (u16)src->value;
}
else
{
dest->x = src->x;
dest->lFlags = src->lFlags;
dest->compFlags[0] = src->compFlags[0];
pVal->w.l = (u16)src->value;
}
// overwrite z/w if valid
if (src->compFlags[2] == VALID)
{
dest->z = src->z;
dest->compFlags[2] = src->compFlags[2];
}
//dest->valid = dest->valid && src->valid;
dest->gFlags |= src->gFlags; // inherit flags from both values (?)
}
}
|