Nugget
Bare-metal libraries and examples for the original PlayStation
Loading...
Searching...
No Matches
memcard.cpp
Go to the documentation of this file.
1/*
2
3MIT License
4
5Copyright (c) 2026 PCSX-Redux authors
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26
27// psyqo MemoryCard and MemoryCardFileSystem, against whatever card sits in
28// MEMCARD_PORT (0 = slot 1, 1 = slot 2). THIS TEST ERASES THAT CARD. Before
29// the first write it reads the card and refuses to go on if it holds any save
30// this test did not write, so a card with real data on it survives a run on
31// the wrong slot.
32//
33// Grading: every check prints PASS or FAIL, and the run ends on
34// "memcard port N: all K checks passed" only when every check passed.
35//
36// The capacity probe writes a distinct tag to the last frame of each block and
37// reads them all back. A 128 KiB card returns 16 distinct tags. A 64 KiB card
38// that ignores the top sector address bit returns blocks 8..15's tags in
39// blocks 0..7. Either is a pass: the probe reports what the card is. The fill
40// test then writes one-block files until the filesystem stops, and checks the
41// directory after each one. Whatever the card's size, the filesystem has to
42// either keep every file intact or refuse the write; a write that reports OK
43// and breaks the directory is a failure. A 64 KiB card holds 7 one-block
44// files and refuses the 8th with OutOfSpace.
45
46#include <stdint.h>
47
50#include "psyqo/application.hh"
51#include "psyqo/gpu.hh"
53#include "psyqo/memory-card.hh"
54#include "psyqo/scene.hh"
55
56#ifndef MEMCARD_PORT
57#define MEMCARD_PORT 0
58#endif
59
60namespace {
61
62using MC = psyqo::MemoryCard;
64using Error = MC::Error;
65
66constexpr MC::Port kPort = MEMCARD_PORT == 0 ? MC::Port::Port0 : MC::Port::Port1;
67
68class MemcardTest final : public psyqo::Application {
69 void prepare() override;
70 void createScene() override;
71
72 public:
73 MC m_card;
74 FS m_fs{m_card};
75};
76
77class TestScene final : public psyqo::Scene {
78 void frame() override;
79 bool m_done = false;
80};
81
82MemcardTest app;
83TestScene scene;
84
85unsigned s_checks = 0;
86unsigned s_failures = 0;
87
88bool check(bool pass, const char *name) {
89 s_checks++;
90 if (!pass) s_failures++;
91 ramsyscall_printf("%s %s\n", pass ? "PASS" : "FAIL", name);
92 return pass;
93}
94
95bool checkError(Error got, Error want, const char *name) {
96 s_checks++;
97 bool pass = got == want;
98 if (!pass) s_failures++;
99 ramsyscall_printf("%s %s: %s", pass ? "PASS" : "FAIL", name, MC::errorMessage(got));
100 if (!pass) ramsyscall_printf(" (want %s)", MC::errorMessage(want));
101 ramsyscall_printf("\n");
102 return pass;
103}
104
105bool same(const uint8_t *a, const uint8_t *b, uint32_t len) {
106 for (uint32_t i = 0; i < len; i++) {
107 if (a[i] != b[i]) return false;
108 }
109 return true;
110}
111
112bool streq(const char *a, const char *b) {
113 for (uint32_t i = 0;; i++) {
114 if (a[i] != b[i]) return false;
115 if (a[i] == 0) return true;
116 }
117}
118
119bool startsWith(const uint8_t *s, const char *prefix) {
120 for (uint32_t i = 0; prefix[i]; i++) {
121 if (s[i] != static_cast<uint8_t>(prefix[i])) return false;
122 }
123 return true;
124}
125
126// Every file this test writes is named with this prefix.
127constexpr const char kPrefix[] = "BIMEMTEST";
128// writeFile stores the title as fullwidth Shift-JIS: 'M' 'T' is 82 6c 82 73.
129constexpr const char kTitle[] = "MT MEMCARD TEST";
130constexpr uint8_t kTitleSjis[] = {0x82, 0x6c, 0x82, 0x73};
131
132alignas(4) uint8_t s_frame[128];
133alignas(4) uint8_t s_frame2[128];
134constexpr uint32_t kBig = 9000;
135uint8_t s_payload[kBig];
136uint8_t s_readback[kBig];
137
138void fillFrame(uint8_t *frame, uint32_t seed) {
139 for (uint32_t i = 0; i < 128; i++) frame[i] = static_cast<uint8_t>(seed * 37 + i * 11 + (seed >> 8));
140}
141
142void fillPayload(uint8_t *buf, uint32_t len, uint32_t seed) {
143 uint32_t x = seed * 2654435761u + 1;
144 for (uint32_t i = 0; i < len; i++) {
145 x = x * 1103515245u + 12345u;
146 buf[i] = static_cast<uint8_t>(x >> 16);
147 }
148}
149
150void buildIcon(FS::Icon &icon, uint8_t frames) {
151 __builtin_memset(&icon, 0, sizeof(icon));
152 icon.frameCount = frames;
153 for (unsigned i = 0; i < 16; i++) icon.clut[i] = static_cast<uint16_t>(i * 0x0842);
154 for (unsigned f = 0; f < 3; f++) {
155 for (unsigned i = 0; i < 128; i++) icon.pixels[f][i] = static_cast<uint8_t>(i + f * 0x31);
156 }
157}
158
159// Reads the card before anything is written and decides whether it is ours to
160// erase: blank (frame 0 all 00 or all FF), a Sony filesystem holding only
161// files named with kPrefix, or a card a previous run left with one of its
162// title frames over frame 0 (the half-size failure the fill test looks for).
163bool cardIsOursToErase() {
164 Error e = app.m_card.readSectorBlocking(kPort, 0, s_frame);
165 if (e != Error::OK) {
166 ramsyscall_printf("REFUSE: frame 0 read failed: %s\n", MC::errorMessage(e));
167 return false;
168 }
169 bool zeros = true, ones = true;
170 for (unsigned i = 0; i < 128; i++) {
171 zeros = zeros && s_frame[i] == 0x00;
172 ones = ones && s_frame[i] == 0xff;
173 }
174 if (zeros || ones) {
175 ramsyscall_printf("card: blank (frame 0 all %s)\n", zeros ? "00" : "ff");
176 return true;
177 }
178 if (s_frame[0] == 'S' && s_frame[1] == 'C' && same(s_frame + 4, kTitleSjis, sizeof(kTitleSjis))) {
179 ramsyscall_printf("card: frame 0 holds this test's title frame, from an earlier run\n");
180 return true;
181 }
182 if (s_frame[0] != 'M' || s_frame[1] != 'C') {
183 ramsyscall_printf("REFUSE: frame 0 is neither blank nor a Sony header\n");
184 return false;
185 }
186 for (uint16_t s = 1; s <= 15; s++) {
187 e = app.m_card.readSectorBlocking(kPort, s, s_frame);
188 if (e != Error::OK) {
189 ramsyscall_printf("REFUSE: directory frame %d read failed: %s\n", s, MC::errorMessage(e));
190 return false;
191 }
192 if (s_frame[0] == 0x51 && !startsWith(s_frame + 0x0a, kPrefix)) {
193 char name[21];
194 for (unsigned i = 0; i < 20; i++) name[i] = static_cast<char>(s_frame[0x0a + i]);
195 name[20] = 0;
196 ramsyscall_printf("REFUSE: block %d holds a save this test did not write: %s\n", s, name);
197 return false;
198 }
199 }
200 ramsyscall_printf("card: Sony filesystem, no save but this test's\n");
201 return true;
202}
203
204void testRange() {
205 checkError(app.m_card.readSectorBlocking(kPort, 1024, s_frame), Error::BadSector, "read sector 1024");
206 checkError(app.m_card.writeSectorBlocking(kPort, 1024, s_frame), Error::BadSector, "write sector 1024");
207}
208
209// Returns the card's size in blocks (16 or 8), or 0 if it answered neither way.
210unsigned testCapacity() {
211 bool ok = true;
212 for (uint16_t b = 0; b < 16; b++) {
213 fillFrame(s_frame, 0xca00 + b);
214 Error e = app.m_card.writeSectorBlocking(kPort, b * 64 + 63, s_frame);
215 if (e != Error::OK) {
216 ramsyscall_printf("capacity: tag write to block %d failed: %s\n", b, MC::errorMessage(e));
217 ok = false;
218 }
219 }
220 int seen[16];
221 for (uint16_t b = 0; b < 16; b++) {
222 seen[b] = -1;
223 Error e = app.m_card.readSectorBlocking(kPort, b * 64 + 63, s_frame);
224 if (e != Error::OK) {
225 ramsyscall_printf("capacity: tag read from block %d failed: %s\n", b, MC::errorMessage(e));
226 ok = false;
227 continue;
228 }
229 for (uint32_t t = 0; t < 16; t++) {
230 fillFrame(s_frame2, 0xca00 + t);
231 if (same(s_frame, s_frame2, 128)) seen[b] = t;
232 }
233 }
234 bool full = ok, half = ok;
235 for (int b = 0; b < 16; b++) {
236 full = full && seen[b] == b;
237 half = half && seen[b] == (b < 8 ? b + 8 : b);
238 }
239 ramsyscall_printf("capacity: tags read back:");
240 for (int b = 0; b < 16; b++) ramsyscall_printf(" %d", seen[b]);
241 ramsyscall_printf("\n");
242 unsigned blocks = full ? 16 : half ? 8 : 0;
243 if (blocks == 16) ramsyscall_printf("capacity: 16 blocks, 128 KiB\n");
244 if (blocks == 8) ramsyscall_printf("capacity: 8 blocks, 64 KiB, block N+8 aliases block N\n");
245#ifdef PCSX_TESTS
246 check(blocks == 16, "capacity probe reads 16 distinct blocks");
247#else
248 check(blocks != 0, "capacity probe reads a 128 KiB or a 64 KiB card");
249#endif
250 return blocks;
251}
252
253void testRawFrames() {
254 // All below sector 512, so a 64 KiB card holds them too. Frame 40 sits in
255 // the directory block's unused area.
256 static const uint16_t sectors[] = {40, 64, 127, 300, 511};
257 bool ok = true;
258 for (int pass = 0; pass < 2; pass++) {
259 for (uint16_t s : sectors) {
260 fillFrame(s_frame, s + pass * 0x500);
261 if (pass) s_frame[0] = 0xff, s_frame[127] = 0x00;
262 Error e = app.m_card.writeSectorBlocking(kPort, s, s_frame);
263 if (e != Error::OK) {
264 ramsyscall_printf("raw: write sector %d failed: %s\n", s, MC::errorMessage(e));
265 ok = false;
266 }
267 }
268 for (uint16_t s : sectors) {
269 fillFrame(s_frame, s + pass * 0x500);
270 if (pass) s_frame[0] = 0xff, s_frame[127] = 0x00;
271 Error e = app.m_card.readSectorBlocking(kPort, s, s_frame2);
272 if (e != Error::OK || !same(s_frame, s_frame2, 128)) {
273 ramsyscall_printf("raw: sector %d pass %d: %s, %s\n", s, pass, MC::errorMessage(e),
274 e == Error::OK ? "data differs" : "no data");
275 ok = false;
276 }
277 }
278 }
279 check(ok, "raw frames: write, read back, overwrite, read back (5 sectors)");
280
281 // The callback variant, through the same interrupt-driven transport.
282 volatile bool done = false;
283 Error result = Error::Timeout;
284 __builtin_memset(s_frame2, 0, 128);
285 app.m_card.readSector(kPort, 300, s_frame2, [&](Error e) {
286 result = e;
287 done = true;
288 });
289 while (!done) app.gpu().pumpCallbacks();
290 fillFrame(s_frame, 300 + 0x500);
291 s_frame[0] = 0xff, s_frame[127] = 0x00;
292 check(result == Error::OK && same(s_frame, s_frame2, 128), "raw frames: callback read returns the frame");
293}
294
295void testFileSystem(unsigned capacity) {
296 auto &gpu = app.gpu();
297 auto &fs = app.m_fs;
298 uint32_t freeBlocks = 0, len = 0, count = 0;
299 bool exists = false;
300 FS::Icon icon;
301 buildIcon(icon, 2);
302
303 if (!checkError(fs.formatBlocking(gpu, kPort), Error::OK, "fs: format")) return;
304 checkError(fs.getCardStateBlocking(gpu, kPort), Error::OK, "fs: formatted card state");
305 Error e = fs.getFreeBlockCountBlocking(gpu, kPort, &freeBlocks);
306 // A 64 KiB card has 7 usable file blocks, a 128 KiB card 15.
307 const uint32_t usable = capacity == 8 ? 7 : 15;
308 check(e == Error::OK && freeBlocks == usable, "fs: every usable block free after format");
309
310 fillPayload(s_payload, 200, 1);
311 checkError(fs.writeFileBlocking(gpu, kPort, "BIMEMTEST-RW", kTitle, icon, s_payload, 200), Error::OK,
312 "fs: write a one-block file");
313 e = fs.fileExistsBlocking(gpu, kPort, "BIMEMTEST-RW", &exists);
314 check(e == Error::OK && exists, "fs: file exists");
315 __builtin_memset(s_readback, 0, 200);
316 e = fs.readFileBlocking(gpu, kPort, "BIMEMTEST-RW", s_readback, 200, &len);
317 check(e == Error::OK && len == 200 && same(s_payload, s_readback, 200), "fs: read back the payload");
318
319 static FS::FileInfo info;
320 e = fs.readFileInfoBlocking(gpu, kPort, "BIMEMTEST-RW", &info);
321 check(
322 e == Error::OK && same(info.title, kTitleSjis, sizeof(kTitleSjis)) && info.icon.frameCount == 2 &&
323 same(reinterpret_cast<const uint8_t *>(info.icon.clut), reinterpret_cast<const uint8_t *>(icon.clut), 32) &&
324 same(info.icon.pixels[0], icon.pixels[0], 128) && same(info.icon.pixels[1], icon.pixels[1], 128),
325 "fs: title and icon read back");
326
327 static FS::FileEntry entries[15];
328 e = fs.listFilesBlocking(gpu, kPort, entries, 15, &count);
329 check(e == Error::OK && count == 1 && streq(entries[0].name, "BIMEMTEST-RW") && entries[0].sizeInBlocks == 1 &&
330 entries[0].firstBlock == 1,
331 "fs: listing holds the one file, block 1");
332
333 // 2 header frames + 9000 bytes = 2 blocks, 2 and 3: both under block 8.
334 fillPayload(s_payload, kBig, 2);
335 checkError(fs.writeFileBlocking(gpu, kPort, "BIMEMTEST-BIG", kTitle, icon, s_payload, kBig), Error::OK,
336 "fs: write a two-block file");
337 __builtin_memset(s_readback, 0, kBig);
338 e = fs.readFileBlocking(gpu, kPort, "BIMEMTEST-BIG", s_readback, kBig, &len);
339 check(e == Error::OK && len == kBig && same(s_payload, s_readback, kBig), "fs: read back 9000 bytes");
340 e = fs.getFreeBlockCountBlocking(gpu, kPort, &freeBlocks);
341 check(e == Error::OK && freeBlocks == usable - 3, "fs: 3 fewer free blocks with 1 + 2 in use");
342
343 fillPayload(s_payload, 200, 3);
344 checkError(fs.writeFileBlocking(gpu, kPort, "BIMEMTEST-RW", kTitle, icon, s_payload, 200), Error::OK,
345 "fs: overwrite the one-block file");
346 e = fs.readFileBlocking(gpu, kPort, "BIMEMTEST-RW", s_readback, 200, &len);
347 check(e == Error::OK && len == 200 && same(s_payload, s_readback, 200), "fs: read back the new payload");
348 e = fs.getFreeBlockCountBlocking(gpu, kPort, &freeBlocks);
349 check(e == Error::OK && freeBlocks == usable - 3, "fs: overwrite left the free count alone");
350
351 checkError(fs.writeFileBlocking(gpu, kPort, "BIMEMTEST-NAME-TOO-LONG", kTitle, icon, s_payload, 1),
352 Error::NameTooLong, "fs: 23-character name");
353 checkError(fs.writeFileBlocking(gpu, kPort, "BIMEMTEST-HUGE", kTitle, icon, s_payload, 15 * 8192),
354 Error::FileTooLarge, "fs: 16-block file");
355
356 checkError(fs.deleteFileBlocking(gpu, kPort, "BIMEMTEST-RW"), Error::OK, "fs: delete the one-block file");
357 e = fs.fileExistsBlocking(gpu, kPort, "BIMEMTEST-RW", &exists);
358 check(e == Error::OK && !exists, "fs: deleted file is gone");
359 checkError(fs.readFileBlocking(gpu, kPort, "BIMEMTEST-RW", s_readback, 200, &len), Error::FileNotFound,
360 "fs: read a deleted file");
361 checkError(fs.deleteFileBlocking(gpu, kPort, "BIMEMTEST-RW"), Error::FileNotFound, "fs: delete it again");
362 fillPayload(s_payload, kBig, 2);
363 __builtin_memset(s_readback, 0, kBig);
364 e = fs.readFileBlocking(gpu, kPort, "BIMEMTEST-BIG", s_readback, kBig, &len);
365 check(e == Error::OK && len == kBig && same(s_payload, s_readback, kBig), "fs: other file still intact");
366 checkError(fs.deleteFileBlocking(gpu, kPort, "BIMEMTEST-BIG"), Error::OK, "fs: delete the two-block file");
367 e = fs.getFreeBlockCountBlocking(gpu, kPort, &freeBlocks);
368 check(e == Error::OK && freeBlocks == usable, "fs: every usable block free after both deletes");
369
370 // Make sector 512 repeat sector 0, the way a 64 KiB card reads, so the
371 // filesystem's size probe is exercised on a 128 KiB card too. Formatting
372 // again has to clear it.
373 e = app.m_card.readSectorBlocking(kPort, 0, s_frame);
374 if (e == Error::OK) e = app.m_card.writeSectorBlocking(kPort, 512, s_frame);
375 if (e == Error::OK) e = fs.getFreeBlockCountBlocking(gpu, kPort, &freeBlocks);
376 check(e == Error::OK && freeBlocks == 7, "fs: sector 512 repeating sector 0 reads as 7 usable blocks");
377 unsigned aliasWritten = 0;
378 Error aliasRefused = Error::OK;
379 fillPayload(s_payload, 512, 0x200);
380 for (unsigned n = 1; n <= 8; n++) {
381 char name[21];
382 __builtin_memcpy(name, "BIMEMTEST-A00", 14);
383 name[12] = static_cast<char>('0' + n);
384 aliasRefused = fs.writeFileBlocking(gpu, kPort, name, kTitle, icon, s_payload, 512);
385 if (aliasRefused != Error::OK) break;
386 aliasWritten = n;
387 }
388 check(aliasWritten == 7 && aliasRefused == Error::OutOfSpace,
389 "fs: sector 512 repeating sector 0 takes 7 files, then out of space");
390 checkError(fs.formatBlocking(gpu, kPort), Error::OK, "fs: format again");
391 e = fs.getFreeBlockCountBlocking(gpu, kPort, &freeBlocks);
392 check(e == Error::OK && freeBlocks == usable, "fs: format clears the copy of sector 0 at sector 512");
393}
394
395bool readsBack(char names[][21], unsigned k, unsigned after) {
396 uint32_t len = 0;
397 fillPayload(s_payload, 512, 0x100 + k);
398 Error e = app.m_fs.readFileBlocking(app.gpu(), kPort, names[k - 1], s_readback, 512, &len);
399 if (e == Error::OK && len == 512 && same(s_payload, s_readback, 512)) return true;
400 ramsyscall_printf("fill: after file %d, file %d reads %s%s\n", after, k, MC::errorMessage(e),
401 e == Error::OK ? ", wrong data" : "");
402 return false;
403}
404
405// Writes one-block files until the filesystem refuses, checking the listing
406// and the new file after each write, and every file at the end.
407void testFill(unsigned capacity) {
408 auto &gpu = app.gpu();
409 auto &fs = app.m_fs;
410 FS::Icon icon;
411 buildIcon(icon, 1);
412 static char names[16][21];
413 static FS::FileEntry entries[16];
414
415 if (!checkError(fs.formatBlocking(gpu, kPort), Error::OK, "fill: format")) return;
416 unsigned written = 0;
417 bool intact = true;
418 Error refused = Error::OK;
419 for (unsigned n = 1; n <= 16 && intact; n++) {
420 char *name = names[n - 1];
421 __builtin_memcpy(name, "BIMEMTEST-F00", 14);
422 name[11] = static_cast<char>('0' + n / 10);
423 name[12] = static_cast<char>('0' + n % 10);
424 fillPayload(s_payload, 512, 0x100 + n);
425 Error e = fs.writeFileBlocking(gpu, kPort, name, kTitle, icon, s_payload, 512);
426 if (e != Error::OK) {
427 refused = e;
428 ramsyscall_printf("fill: file %d refused: %s\n", n, MC::errorMessage(e));
429 break;
430 }
431 written = n;
432 // Every file written so far must still be listed and readable.
433 uint32_t count = 0;
434 e = fs.listFilesBlocking(gpu, kPort, entries, 16, &count);
435 if (e != Error::OK || count != written) {
436 ramsyscall_printf("fill: after file %d the listing reads %s, %d files\n", n, MC::errorMessage(e), count);
437 intact = false;
438 break;
439 }
440 if (!readsBack(names, n, n)) intact = false;
441 }
442 // And all of them once more at the end.
443 for (unsigned k = 1; k <= written && intact; k++) {
444 if (!readsBack(names, k, written)) intact = false;
445 }
446 ramsyscall_printf("fill: %d one-block files written on a %d-block card\n", written, capacity);
447 check(intact, "fill: every file written stays listed and readable");
448 if (intact) {
449 bool expected = written == 15 && refused == Error::OutOfSpace;
450 if (capacity == 8) expected = written == 7 && refused == Error::OutOfSpace;
451 check(expected,
452 capacity == 8 ? "fill: half-size card, 7 files, then out of space" : "fill: 15 files, then out of space");
453 }
454}
455
456} // namespace
457
458void MemcardTest::prepare() {
464 gpu().initialize(config);
465 m_card.prepare();
466}
467
468void MemcardTest::createScene() { pushScene(&scene); }
469
470void TestScene::frame() {
471 if (m_done) return;
472 m_done = true;
473 ramsyscall_printf("psyqo memory card, port %d (slot %d)\n", MEMCARD_PORT, MEMCARD_PORT + 1);
474
475 if (check(app.m_card.probeBlocking(kPort) == Error::OK, "probe: a card answers") && cardIsOursToErase()) {
476 testRange();
477 unsigned capacity = testCapacity();
478 testRawFrames();
479 testFileSystem(capacity);
480 testFill(capacity);
481 checkError(app.m_fs.formatBlocking(app.gpu(), kPort), Error::OK, "cleanup: format");
482 } else {
483 s_failures++;
484 }
485
486 if (s_failures == 0) {
487 ramsyscall_printf("memcard port %d: all %d checks passed\n", MEMCARD_PORT, s_checks);
488 } else {
489 ramsyscall_printf("memcard port %d: %d of %d checks FAILED\n", MEMCARD_PORT, s_failures, s_checks);
490 }
491 int code = s_failures == 0 ? 0 : 1;
492 pcsx_exit(code);
493 // On hardware: the break the farm reads back as the verdict, exit code in
494 // $a0, as tests/support/runtime.c does.
495 register int a0 asm("$4") = code;
496 __asm__ volatile("break 4, 0\n" : : "r"(a0) : "memory");
497 while (1);
498}
499
500int main() { return app.run(); }
int written
Definition cdda.c:321
int ok
Definition cdlstop.c:75
ramsyscall_printf("T21 phase=%s t=%u v=%02x cause=%u size=%u stat=%02x\n", phase, t/1000, response[0], cause, size,(nopCause==3 &&nopSize >=1) ? stat[0] :0xff)
__builtin_memset(response, 0xff, 16)
uint32_t t
Definition cdltest.c:291
The application class.
Definition application.hh:49
virtual void createScene()
Create the root scene object.
Definition application.hh:86
virtual void prepare()
Prepare the objects for the application.
Definition application.hh:66
A Sony-compatible memory card filesystem.
Definition memory-card-filesystem.hh:77
A low level driver for the PlayStation memory cards.
Definition memory-card.hh:67
Error
The error codes returned by every memory card operation.
Definition memory-card.hh:75
The Scene class.
Definition scene.hh:43
virtual void frame()
Renders a frame.
Definition scene.hh:65
struct s_info info
Definition syscalls.h:535
uint8_t b
Definition gte-depthcue.c:41
int i
Definition gte-regio.c:299
const char * names[]
Definition icache.c:150
#define MEMCARD_PORT
Definition memcard.cpp:57
int main()
Definition memcard.cpp:500
void * result
Definition memcpy.c:52
__asm__(" .section .text.monitorSlotEntry, \"ax\", @progbits\n" " .align 2\n" " .global monitorSlotEntry\n" " .type monitorSlotEntry, @function\n" " .set push\n" " .set noreorder\n" " .set noat\n" "monitorSlotEntry:\n" " mfc0 $v0, $13\n" " nop\n" " andi $v0, $v0, 0x7c\n" " beqz $v0, 1f\n" " srl $v0, $v0, 2\n" " li $v1, " MON_STR(MON_SLOT_EXCMASK) "\n" " srlv $v1, $v1, $v0\n" " andi $v1, $v1, 1\n" " bnez $v1, 2f\n" " nop\n" " jr $ra\n" " nop\n" "1:\n" MON_SLOT_RX_TEST " jr $ra\n" " nop\n" "2:\n" " sw $a0, 0x10($k0)\n" " sw $a1, 0x14($k0)\n" " sw $a2, 0x18($k0)\n" " sw $a3, 0x1c($k0)\n" " mfc0 $a0, $12\n" " nop\n" " sw $a0, 0x8c($k0)\n" " mfc0 $a1, $13\n" " nop\n" " sw $a1, 0x90($k0)\n" " sw $k1, 0x6c($k0)\n" " sw $s0, 0x40($k0)\n" " sw $s1, 0x44($k0)\n" " sw $s2, 0x48($k0)\n" " sw $s3, 0x4c($k0)\n" " sw $s4, 0x50($k0)\n" " sw $s5, 0x54($k0)\n" " sw $s6, 0x58($k0)\n" " sw $s7, 0x5c($k0)\n" " sw $t0, 0x20($k0)\n" " sw $t1, 0x24($k0)\n" " sw $t2, 0x28($k0)\n" " sw $t3, 0x2c($k0)\n" " sw $t4, 0x30($k0)\n" " sw $t5, 0x34($k0)\n" " sw $t6, 0x38($k0)\n" " sw $t7, 0x3c($k0)\n" " sw $t8, 0x60($k0)\n" " sw $t9, 0x64($k0)\n" " sw $gp, 0x70($k0)\n" " sw $sp, 0x74($k0)\n" " sw $fp, 0x78($k0)\n" " mfhi $a0\n" " nop\n" " sw $a0, 0x84($k0)\n" " mflo $a0\n" " nop\n" " sw $a0, 0x88($k0)\n" " move $s0, $ra\n" " la $sp, monitorSlotStack + " MON_STR(MONITOR_SLOT_STACK_WORDS) " * 4 - 16\n" " jal monitorSlotDispatch\n" " nop\n" " lw $k0, 0x108($zero)\n" " move $ra, $s0\n" " lw $k0, 0($k0)\n" " nop\n" " addiu $k0, $k0, 8\n" " lw $a0, 0x84($k0)\n" " lw $a1, 0x88($k0)\n" " mthi $a0\n" " mtlo $a1\n" " lw $a0, 0x10($k0)\n" " lw $a1, 0x14($k0)\n" " lw $a2, 0x18($k0)\n" " lw $a3, 0x1c($k0)\n" " lw $t0, 0x20($k0)\n" " lw $t1, 0x24($k0)\n" " lw $t2, 0x28($k0)\n" " lw $t3, 0x2c($k0)\n" " lw $t4, 0x30($k0)\n" " lw $t5, 0x34($k0)\n" " lw $t6, 0x38($k0)\n" " lw $t7, 0x3c($k0)\n" " lw $t8, 0x60($k0)\n" " lw $t9, 0x64($k0)\n" " lw $s0, 0x40($k0)\n" " lw $sp, 0x74($k0)\n" " jr $ra\n" " nop\n" " .set pop\n" " .size monitorSlotEntry, . - monitorSlotEntry\n" " .previous\n")
check
Definition mkimage.py:54
uint32_t after
Definition readnosetloc.c:139
char * s
Definition string.c:48
char e[1]
Definition string.c:119
Definition configuration.hh:29
Configuration & set(Resolution resolution)
Definition configuration.hh:30
Definition xprintf.c:112
static const void size_t count
Definition syscalls.h:196
static const void * buf
Definition syscalls.h:114
int done
Definition xa.c:238