Skip to content

Commit e02cc42

Browse files
committed
COS: Implement PPC va_list, va_arg and update related functions
1 parent 9812a47 commit e02cc42

File tree

5 files changed

+168
-57
lines changed

5 files changed

+168
-57
lines changed

src/Cafe/OS/common/OSCommon.h

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,86 @@ void osLib_returnFromFunction64(PPCInterpreter_t* hCPU, uint64 returnValue64);
2323

2424
// utility functions
2525
#include "Cafe/OS/common/OSUtil.h"
26+
27+
// va_list
28+
struct ppc_va_list
29+
{
30+
uint8be gprIndex;
31+
uint8be fprIndex;
32+
uint8be _padding2[2];
33+
MEMPTR<uint8be> overflow_arg_area;
34+
MEMPTR<uint8be> reg_save_area;
35+
};
36+
static_assert(sizeof(ppc_va_list) == 0xC);
37+
38+
struct ppc_va_list_reg_storage
39+
{
40+
uint32be gpr_save_area[8]; // 32 bytes, r3 to r10
41+
float64be fpr_save_area[8]; // 64 bytes, f1 to f8
42+
ppc_va_list vargs;
43+
uint32be padding;
44+
};
45+
static_assert(sizeof(ppc_va_list_reg_storage) == 0x70);
46+
47+
// Equivalent of va_start for PPC HLE functions. Must be called before any StackAllocator<> definitions
48+
#define ppc_define_va_list(__gprIndex, __fprIndex) \
49+
MPTR vaOriginalR1 = PPCInterpreter_getCurrentInstance()->gpr[1]; \
50+
StackAllocator<ppc_va_list_reg_storage> va_list_storage; \
51+
for(int i=3; i<=10; i++) va_list_storage->gpr_save_area[i-3] = PPCInterpreter_getCurrentInstance()->gpr[i]; \
52+
for(int i=1; i<=8; i++) va_list_storage->fpr_save_area[i-1] = PPCInterpreter_getCurrentInstance()->fpr[i].fp0; \
53+
va_list_storage->vargs.gprIndex = __gprIndex; \
54+
va_list_storage->vargs.fprIndex = __fprIndex; \
55+
va_list_storage->vargs.reg_save_area = (uint8be*)&va_list_storage; \
56+
va_list_storage->vargs.overflow_arg_area = {vaOriginalR1 + 8}; \
57+
ppc_va_list& vargs = va_list_storage->vargs;
58+
59+
enum class ppc_va_type
60+
{
61+
INT32 = 1,
62+
INT64 = 2,
63+
FLOAT_OR_DOUBLE = 3,
64+
};
65+
66+
static void* _ppc_va_arg(ppc_va_list* vargs, ppc_va_type argType)
67+
{
68+
void* r;
69+
switch ( argType )
70+
{
71+
default:
72+
cemu_assert_suspicious();
73+
case ppc_va_type::INT32:
74+
if ( vargs[0].gprIndex < 8u )
75+
{
76+
r = &vargs->reg_save_area[4 * vargs->gprIndex];
77+
vargs->gprIndex++;
78+
return r;
79+
}
80+
r = vargs->overflow_arg_area;
81+
vargs->overflow_arg_area += 4;
82+
return r;
83+
case ppc_va_type::INT64:
84+
if ( (vargs->gprIndex & 1) != 0 )
85+
vargs->gprIndex++;
86+
if ( vargs->gprIndex < 8 )
87+
{
88+
r = &vargs->reg_save_area[4 * vargs->gprIndex];
89+
vargs->gprIndex += 2;
90+
return r;
91+
}
92+
vargs->overflow_arg_area = {(vargs->overflow_arg_area.GetMPTR()+7) & 0xFFFFFFF8};
93+
r = vargs->overflow_arg_area;
94+
vargs->overflow_arg_area += 8;
95+
return r;
96+
case ppc_va_type::FLOAT_OR_DOUBLE:
97+
if ( vargs->fprIndex < 8 )
98+
{
99+
r = &vargs->reg_save_area[0x20 + 8 * vargs->fprIndex];
100+
vargs->fprIndex++;
101+
return r;
102+
}
103+
vargs->overflow_arg_area = {(vargs->overflow_arg_area.GetMPTR()+7) & 0xFFFFFFF8};
104+
r = vargs->overflow_arg_area;
105+
vargs->overflow_arg_area += 8;
106+
return r;
107+
}
108+
}

