Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HLE/sceDmac.cpp
5663 views
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/ErrorCodes.h"
25
#include "Core/HLE/sceDmac.h"
26
#include "Core/HLE/sceKernel.h"
27
#include "Core/HLE/FunctionWrappers.h"
28
#include "Core/Debugger/Breakpoints.h"
29
#include "GPU/GPUCommon.h"
30
#include "GPU/GPUState.h"
31
32
u64 dmacMemcpyDeadline;
33
34
void __DmacInit() {
35
dmacMemcpyDeadline = 0;
36
}
37
38
void __DmacDoState(PointerWrap &p) {
39
auto s = p.Section("sceDmac", 0, 1);
40
if (s == 0) {
41
dmacMemcpyDeadline = 0;
42
return;
43
}
44
45
Do(p, dmacMemcpyDeadline);
46
}
47
48
static int __DmacMemcpy(u32 dst, u32 src, u32 size) {
49
bool skip = false;
50
if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) {
51
// We let the GPU deal with invalid range.
52
skip = gpu->PerformMemoryCopy(dst, src, size);
53
}
54
if (!skip && size != 0) {
55
currentMIPS->InvalidateICache(src, size);
56
if (Memory::IsValidRange(dst, size) && Memory::IsValidRange(src, size)) {
57
memcpy(Memory::GetPointerWriteUnchecked(dst), Memory::GetPointerUnchecked(src), size);
58
}
59
if (MemBlockInfoDetailed(size)) {
60
NotifyMemInfoCopy(dst, src, size, "DmacMemcpy/");
61
}
62
currentMIPS->InvalidateICache(dst, size);
63
}
64
65
// This number seems strangely reproducible.
66
if (size >= 272) {
67
// Approx. 225 MiB/s or 235929600 B/s, so let's go with 236 B/us.
68
int delayUs = size / 236;
69
dmacMemcpyDeadline = CoreTiming::GetTicks() + usToCycles(delayUs);
70
return delayUs;
71
} else {
72
return 0;
73
}
74
}
75
76
static u32 sceDmacMemcpy(u32 dst, u32 src, u32 size) {
77
if (size == 0) {
78
// Some games seem to do this frequently.
79
return hleLogDebug(Log::HLE, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid size");
80
}
81
if (!Memory::IsValidAddress(dst) || !Memory::IsValidAddress(src)) {
82
return hleLogError(Log::HLE, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid address (dst or src)");
83
}
84
if (dst + size >= 0x80000000 || src + size >= 0x80000000 || size >= 0x80000000) {
85
return hleLogError(Log::HLE, SCE_KERNEL_ERROR_PRIV_REQUIRED, "illegal size");
86
}
87
88
if (dmacMemcpyDeadline > CoreTiming::GetTicks()) {
89
WARN_LOG(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
}
93
94
int delay = __DmacMemcpy(dst, src, size);
95
int result = hleLogDebug(Log::HLE, 0);
96
return delay ? hleDelayResult(result, "dmac-memcpy", delay) : delay;
97
}
98
99
static u32 sceDmacTryMemcpy(u32 dst, u32 src, u32 size) {
100
if (size == 0) {
101
return hleLogError(Log::HLE, SCE_KERNEL_ERROR_INVALID_SIZE, "invalid size");
102
}
103
if (!Memory::IsValidAddress(dst) || !Memory::IsValidAddress(src)) {
104
return hleLogError(Log::HLE, SCE_KERNEL_ERROR_INVALID_POINTER, "invalid address");
105
}
106
if (dst + size >= 0x80000000 || src + size >= 0x80000000 || size >= 0x80000000) {
107
return hleLogError(Log::HLE, SCE_KERNEL_ERROR_PRIV_REQUIRED, "illegal size");
108
}
109
110
if (dmacMemcpyDeadline > CoreTiming::GetTicks()) {
111
return hleLogDebug(Log::HLE, SCE_KERNEL_ERROR_BUSY, "busy");
112
}
113
114
int delay = __DmacMemcpy(dst, src, size);
115
int result = hleLogDebug(Log::HLE, 0);
116
return delay ? hleDelayResult(result, "dmac-memcpy", delay) : delay;
117
}
118
119
const HLEFunction sceDmac[] = {
120
{0X617F3FE6, &WrapU_UUU<sceDmacMemcpy>, "sceDmacMemcpy", 'x', "xxx"},
121
{0XD97F94D8, &WrapU_UUU<sceDmacTryMemcpy>, "sceDmacTryMemcpy", 'x', "xxx"},
122
};
123
124
void Register_sceDmac() {
125
RegisterHLEModule("sceDmac", ARRAY_SIZE(sceDmac), sceDmac);
126
}
127
128