summaryrefslogtreecommitdiff
path: root/libpcsxcore/pgxp_mem.c
blob: 6e6323106d4615f947ad24d336b69f52bea4a9a8 (plain) (blame)
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 (?)
	}
}