src/Cafe/OS/libs/coreinit/coreinit_Misc.cpp

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,9 @@
77

88
namespace coreinit
99
{
10-
11-
/* coreinit logging and string format */
12-
13-
sint32 ppcSprintf(const char* formatStr, char* strOut, sint32 maxLength, PPCInterpreter_t* hCPU, sint32 initialParamIndex)
10+
sint32 ppc_vprintf(const char* formatStr, char* strOut, sint32 maxLength, ppc_va_list* vargs)
1411
{
1512
char tempStr[4096];
16-
sint32 integerParamIndex = initialParamIndex;
17-
sint32 floatParamIndex = 0;
1813
sint32 writeIndex = 0;
1914
while (*formatStr)
2015
{
@@ -101,8 +96,7 @@ namespace coreinit
10196
tempFormat[(formatStr - formatStart)] = '\0';
10297
else
10398
tempFormat[sizeof(tempFormat) - 1] = '\0';
104-
sint32 tempLen = sprintf(tempStr, tempFormat, PPCInterpreter_getCallParamU32(hCPU, integerParamIndex));
105-
integerParamIndex++;
99+
sint32 tempLen = sprintf(tempStr, tempFormat, (uint32)*(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32));
106100
for (sint32 i = 0; i < tempLen; i++)
107101
{
108102
if (writeIndex >= maxLength)
@@ -120,13 +114,12 @@ namespace coreinit
120114
tempFormat[(formatStr - formatStart)] = '\0';
121115
else
122116
tempFormat[sizeof(tempFormat) - 1] = '\0';
123-
MPTR strOffset = PPCInterpreter_getCallParamU32(hCPU, integerParamIndex);
117+
MPTR strOffset = *(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32);
124118
sint32 tempLen = 0;
125119
if (strOffset == MPTR_NULL)
126120
tempLen = sprintf(tempStr, "NULL");
127121
else
128122
tempLen = sprintf(tempStr, tempFormat, memory_getPointerFromVirtualOffset(strOffset));
129-
integerParamIndex++;
130123
for (sint32 i = 0; i < tempLen; i++)
131124
{
132125
if (writeIndex >= maxLength)
@@ -136,17 +129,16 @@ namespace coreinit
136129
}
137130
strOut[std::min(maxLength - 1, writeIndex)] = '\0';
138131
}
139-
else if (*formatStr == 'f')
132+
else if (*formatStr == 'c')
140133
{
141-
// float
134+
// character
142135
formatStr++;
143136
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
144137
if ((formatStr - formatStart) < sizeof(tempFormat))
145138
tempFormat[(formatStr - formatStart)] = '\0';
146139
else
147140
tempFormat[sizeof(tempFormat) - 1] = '\0';
148-
sint32 tempLen = sprintf(tempStr, tempFormat, (float)hCPU->fpr[1 + floatParamIndex].fp0);
149-
floatParamIndex++;
141+
sint32 tempLen = sprintf(tempStr, tempFormat, (uint32)*(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32));
150142
for (sint32 i = 0; i < tempLen; i++)
151143
{
152144
if (writeIndex >= maxLength)
@@ -155,17 +147,15 @@ namespace coreinit
155147
writeIndex++;
156148
}
157149
}
158-
else if (*formatStr == 'c')
150+
else if (*formatStr == 'f' || *formatStr == 'g' || *formatStr == 'G')
159151
{
160-
// character
161152
formatStr++;
162153
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
163154
if ((formatStr - formatStart) < sizeof(tempFormat))
164155
tempFormat[(formatStr - formatStart)] = '\0';
165156
else
166157
tempFormat[sizeof(tempFormat) - 1] = '\0';
167-
sint32 tempLen = sprintf(tempStr, tempFormat, PPCInterpreter_getCallParamU32(hCPU, integerParamIndex));
168-
integerParamIndex++;
158+
sint32 tempLen = sprintf(tempStr, tempFormat, (double)*(betype<double>*)_ppc_va_arg(vargs, ppc_va_type::FLOAT_OR_DOUBLE));
169159
for (sint32 i = 0; i < tempLen; i++)
170160
{
171161
if (writeIndex >= maxLength)
@@ -183,8 +173,7 @@ namespace coreinit
183173
tempFormat[(formatStr - formatStart)] = '\0';
184174
else
185175
tempFormat[sizeof(tempFormat) - 1] = '\0';
186-
sint32 tempLen = sprintf(tempStr, tempFormat, (double)hCPU->fpr[1 + floatParamIndex].fp0);
187-
floatParamIndex++;
176+
sint32 tempLen = sprintf(tempStr, tempFormat, (double)*(betype<double>*)_ppc_va_arg(vargs, ppc_va_type::FLOAT_OR_DOUBLE));
188177
for (sint32 i = 0; i < tempLen; i++)
189178
{
190179
if (writeIndex >= maxLength)
@@ -196,16 +185,13 @@ namespace coreinit
196185
else if ((formatStr[0] == 'l' && formatStr[1] == 'l' && (formatStr[2] == 'x' || formatStr[2] == 'X')))
197186
{
198187
formatStr += 3;
199-
// double (64bit)
188+
// 64bit int
200189
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
201190
if ((formatStr - formatStart) < sizeof(tempFormat))
202191
tempFormat[(formatStr - formatStart)] = '\0';
203192
else
204193
tempFormat[sizeof(tempFormat) - 1] = '\0';
205-
if (integerParamIndex & 1)
206-
integerParamIndex++;
207-
sint32 tempLen = sprintf(tempStr, tempFormat, PPCInterpreter_getCallParamU64(hCPU, integerParamIndex));
208-
integerParamIndex += 2;
194+
sint32 tempLen = sprintf(tempStr, tempFormat, (uint64)*(uint64be*)_ppc_va_arg(vargs, ppc_va_type::INT64));
209195
for (sint32 i = 0; i < tempLen; i++)
210196
{
211197
if (writeIndex >= maxLength)
@@ -223,10 +209,7 @@ namespace coreinit
223209
tempFormat[(formatStr - formatStart)] = '\0';
224210
else
225211
tempFormat[sizeof(tempFormat) - 1] = '\0';
226-
if (integerParamIndex & 1)
227-
integerParamIndex++;
228-
sint32 tempLen = sprintf(tempStr, tempFormat, PPCInterpreter_getCallParamU64(hCPU, integerParamIndex));
229-
integerParamIndex += 2;
212+
sint32 tempLen = sprintf(tempStr, tempFormat, (sint64)*(sint64be*)_ppc_va_arg(vargs, ppc_va_type::INT64));
230213
for (sint32 i = 0; i < tempLen; i++)
231214
{
232215
if (writeIndex >= maxLength)
@@ -255,9 +238,12 @@ namespace coreinit
255238
return std::min(writeIndex, maxLength - 1);
256239
}
257240

241+
/* coreinit logging and string format */
242+
258243
sint32 __os_snprintf(char* outputStr, sint32 maxLength, const char* formatStr)
259244
{
260-
sint32 r = ppcSprintf(formatStr, outputStr, maxLength, PPCInterpreter_getCurrentInstance(), 3);
245+
ppc_define_va_list(3, 0);
246+
sint32 r = ppc_vprintf(formatStr, outputStr, maxLength, &vargs);
261247
return r;
262248
}
263249

@@ -322,32 +308,40 @@ namespace coreinit
322308
}
323309
}
324310

311+
void COSVReport(COSReportModule module, COSReportLevel level, const char* format, ppc_va_list* vargs)
312+
{
313+
char tmpBuffer[1024];
314+
sint32 len = ppc_vprintf(format, tmpBuffer, sizeof(tmpBuffer), vargs);
315+
WriteCafeConsole(CafeLogType::OSCONSOLE, tmpBuffer, len);
316+
}
317+
325318
void OSReport(const char* format)
326319
{
327-
char buffer[1024 * 2];
328-
sint32 len = ppcSprintf(format, buffer, sizeof(buffer), PPCInterpreter_getCurrentInstance(), 1);
329-
WriteCafeConsole(CafeLogType::OSCONSOLE, buffer, len);
320+
ppc_define_va_list(1, 0);
321+
COSVReport(COSReportModule::coreinit, COSReportLevel::Info, format, &vargs);
330322
}
331323

332-
void OSVReport(const char* format, MPTR vaArgs)
324+
void OSVReport(const char* format, ppc_va_list* vargs)
333325
{
334-
cemu_assert_unimplemented();
326+
COSVReport(COSReportModule::coreinit, COSReportLevel::Info, format, vargs);
335327
}
336328

337329
void COSWarn(int moduleId, const char* format)
338330
{
339-
char buffer[1024 * 2];
340-
int prefixLen = sprintf(buffer, "[COSWarn-%d] ", moduleId);
341-
sint32 len = ppcSprintf(format, buffer + prefixLen, sizeof(buffer) - prefixLen, PPCInterpreter_getCurrentInstance(), 2);
342-
WriteCafeConsole(CafeLogType::OSCONSOLE, buffer, len + prefixLen);
331+
ppc_define_va_list(2, 0);
332+
char tmpBuffer[1024];
333+
int prefixLen = sprintf(tmpBuffer, "[COSWarn-%d] ", moduleId);
334+
sint32 len = ppc_vprintf(format, tmpBuffer + prefixLen, sizeof(tmpBuffer) - prefixLen, &vargs);
335+
WriteCafeConsole(CafeLogType::OSCONSOLE, tmpBuffer, len + prefixLen);
343336
}
344337

345338
void OSLogPrintf(int ukn1, int ukn2, int ukn3, const char* format)
346339
{
347-
char buffer[1024 * 2];
348-
int prefixLen = sprintf(buffer, "[OSLogPrintf-%d-%d-%d] ", ukn1, ukn2, ukn3);
349-
sint32 len = ppcSprintf(format, buffer + prefixLen, sizeof(buffer) - prefixLen, PPCInterpreter_getCurrentInstance(), 4);
350-
WriteCafeConsole(CafeLogType::OSCONSOLE, buffer, len + prefixLen);
340+
ppc_define_va_list(4, 0);
341+
char tmpBuffer[1024];
342+
int prefixLen = sprintf(tmpBuffer, "[OSLogPrintf-%d-%d-%d] ", ukn1, ukn2, ukn3);
343+
sint32 len = ppc_vprintf(format, tmpBuffer + prefixLen, sizeof(tmpBuffer) - prefixLen, &vargs);
344+
WriteCafeConsole(CafeLogType::OSCONSOLE, tmpBuffer, len + prefixLen);
351345
}
352346

353347
void OSConsoleWrite(const char* strPtr, sint32 length)
@@ -562,9 +556,11 @@ namespace coreinit
562556
s_transitionToForeground = false;
563557

564558
cafeExportRegister("coreinit", __os_snprintf, LogType::Placeholder);
559+
560+
cafeExportRegister("coreinit", COSVReport, LogType::Placeholder);
561+
cafeExportRegister("coreinit", COSWarn, LogType::Placeholder);
565562
cafeExportRegister("coreinit", OSReport, LogType::Placeholder);
566563
cafeExportRegister("coreinit", OSVReport, LogType::Placeholder);
567-
cafeExportRegister("coreinit", COSWarn, LogType::Placeholder);
568564
cafeExportRegister("coreinit", OSLogPrintf, LogType::Placeholder);
569565
cafeExportRegister("coreinit", OSConsoleWrite, LogType::Placeholder);
570566

src/Cafe/OS/libs/coreinit/coreinit_Misc.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,19 @@ namespace coreinit
2626
uint32 OSDriver_Register(uint32 moduleHandle, sint32 priority, OSDriverInterface* driverCallbacks, sint32 driverId, uint32be* outUkn1, uint32be* outUkn2, uint32be* outUkn3);
2727
uint32 OSDriver_Deregister(uint32 moduleHandle, sint32 driverId);
2828

29+
enum class COSReportModule
30+
{
31+
coreinit = 0,
32+
};
33+
34+
enum class COSReportLevel
35+
{
36+
Error = 0,
37+
Warn = 1,
38+
Info = 2
39+
};
40+
41+
sint32 ppc_vprintf(const char* formatStr, char* strOut, sint32 maxLength, ppc_va_list* vargs);
42+
2943
void miscInit();
3044
};

src/Common/MemPtr.h

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,19 +92,6 @@ class MEMPTR : MEMPTRBase
9292
template <typename X>
9393
explicit operator MEMPTR<X>() const { return MEMPTR<X>(this->m_value); }
9494

95-
//bool operator==(const MEMPTR<T>& v) const { return m_value == v.m_value; }
96-
//bool operator==(const T* rhs) const { return (T*)(m_value == 0 ? nullptr : memory_base + (uint32)m_value) == rhs; } -> ambigious (implicit cast to T* allows for T* == T*)
97-
//bool operator==(std::nullptr_t rhs) const { return m_value == 0; }
98-
99-
//bool operator!=(const MEMPTR<T>& v) const { return !(*this == v); }
100-
//bool operator!=(const void* rhs) const { return !(*this == rhs); }
101-
//bool operator!=(int rhs) const { return !(*this == rhs); }
102-
103-
//bool operator==(const void* rhs) const { return (void*)(m_value == 0 ? nullptr : memory_base + (uint32)m_value) == rhs; }
104-
105-
//explicit bool operator==(int rhs) const { return *this == (const void*)(size_t)rhs; }
106-
107-
10895
MEMPTR operator+(const MEMPTR& ptr) { return MEMPTR(this->GetMPTR() + ptr.GetMPTR()); }
10996
MEMPTR operator-(const MEMPTR& ptr) { return MEMPTR(this->GetMPTR() - ptr.GetMPTR()); }
11097

@@ -120,6 +107,12 @@ class MEMPTR : MEMPTRBase
120107
return MEMPTR(this->GetMPTR() - v * 4);
121108
}
122109

110+
MEMPTR& operator+=(sint32 v)
111+
{
112+
m_value += v * sizeof(T);
113+
return *this;
114+
}
115+
123116
template <class Q = T>
124117
typename std::enable_if<!std::is_same<Q, void>::value, Q>::type&
125118
operator*() const { return *GetPtr(); }

src/Common/betype.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ class betype
121121
return *this;
122122
}
123123

124+
betype<T>& operator+=(const T& v) requires std::integral<T>
125+
{
126+
m_value = SwapEndian(T(value() + v));
127+
return *this;
128+
}
129+
124130
betype<T>& operator-=(const betype<T>& v)
125131
{
126132
m_value = SwapEndian(T(value() - v.value()));
@@ -188,17 +194,36 @@ class betype
188194
return from_bevalue(T(~m_value));
189195
}
190196

197+
// pre-increment
191198
betype<T>& operator++() requires std::integral<T>
192199
{
193200
m_value = SwapEndian(T(value() + 1));
194201
return *this;
195202
}
196203

204+
// post-increment
205+
betype<T> operator++(int) requires std::integral<T>
206+
{
207+
betype<T> tmp(*this);
208+
m_value = SwapEndian(T(value() + 1));
209+
return tmp;
210+
}
211+
212+
// pre-decrement
197213
betype<T>& operator--() requires std::integral<T>
198214
{
199215
m_value = SwapEndian(T(value() - 1));
200216
return *this;
201217
}
218+
219+
// post-decrement
220+
betype<T> operator--(int) requires std::integral<T>
221+
{
222+
betype<T> tmp(*this);
223+
m_value = SwapEndian(T(value() - 1));
224+
return tmp;
225+
}
226+
202227
private:
203228
//T m_value{}; // before 1.26.2
204229
T m_value;

0 commit comments

Comments
 (0)