CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HLE/sceDmac.cpp
Views: 1401
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include "Common/Serialize/Serializer.h"
19
#include "Common/Serialize/SerializeFuncs.h"
20
#include "Core/CoreTiming.h"
21
#include "Core/MemMapHelpers.h"
22
#include "Core/Reporting.h"
23
#include "Core/HLE/HLE.h"
24
#include "Core/HLE/sceDmac.h"
25
#include "Core/HLE/sceKernel.h"
26
#include "Core/HLE/FunctionWrappers.h"
27
#include "Core/Debugger/Breakpoints.h"
28
#include "GPU/GPUInterface.h"
29
#include "GPU/GPUState.h"
30
31
u64 dmacMemcpyDeadline;
32
33
void __DmacInit() {
34
dmacMemcpyDeadline = 0;
35
}
36
37
void __DmacDoState(PointerWrap &p) {
38
auto s = p.Section("sceDmac", 0, 1);
39
if (s == 0) {
40
dmacMemcpyDeadline = 0;
41
return;
42
}
43
44
Do(p, dmacMemcpyDeadline);
45
}
46
47
static int __DmacMemcpy(u32 dst, u32 src, u32 size) {
48
bool skip = false;
49
if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) {
50
skip = gpu->PerformMemoryCopy(dst, src, size);
51
}
52
if (!skip && size != 0) {
53
currentMIPS->InvalidateICache(src, size);
54
if (Memory::IsValidRange(dst, size) && Memory::IsValidRange(src, size)) {
55
memcpy(Memory::GetPointerWriteUnchecked(dst), Memory::GetPointerUnchecked(src), size);
56
}
57
if (MemBlockInfoDetailed(size)) {
58
NotifyMemInfoCopy(dst, src, size, "DmacMemcpy/");
59
}
60
currentMIPS->InvalidateICache(dst, size);
61
}
62
63
// This number seems strangely reproducible.
64
if (size >= 272) {
65
// Approx. 225 MiB/s or 235929600 B/s, so let's go with 236 B/us.
66
int delayUs = size / 236;
67
dmacMemcpyDeadline = CoreTiming::GetTicks() + usToCycles(delayUs);
68
return hleDelayResult(0, "dmac copy", delayUs);
69
}
70
return 0;
71
}
72
73
static u32 sceDmacMemcpy(u32 dst, u32 src, u32 size) {
74
if (size == 0) {
75
// Some games seem to do this frequently.
76
DEBUG_LOG(Log::HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): invalid size", dst, src, size);
77
return SCE_KERNEL_ERROR_INVALID_SIZE;
78
}
79
if (!Memory::IsValidAddress(dst) || !Memory::IsValidAddress(src)) {
80
ERROR_LOG(Log::HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): invalid address", dst, src, size);
81
return SCE_KERNEL_ERROR_INVALID_POINTER;
82
}
83
if (dst + size >= 0x80000000 || src + size >= 0x80000000 || size >= 0x80000000) {
84
ERROR_LOG(Log::HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): illegal size", dst, src, size);
85
return SCE_KERNEL_ERROR_PRIV_REQUIRED;
86
}
87
88
if (dmacMemcpyDeadline > CoreTiming::GetTicks()) {
89
WARN_LOG_REPORT_ONCE(overlapDmacMemcpy, Log::HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%d): overlapping read", dst, src, size);
90
// TODO: Should block, seems like copy doesn't start until previous finishes.
91
// Might matter for overlapping copies.
92
} else {
93
DEBUG_LOG(Log::HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size);
94
}
95
96
return __DmacMemcpy(dst, src, size);
97
}
98
99
static u32 sceDmacTryMemcpy(u32 dst, u32 src, u32 size) {
100
if (size == 0) {
101
ERROR_LOG(Log::HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): invalid size", dst, src, size);
102
return SCE_KERNEL_ERROR_INVALID_SIZE;
103
}
104
if (!Memory::IsValidAddress(dst) || !Memory::IsValidAddress(src)) {
105
ERROR_LOG(Log::HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): invalid address", dst, src, size);
106
return SCE_KERNEL_ERROR_INVALID_POINTER;
107
}
108
if (dst + size >= 0x80000000 || src + size >= 0x80000000 || size >= 0x80000000) {
109
ERROR_LOG(Log::HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): illegal size", dst, src, size);
110
return SCE_KERNEL_ERROR_PRIV_REQUIRED;
111
}
112
113
if (dmacMemcpyDeadline > CoreTiming::GetTicks()) {
114
DEBUG_LOG(Log::HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): busy", dst, src, size);
115
return SCE_KERNEL_ERROR_BUSY;
116
} else {
117
DEBUG_LOG(Log::HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size);
118
}
119
120
return __DmacMemcpy(dst, src, size);
121
}
122
123
const HLEFunction sceDmac[] = {
124
{0X617F3FE6, &WrapU_UUU<sceDmacMemcpy>, "sceDmacMemcpy", 'x', "xxx"},
125
{0XD97F94D8, &WrapU_UUU<sceDmacTryMemcpy>, "sceDmacTryMemcpy", 'x', "xxx"},
126
};
127
128
void Register_sceDmac() {
129
RegisterModule("sceDmac", ARRAY_SIZE(sceDmac), sceDmac);
130
}
131
132