1 |
william |
31 |
/* PCSX2 - PS2 Emulator for PCs |
2 |
|
|
* Copyright (C) 2002-2010 PCSX2 Dev Team |
3 |
|
|
* |
4 |
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms |
5 |
|
|
* of the GNU Lesser General Public License as published by the Free Software Found- |
6 |
|
|
* ation, either version 3 of the License, or (at your option) any later version. |
7 |
|
|
* |
8 |
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; |
9 |
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR |
10 |
|
|
* PURPOSE. See the GNU General Public License for more details. |
11 |
|
|
* |
12 |
|
|
* You should have received a copy of the GNU General Public License along with PCSX2. |
13 |
|
|
* If not, see <http://www.gnu.org/licenses/>. |
14 |
|
|
*/ |
15 |
|
|
|
16 |
|
|
|
17 |
|
|
#include "PrecompiledHeader.h" |
18 |
|
|
#include "IopCommon.h" |
19 |
|
|
#include "R5900.h" // for g_GameStarted |
20 |
|
|
|
21 |
|
|
#include <ctype.h> |
22 |
|
|
#include <string.h> |
23 |
|
|
|
24 |
|
|
#ifndef O_BINARY |
25 |
|
|
#define O_BINARY 0 |
26 |
|
|
#endif |
27 |
|
|
|
28 |
|
|
namespace R3000A { |
29 |
|
|
|
30 |
|
|
#define v0 (psxRegs.GPR.n.v0) |
31 |
|
|
#define a0 (psxRegs.GPR.n.a0) |
32 |
|
|
#define a1 (psxRegs.GPR.n.a1) |
33 |
|
|
#define a2 (psxRegs.GPR.n.a2) |
34 |
|
|
#define a3 (psxRegs.GPR.n.a3) |
35 |
|
|
#define sp (psxRegs.GPR.n.sp) |
36 |
|
|
#define ra (psxRegs.GPR.n.ra) |
37 |
|
|
#define pc (psxRegs.pc) |
38 |
|
|
|
39 |
|
|
#define Ra0 (iopVirtMemR<char>(a0)) |
40 |
|
|
#define Ra1 (iopVirtMemR<char>(a1)) |
41 |
|
|
#define Ra2 (iopVirtMemR<char>(a2)) |
42 |
|
|
#define Ra3 (iopVirtMemR<char>(a3)) |
43 |
|
|
|
44 |
|
|
// TODO: sandbox option, other permissions |
45 |
|
|
class HostFile : public IOManFile |
46 |
|
|
{ |
47 |
|
|
public: |
48 |
|
|
int fd; |
49 |
|
|
|
50 |
|
|
HostFile(int hostfd) |
51 |
|
|
{ |
52 |
|
|
fd = hostfd; |
53 |
|
|
} |
54 |
|
|
|
55 |
|
|
static __forceinline int translate_error(int err) |
56 |
|
|
{ |
57 |
|
|
if (err >= 0) |
58 |
|
|
return err; |
59 |
|
|
|
60 |
|
|
switch(err) |
61 |
|
|
{ |
62 |
|
|
case -ENOENT: |
63 |
|
|
return -IOP_ENOENT; |
64 |
|
|
case -EACCES: |
65 |
|
|
return -IOP_EACCES; |
66 |
|
|
case -EISDIR: |
67 |
|
|
return -IOP_EISDIR; |
68 |
|
|
case -EIO: |
69 |
|
|
default: |
70 |
|
|
return -IOP_EIO; |
71 |
|
|
} |
72 |
|
|
} |
73 |
|
|
|
74 |
|
|
static int open(IOManFile **file, const char *name, s32 flags, u16 mode) |
75 |
|
|
{ |
76 |
|
|
const char *path = strchr(name, ':') + 1; |
77 |
|
|
|
78 |
|
|
if (flags != IOP_O_RDONLY) |
79 |
|
|
return -IOP_EROFS; |
80 |
|
|
|
81 |
|
|
int hostfd = ::open(path, O_BINARY | O_RDONLY); |
82 |
|
|
if (hostfd < 0) |
83 |
|
|
return translate_error(hostfd); |
84 |
|
|
|
85 |
|
|
*file = new HostFile(hostfd); |
86 |
|
|
if (!*file) |
87 |
|
|
return -IOP_ENOMEM; |
88 |
|
|
|
89 |
|
|
return 0; |
90 |
|
|
} |
91 |
|
|
|
92 |
|
|
virtual void close() |
93 |
|
|
{ |
94 |
|
|
::close(fd); |
95 |
|
|
delete this; |
96 |
|
|
} |
97 |
|
|
|
98 |
|
|
virtual int lseek(s32 offset, s32 whence) |
99 |
|
|
{ |
100 |
|
|
int err; |
101 |
|
|
|
102 |
|
|
switch (whence) |
103 |
|
|
{ |
104 |
|
|
case IOP_SEEK_SET: |
105 |
|
|
err = ::lseek(fd, offset, SEEK_SET); |
106 |
|
|
break; |
107 |
|
|
case IOP_SEEK_CUR: |
108 |
|
|
err = ::lseek(fd, offset, SEEK_CUR); |
109 |
|
|
break; |
110 |
|
|
case IOP_SEEK_END: |
111 |
|
|
err = ::lseek(fd, offset, SEEK_END); |
112 |
|
|
break; |
113 |
|
|
default: |
114 |
|
|
return -IOP_EIO; |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
return translate_error(err); |
118 |
|
|
} |
119 |
|
|
|
120 |
|
|
virtual int read(void *buf, u32 count) |
121 |
|
|
{ |
122 |
|
|
return translate_error(::read(fd, buf, count)); |
123 |
|
|
} |
124 |
|
|
}; |
125 |
|
|
|
126 |
|
|
namespace ioman { |
127 |
|
|
const int firstfd = 0x100; |
128 |
|
|
const int maxfds = 0x100; |
129 |
|
|
int openfds = 0; |
130 |
|
|
|
131 |
|
|
int freefdcount() |
132 |
|
|
{ |
133 |
|
|
return maxfds - openfds; |
134 |
|
|
} |
135 |
|
|
|
136 |
|
|
struct filedesc |
137 |
|
|
{ |
138 |
|
|
enum { |
139 |
|
|
FILE_FREE, |
140 |
|
|
FILE_FILE, |
141 |
|
|
FILE_DIR, |
142 |
|
|
} type; |
143 |
|
|
union { |
144 |
|
|
IOManFile *file; |
145 |
|
|
IOManDir *dir; |
146 |
|
|
}; |
147 |
|
|
|
148 |
|
|
operator bool() const { return type != FILE_FREE; } |
149 |
|
|
operator IOManFile*() const { return type == FILE_FILE ? file : NULL; } |
150 |
|
|
operator IOManDir*() const { return type == FILE_DIR ? dir : NULL; } |
151 |
|
|
void operator=(IOManFile *f) { type = FILE_FILE; file = f; openfds++; } |
152 |
|
|
void operator=(IOManDir *d) { type = FILE_DIR; dir = d; openfds++; } |
153 |
|
|
|
154 |
|
|
void close() |
155 |
|
|
{ |
156 |
|
|
if (type == FILE_FREE) |
157 |
|
|
return; |
158 |
|
|
|
159 |
|
|
switch (type) |
160 |
|
|
{ |
161 |
|
|
case FILE_FILE: |
162 |
|
|
file->close(); |
163 |
|
|
file = NULL; |
164 |
|
|
break; |
165 |
|
|
case FILE_DIR: |
166 |
|
|
dir->close(); |
167 |
|
|
dir = NULL; |
168 |
|
|
break; |
169 |
|
|
} |
170 |
|
|
|
171 |
|
|
type = FILE_FREE; |
172 |
|
|
openfds--; |
173 |
|
|
} |
174 |
|
|
}; |
175 |
|
|
|
176 |
|
|
filedesc fds[maxfds]; |
177 |
|
|
|
178 |
|
|
template<typename T> |
179 |
|
|
T* getfd(int fd) |
180 |
|
|
{ |
181 |
|
|
fd -= firstfd; |
182 |
|
|
|
183 |
|
|
if (fd < 0 || fd >= maxfds) |
184 |
|
|
return NULL; |
185 |
|
|
|
186 |
|
|
return fds[fd]; |
187 |
|
|
} |
188 |
|
|
|
189 |
|
|
template <typename T> |
190 |
|
|
int allocfd(T *obj) |
191 |
|
|
{ |
192 |
|
|
for (int i = 0; i < maxfds; i++) |
193 |
|
|
{ |
194 |
|
|
if (!fds[i]) |
195 |
|
|
{ |
196 |
|
|
fds[i] = obj; |
197 |
|
|
return firstfd + i; |
198 |
|
|
} |
199 |
|
|
} |
200 |
|
|
|
201 |
|
|
obj->close(); |
202 |
|
|
return -IOP_EMFILE; |
203 |
|
|
} |
204 |
|
|
|
205 |
|
|
void freefd(int fd) |
206 |
|
|
{ |
207 |
|
|
fd -= firstfd; |
208 |
|
|
|
209 |
|
|
if (fd < 0 || fd >= maxfds) |
210 |
|
|
return; |
211 |
|
|
|
212 |
|
|
fds[fd].close(); |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
void reset() |
216 |
|
|
{ |
217 |
|
|
for (int i = 0; i < maxfds; i++) |
218 |
|
|
fds[i].close(); |
219 |
|
|
} |
220 |
|
|
|
221 |
|
|
int open_HLE() |
222 |
|
|
{ |
223 |
|
|
IOManFile *file = NULL; |
224 |
|
|
const char *name = Ra0; |
225 |
|
|
s32 flags = a1; |
226 |
|
|
u16 mode = a2; |
227 |
|
|
|
228 |
|
|
if ((!g_GameStarted || EmuConfig.HostFs) |
229 |
|
|
&& !strncmp(name, "host", 4) && name[4 + strspn(name + 4, "0123456789")] == ':') |
230 |
|
|
{ |
231 |
|
|
if (!freefdcount()) |
232 |
|
|
{ |
233 |
|
|
v0 = -IOP_EMFILE; |
234 |
|
|
pc = ra; |
235 |
|
|
return 1; |
236 |
|
|
} |
237 |
|
|
|
238 |
|
|
int err = HostFile::open(&file, name, flags, mode); |
239 |
|
|
|
240 |
|
|
if (err != 0 || !file) |
241 |
|
|
{ |
242 |
|
|
if (err == 0) // ??? |
243 |
|
|
err = -IOP_EIO; |
244 |
|
|
if (file) // ?????? |
245 |
|
|
file->close(); |
246 |
|
|
v0 = err; |
247 |
|
|
} |
248 |
|
|
else |
249 |
|
|
{ |
250 |
|
|
v0 = allocfd(file); |
251 |
|
|
if (v0 < 0) |
252 |
|
|
file->close(); |
253 |
|
|
} |
254 |
|
|
|
255 |
|
|
pc = ra; |
256 |
|
|
return 1; |
257 |
|
|
} |
258 |
|
|
|
259 |
|
|
return 0; |
260 |
|
|
} |
261 |
|
|
|
262 |
|
|
int close_HLE() |
263 |
|
|
{ |
264 |
|
|
s32 fd = a0; |
265 |
|
|
|
266 |
|
|
if (getfd<IOManFile>(fd)) |
267 |
|
|
{ |
268 |
|
|
freefd(fd); |
269 |
|
|
v0 = 0; |
270 |
|
|
pc = ra; |
271 |
|
|
return 1; |
272 |
|
|
} |
273 |
|
|
|
274 |
|
|
return 0; |
275 |
|
|
} |
276 |
|
|
|
277 |
|
|
int lseek_HLE() |
278 |
|
|
{ |
279 |
|
|
s32 fd = a0; |
280 |
|
|
s32 offset = a1; |
281 |
|
|
s32 whence = a2; |
282 |
|
|
|
283 |
|
|
if (IOManFile *file = getfd<IOManFile>(fd)) |
284 |
|
|
{ |
285 |
|
|
v0 = file->lseek(offset, whence); |
286 |
|
|
pc = ra; |
287 |
|
|
return 1; |
288 |
|
|
} |
289 |
|
|
|
290 |
|
|
return 0; |
291 |
|
|
} |
292 |
|
|
|
293 |
|
|
int read_HLE() |
294 |
|
|
{ |
295 |
|
|
s32 fd = a0; |
296 |
|
|
u32 buf = a1; |
297 |
|
|
u32 count = a2; |
298 |
|
|
|
299 |
|
|
if (IOManFile *file = getfd<IOManFile>(fd)) |
300 |
|
|
{ |
301 |
|
|
if (!iopVirtMemR<void>(buf)) |
302 |
|
|
return 0; |
303 |
|
|
|
304 |
|
|
v0 = file->read(iopVirtMemW<void>(buf), count); |
305 |
|
|
pc = ra; |
306 |
|
|
return 1; |
307 |
|
|
} |
308 |
|
|
|
309 |
|
|
return 0; |
310 |
|
|
} |
311 |
|
|
|
312 |
|
|
int write_HLE() |
313 |
|
|
{ |
314 |
|
|
int fd = a0; |
315 |
|
|
|
316 |
|
|
#ifdef PCSX2_DEVBUILD |
317 |
|
|
if (fd == 1) // stdout |
318 |
|
|
{ |
319 |
|
|
Console.Write(ConColor_IOP, L"%s", ShiftJIS_ConvertString(Ra1, a2).c_str()); |
320 |
|
|
pc = ra; |
321 |
|
|
v0 = a2; |
322 |
|
|
return 1; |
323 |
|
|
} |
324 |
|
|
#endif |
325 |
|
|
|
326 |
|
|
return 0; |
327 |
|
|
} |
328 |
|
|
} |
329 |
|
|
|
330 |
|
|
namespace sysmem { |
331 |
|
|
int Kprintf_HLE() |
332 |
|
|
{ |
333 |
|
|
char tmp[1024], tmp2[1024]; |
334 |
|
|
char *ptmp = tmp; |
335 |
|
|
int n=1, i=0, j = 0; |
336 |
|
|
|
337 |
|
|
iopMemWrite32(sp, a0); |
338 |
|
|
iopMemWrite32(sp + 4, a1); |
339 |
|
|
iopMemWrite32(sp + 8, a2); |
340 |
|
|
iopMemWrite32(sp + 12, a3); |
341 |
|
|
|
342 |
|
|
while (Ra0[i]) |
343 |
|
|
{ |
344 |
|
|
switch (Ra0[i]) |
345 |
|
|
{ |
346 |
|
|
case '%': |
347 |
|
|
j = 0; |
348 |
|
|
tmp2[j++] = '%'; |
349 |
|
|
_start: |
350 |
|
|
switch (Ra0[++i]) |
351 |
|
|
{ |
352 |
|
|
case '.': |
353 |
|
|
case 'l': |
354 |
|
|
tmp2[j++] = Ra0[i]; |
355 |
|
|
goto _start; |
356 |
|
|
default: |
357 |
|
|
if (Ra0[i] >= '0' && Ra0[i] <= '9') |
358 |
|
|
{ |
359 |
|
|
tmp2[j++] = Ra0[i]; |
360 |
|
|
goto _start; |
361 |
|
|
} |
362 |
|
|
break; |
363 |
|
|
} |
364 |
|
|
|
365 |
|
|
tmp2[j++] = Ra0[i]; |
366 |
|
|
tmp2[j] = 0; |
367 |
|
|
|
368 |
|
|
switch (Ra0[i]) |
369 |
|
|
{ |
370 |
|
|
case 'f': case 'F': |
371 |
|
|
ptmp+= sprintf(ptmp, tmp2, (float)iopMemRead32(sp + n * 4)); |
372 |
|
|
n++; |
373 |
|
|
break; |
374 |
|
|
|
375 |
|
|
case 'a': case 'A': |
376 |
|
|
case 'e': case 'E': |
377 |
|
|
case 'g': case 'G': |
378 |
|
|
ptmp+= sprintf(ptmp, tmp2, (double)iopMemRead32(sp + n * 4)); |
379 |
|
|
n++; |
380 |
|
|
break; |
381 |
|
|
|
382 |
|
|
case 'p': |
383 |
|
|
case 'i': |
384 |
|
|
case 'd': case 'D': |
385 |
|
|
case 'o': case 'O': |
386 |
|
|
case 'x': case 'X': |
387 |
|
|
ptmp+= sprintf(ptmp, tmp2, (u32)iopMemRead32(sp + n * 4)); |
388 |
|
|
n++; |
389 |
|
|
break; |
390 |
|
|
|
391 |
|
|
case 'c': |
392 |
|
|
ptmp+= sprintf(ptmp, tmp2, (u8)iopMemRead32(sp + n * 4)); |
393 |
|
|
n++; |
394 |
|
|
break; |
395 |
|
|
|
396 |
|
|
case 's': |
397 |
|
|
ptmp+= sprintf(ptmp, tmp2, iopVirtMemR<char>(iopMemRead32(sp + n * 4))); |
398 |
|
|
n++; |
399 |
|
|
break; |
400 |
|
|
|
401 |
|
|
case '%': |
402 |
|
|
*ptmp++ = Ra0[i]; |
403 |
|
|
break; |
404 |
|
|
|
405 |
|
|
default: |
406 |
|
|
break; |
407 |
|
|
} |
408 |
|
|
i++; |
409 |
|
|
break; |
410 |
|
|
|
411 |
|
|
default: |
412 |
|
|
*ptmp++ = Ra0[i++]; |
413 |
|
|
break; |
414 |
|
|
} |
415 |
|
|
} |
416 |
|
|
*ptmp = 0; |
417 |
|
|
|
418 |
|
|
// Use "%s" even though it seems indirect: this avoids chaos if/when the IOP decides |
419 |
|
|
// to feed us strings that contain percentages or other printf formatting control chars. |
420 |
|
|
Console.Write( ConColor_IOP, L"%s", ShiftJIS_ConvertString(tmp).c_str(), 1023 ); |
421 |
|
|
|
422 |
|
|
pc = ra; |
423 |
|
|
return 1; |
424 |
|
|
} |
425 |
|
|
} |
426 |
|
|
|
427 |
|
|
namespace loadcore { |
428 |
|
|
void RegisterLibraryEntries_DEBUG() |
429 |
|
|
{ |
430 |
|
|
DbgCon.WriteLn(Color_Gray, "RegisterLibraryEntries: %8.8s", iopVirtMemR<char>(a0 + 12)); |
431 |
|
|
} |
432 |
|
|
} |
433 |
|
|
|
434 |
|
|
namespace intrman { |
435 |
|
|
static const char* intrname[] = { |
436 |
|
|
"INT_VBLANK", "INT_GM", "INT_CDROM", "INT_DMA", //00 |
437 |
|
|
"INT_RTC0", "INT_RTC1", "INT_RTC2", "INT_SIO0", //04 |
438 |
|
|
"INT_SIO1", "INT_SPU", "INT_PIO", "INT_EVBLANK", //08 |
439 |
|
|
"INT_DVD", "INT_PCMCIA", "INT_RTC3", "INT_RTC4", //0C |
440 |
|
|
"INT_RTC5", "INT_SIO2", "INT_HTR0", "INT_HTR1", //10 |
441 |
|
|
"INT_HTR2", "INT_HTR3", "INT_USB", "INT_EXTR", //14 |
442 |
|
|
"INT_FWRE", "INT_FDMA", "INT_1A", "INT_1B", //18 |
443 |
|
|
"INT_1C", "INT_1D", "INT_1E", "INT_1F", //1C |
444 |
|
|
"INT_dmaMDECi", "INT_dmaMDECo", "INT_dmaGPU", "INT_dmaCD", //20 |
445 |
|
|
"INT_dmaSPU", "INT_dmaPIO", "INT_dmaOTC", "INT_dmaBERR", //24 |
446 |
|
|
"INT_dmaSPU2", "INT_dma8", "INT_dmaSIF0", "INT_dmaSIF1", //28 |
447 |
|
|
"INT_dmaSIO2i", "INT_dmaSIO2o", "INT_2E", "INT_2F", //2C |
448 |
|
|
"INT_30", "INT_31", "INT_32", "INT_33", //30 |
449 |
|
|
"INT_34", "INT_35", "INT_36", "INT_37", //34 |
450 |
|
|
"INT_38", "INT_39", "INT_3A", "INT_3B", //38 |
451 |
|
|
"INT_3C", "INT_3D", "INT_3E", "INT_3F", //3C |
452 |
|
|
"INT_MAX" //40 |
453 |
|
|
}; |
454 |
|
|
|
455 |
|
|
void RegisterIntrHandler_DEBUG() |
456 |
|
|
{ |
457 |
|
|
DbgCon.WriteLn(Color_Gray, "RegisterIntrHandler: intr %s, handler %x", intrname[a0], a2); |
458 |
|
|
} |
459 |
|
|
} |
460 |
|
|
|
461 |
|
|
namespace sifcmd { |
462 |
|
|
void sceSifRegisterRpc_DEBUG() |
463 |
|
|
{ |
464 |
|
|
DbgCon.WriteLn( Color_Gray, "sifcmd sceSifRegisterRpc: rpc_id %x", a1); |
465 |
|
|
} |
466 |
|
|
} |
467 |
|
|
|
468 |
|
|
const char* irxImportLibname(u32 entrypc) |
469 |
|
|
{ |
470 |
|
|
u32 i; |
471 |
|
|
|
472 |
|
|
i = entrypc; |
473 |
|
|
while (iopMemRead32(i -= 4) != 0x41e00000) // documented magic number |
474 |
|
|
; |
475 |
|
|
|
476 |
|
|
return iopVirtMemR<char>(i + 12); |
477 |
|
|
} |
478 |
|
|
|
479 |
|
|
const char* irxImportFuncname(const char libname[8], u16 index) |
480 |
|
|
{ |
481 |
|
|
#include "IopModuleNames.cpp" |
482 |
|
|
|
483 |
|
|
switch (index) { |
484 |
|
|
case 0: return "start"; |
485 |
|
|
// case 1: reinit? |
486 |
|
|
case 2: return "shutdown"; |
487 |
|
|
// case 3: ??? |
488 |
|
|
} |
489 |
|
|
|
490 |
|
|
return 0; |
491 |
|
|
} |
492 |
|
|
|
493 |
|
|
#define MODULE(n) if (!strncmp(libname, #n, 8)) { using namespace n; switch (index) { |
494 |
|
|
#define END_MODULE }} |
495 |
|
|
#define EXPORT_D(i, n) case (i): return n ## _DEBUG; |
496 |
|
|
#define EXPORT_H(i, n) case (i): return n ## _HLE; |
497 |
|
|
|
498 |
|
|
irxHLE irxImportHLE(const char libname[8], u16 index) |
499 |
|
|
{ |
500 |
|
|
#ifdef PCSX2_DEVBUILD |
501 |
|
|
// debugging output |
502 |
|
|
MODULE(sysmem) |
503 |
|
|
EXPORT_H( 14, Kprintf) |
504 |
|
|
END_MODULE |
505 |
|
|
#endif |
506 |
|
|
MODULE(ioman) |
507 |
|
|
EXPORT_H( 4, open) |
508 |
|
|
EXPORT_H( 5, close) |
509 |
|
|
EXPORT_H( 6, read) |
510 |
|
|
EXPORT_H( 7, write) |
511 |
|
|
EXPORT_H( 8, lseek) |
512 |
|
|
END_MODULE |
513 |
|
|
|
514 |
|
|
return 0; |
515 |
|
|
} |
516 |
|
|
|
517 |
|
|
irxDEBUG irxImportDebug(const char libname[8], u16 index) |
518 |
|
|
{ |
519 |
|
|
MODULE(loadcore) |
520 |
|
|
EXPORT_D( 6, RegisterLibraryEntries) |
521 |
|
|
END_MODULE |
522 |
|
|
MODULE(intrman) |
523 |
|
|
EXPORT_D( 4, RegisterIntrHandler) |
524 |
|
|
END_MODULE |
525 |
|
|
MODULE(sifcmd) |
526 |
|
|
EXPORT_D( 17, sceSifRegisterRpc) |
527 |
|
|
END_MODULE |
528 |
|
|
|
529 |
|
|
return 0; |
530 |
|
|
} |
531 |
|
|
|
532 |
|
|
#undef MODULE |
533 |
|
|
#undef END_MODULE |
534 |
|
|
#undef EXPORT_D |
535 |
|
|
#undef EXPORT_H |
536 |
|
|
|
537 |
|
|
void __fastcall irxImportLog(const char libname[8], u16 index, const char *funcname) |
538 |
|
|
{ |
539 |
|
|
PSXBIOS_LOG("%8.8s.%03d: %s (%x, %x, %x, %x)", |
540 |
|
|
libname, index, funcname ? funcname : "unknown", |
541 |
|
|
a0, a1, a2, a3); |
542 |
|
|
} |
543 |
|
|
|
544 |
|
|
int __fastcall irxImportExec(const char libname[8], u16 index) |
545 |
|
|
{ |
546 |
|
|
const char *funcname = irxImportFuncname(libname, index); |
547 |
|
|
irxHLE hle = irxImportHLE(libname, index); |
548 |
|
|
irxDEBUG debug = irxImportDebug(libname, index); |
549 |
|
|
|
550 |
|
|
irxImportLog(libname, index, funcname); |
551 |
|
|
|
552 |
|
|
if (debug) |
553 |
|
|
debug(); |
554 |
|
|
|
555 |
|
|
if (hle) |
556 |
|
|
return hle(); |
557 |
|
|
else |
558 |
|
|
return 0; |
559 |
|
|
} |
560 |
|
|
|
561 |
|
|
} // end namespace R3000A |