Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-rsp-hle/src/main.c
2 views
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
* Mupen64plus-rsp-hle - main.c *
3
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4
* Copyright (C) 2012 Bobby Smiles *
5
* Copyright (C) 2009 Richard Goedeken *
6
* Copyright (C) 2002 Hacktarux *
7
* *
8
* This program is free software; you can redistribute it and/or modify *
9
* it under the terms of the GNU General Public License as published by *
10
* the Free Software Foundation; either version 2 of the License, or *
11
* (at your option) any later version. *
12
* *
13
* This program is distributed in the hope that it will be useful, *
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16
* GNU General Public License for more details. *
17
* *
18
* You should have received a copy of the GNU General Public License *
19
* along with this program; if not, write to the *
20
* Free Software Foundation, Inc., *
21
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
23
24
#include <stdarg.h>
25
#include <string.h>
26
#include <stdio.h>
27
28
#define M64P_PLUGIN_PROTOTYPES 1
29
#include "m64p_types.h"
30
#include "m64p_common.h"
31
#include "m64p_plugin.h"
32
#include "hle.h"
33
#include "alist.h"
34
#include "cicx105.h"
35
#include "jpeg.h"
36
37
#define min(a,b) (((a) < (b)) ? (a) : (b))
38
39
/* some rsp status flags */
40
#define RSP_STATUS_HALT 0x1
41
#define RSP_STATUS_BROKE 0x2
42
#define RSP_STATUS_INTR_ON_BREAK 0x40
43
#define RSP_STATUS_TASKDONE 0x200
44
45
/* some rdp status flags */
46
#define DP_STATUS_FREEZE 0x2
47
48
/* some mips interface interrupt flags */
49
#define MI_INTR_SP 0x1
50
51
52
/* helper functions prototypes */
53
static unsigned int sum_bytes(const unsigned char *bytes, unsigned int size);
54
static void dump_binary(const char * const filename, const unsigned char * const bytes,
55
unsigned int size);
56
static void dump_task(const char * const filename, const OSTask_t * const task);
57
58
static void handle_unknown_task(unsigned int sum);
59
static void handle_unknown_non_task(unsigned int sum);
60
61
/* global variables */
62
RSP_INFO rsp;
63
64
/* local variables */
65
static const int FORWARD_AUDIO = 0, FORWARD_GFX = 1;
66
static void (*l_DebugCallback)(void *, int, const char *) = NULL;
67
static void *l_DebugCallContext = NULL;
68
static int l_PluginInit = 0;
69
70
/* local functions */
71
72
73
/**
74
* Try to figure if the RSP was launched using osSpTask* functions
75
* and not run directly (in which case DMEM[0xfc0-0xfff] is meaningless).
76
*
77
* Previously, the ucode_size field was used to determine this,
78
* but it is not robust enough (hi Pokemon Stadium !) because games could write anything
79
* in this field : most ucode_boot discard the value and just use 0xf7f anyway.
80
*
81
* Using ucode_boot_size should be more robust in this regard.
82
**/
83
static int is_task()
84
{
85
return (get_task()->ucode_boot_size <= 0x1000);
86
}
87
88
static void rsp_break(unsigned int setbits)
89
{
90
*rsp.SP_STATUS_REG |= setbits | RSP_STATUS_BROKE | RSP_STATUS_HALT;
91
92
if ((*rsp.SP_STATUS_REG & RSP_STATUS_INTR_ON_BREAK))
93
{
94
*rsp.MI_INTR_REG |= MI_INTR_SP;
95
rsp.CheckInterrupts();
96
}
97
}
98
99
static void forward_gfx_task()
100
{
101
if (rsp.ProcessDlistList != NULL)
102
{
103
rsp.ProcessDlistList();
104
*rsp.DPC_STATUS_REG &= ~DP_STATUS_FREEZE;
105
}
106
}
107
108
static void forward_audio_task()
109
{
110
if (rsp.ProcessAlistList != NULL)
111
{
112
rsp.ProcessAlistList();
113
}
114
}
115
116
static void show_cfb()
117
{
118
if (rsp.ShowCFB != NULL)
119
{
120
rsp.ShowCFB();
121
}
122
}
123
124
static int try_fast_audio_dispatching()
125
{
126
/* identify audio ucode by using the content of ucode_data */
127
const OSTask_t * const task = get_task();
128
const unsigned char * const udata_ptr = rsp.RDRAM + task->ucode_data;
129
130
if (*(unsigned int*)(udata_ptr + 0) == 0x00000001)
131
{
132
if (*(unsigned int*)(udata_ptr + 0x30) == 0xf0000f00)
133
{
134
/**
135
* Many games including:
136
* Super Mario 64, Diddy Kong Racing, BlastCorp, GoldenEye, ... (most common)
137
**/
138
alist_process_ABI1(); return 1;
139
}
140
else
141
{
142
/**
143
* Mario Kart / Wave Race,
144
* LylatWars,
145
* FZeroX,
146
* Yoshi Story,
147
* 1080 Snowboarding,
148
* Zelda Ocarina of Time,
149
* Zelda Majoras Mask / Pokemon Stadium 2,
150
* Animal Crossing
151
*
152
* FIXME: in fact, all these games do not share the same ABI.
153
* That's the reason of the workaround in ucode2.cpp with isZeldaABI and isMKABI
154
**/
155
alist_process_ABI2(); return 1;
156
}
157
}
158
else
159
{
160
if (*(unsigned int*)(udata_ptr + 0x10) == 0x00000001)
161
{
162
/**
163
* Musyx ucode found in following games:
164
* RogueSquadron, ResidentEvil2, SnowCrossPolaris, TheWorldIsNotEnough,
165
* RugratsInParis, NBAShowTime, HydroThunder, Tarzan,
166
* GauntletLegend, Rush2049, IndianaJones, BattleForNaboo
167
* TODO: implement ucode
168
**/
169
DebugMessage(M64MSG_WARNING, "MusyX ucode not implemented.");
170
/* return 1; */
171
}
172
else
173
{
174
/**
175
* Many games including:
176
* Pokemon Stadium, Banjo Kazooie, Donkey Kong, Banjo Tooie, Jet Force Gemini,
177
* Mickey SpeedWay USA, Perfect Dark, Conker Bad Fur Day ...
178
**/
179
alist_process_ABI3(); return 1;
180
}
181
}
182
183
return 0;
184
}
185
186
static int try_fast_task_dispatching()
187
{
188
/* identify task ucode by its type */
189
const OSTask_t * const task = get_task();
190
191
switch (task->type)
192
{
193
case 1: if (FORWARD_GFX) { forward_gfx_task(); return 1; } break;
194
195
case 2:
196
if (FORWARD_AUDIO) { forward_audio_task(); return 1; }
197
else if (try_fast_audio_dispatching()) { return 1; }
198
break;
199
200
case 7: show_cfb(); return 1;
201
}
202
203
return 0;
204
}
205
206
static void normal_task_dispatching()
207
{
208
const OSTask_t * const task = get_task();
209
const unsigned int sum =
210
sum_bytes(rsp.RDRAM + task->ucode, min(task->ucode_size, 0xf80) >> 1);
211
212
switch (sum)
213
{
214
/* StoreVe12: found in Zelda Ocarina of Time [misleading task->type == 4] */
215
case 0x278: /* Nothing to emulate */ return;
216
217
/* GFX: Twintris [misleading task->type == 0] */
218
case 0x212ee:
219
if (FORWARD_GFX) { forward_gfx_task(); return; }
220
break;
221
222
/* JPEG: found in Pokemon Stadium J */
223
case 0x2c85a: jpeg_decode_PS0(); return;
224
225
/* JPEG: found in Zelda Ocarina of Time, Pokemon Stadium 1, Pokemon Stadium 2 */
226
case 0x2caa6: jpeg_decode_PS(); return;
227
228
/* JPEG: found in Ogre Battle, Bottom of the 9th */
229
case 0x130de: jpeg_decode_OB(); return;
230
}
231
232
handle_unknown_task(sum);
233
}
234
235
static void non_task_dispatching()
236
{
237
const unsigned int sum = sum_bytes(rsp.IMEM, 0x1000 >> 1);
238
239
switch(sum)
240
{
241
/* CIC x105 ucode (used during boot of CIC x105 games) */
242
case 0x9e2: /* CIC 6105 */
243
case 0x9f2: /* CIC 7105 */
244
cicx105_ucode(); return;
245
}
246
247
handle_unknown_non_task(sum);
248
}
249
250
static void handle_unknown_task(unsigned int sum)
251
{
252
char filename[256];
253
const OSTask_t * const task = get_task();
254
255
DebugMessage(M64MSG_WARNING, "unknown OSTask: sum %x PC:%x", sum, *rsp.SP_PC_REG);
256
257
sprintf(&filename[0], "task_%x.log", sum);
258
dump_task(filename, task);
259
260
// dump ucode_boot
261
sprintf(&filename[0], "ucode_boot_%x.bin", sum);
262
dump_binary(filename, rsp.RDRAM + (task->ucode_boot & 0x7fffff), task->ucode_boot_size);
263
264
// dump ucode
265
if (task->ucode != 0)
266
{
267
sprintf(&filename[0], "ucode_%x.bin", sum);
268
dump_binary(filename, rsp.RDRAM + (task->ucode & 0x7fffff), 0xf80);
269
}
270
271
// dump ucode_data
272
if (task->ucode_data != 0)
273
{
274
sprintf(&filename[0], "ucode_data_%x.bin", sum);
275
dump_binary(filename, rsp.RDRAM + (task->ucode_data & 0x7fffff), task->ucode_data_size);
276
}
277
278
// dump data
279
if (task->data_ptr != 0)
280
{
281
sprintf(&filename[0], "data_%x.bin", sum);
282
dump_binary(filename, rsp.RDRAM + (task->data_ptr & 0x7fffff), task->data_size);
283
}
284
}
285
286
static void handle_unknown_non_task(unsigned int sum)
287
{
288
char filename[256];
289
290
DebugMessage(M64MSG_WARNING, "unknown RSP code: sum: %x PC:%x", sum, *rsp.SP_PC_REG);
291
292
// dump IMEM & DMEM for further analysis
293
sprintf(&filename[0], "imem_%x.bin", sum);
294
dump_binary(filename, rsp.IMEM, 0x1000);
295
296
sprintf(&filename[0], "dmem_%x.bin", sum);
297
dump_binary(filename, rsp.DMEM, 0x1000);
298
}
299
300
301
/* Global functions */
302
void DebugMessage(int level, const char *message, ...)
303
{
304
char msgbuf[1024];
305
va_list args;
306
307
if (l_DebugCallback == NULL)
308
return;
309
310
va_start(args, message);
311
vsprintf(msgbuf, message, args);
312
313
(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
314
315
va_end(args);
316
}
317
318
/* DLL-exported functions */
319
EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
320
void (*DebugCallback)(void *, int, const char *))
321
{
322
if (l_PluginInit)
323
return M64ERR_ALREADY_INIT;
324
325
/* first thing is to set the callback function for debug info */
326
l_DebugCallback = DebugCallback;
327
l_DebugCallContext = Context;
328
329
/* this plugin doesn't use any Core library functions (ex for Configuration), so no need to keep the CoreLibHandle */
330
331
l_PluginInit = 1;
332
return M64ERR_SUCCESS;
333
}
334
335
EXPORT m64p_error CALL PluginShutdown(void)
336
{
337
if (!l_PluginInit)
338
return M64ERR_NOT_INIT;
339
340
/* reset some local variable */
341
l_DebugCallback = NULL;
342
l_DebugCallContext = NULL;
343
344
l_PluginInit = 0;
345
return M64ERR_SUCCESS;
346
}
347
348
EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
349
{
350
/* set version info */
351
if (PluginType != NULL)
352
*PluginType = M64PLUGIN_RSP;
353
354
if (PluginVersion != NULL)
355
*PluginVersion = RSP_HLE_VERSION;
356
357
if (APIVersion != NULL)
358
*APIVersion = RSP_PLUGIN_API_VERSION;
359
360
if (PluginNamePtr != NULL)
361
*PluginNamePtr = "Hacktarux/Azimer High-Level Emulation RSP Plugin";
362
363
if (Capabilities != NULL)
364
{
365
*Capabilities = 0;
366
}
367
368
return M64ERR_SUCCESS;
369
}
370
371
EXPORT unsigned int CALL DoRspCycles(unsigned int Cycles)
372
{
373
if (is_task())
374
{
375
if (!try_fast_task_dispatching()) { normal_task_dispatching(); }
376
rsp_break(RSP_STATUS_TASKDONE);
377
}
378
else
379
{
380
non_task_dispatching();
381
rsp_break(0);
382
}
383
384
return Cycles;
385
}
386
387
EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int *CycleCount)
388
{
389
rsp = Rsp_Info;
390
}
391
392
EXPORT void CALL RomClosed(void)
393
{
394
memset(rsp.DMEM, 0, 0x1000);
395
memset(rsp.IMEM, 0, 0x1000);
396
397
init_ucode2();
398
}
399
400
401
/* local helper functions */
402
static unsigned int sum_bytes(const unsigned char *bytes, unsigned int size)
403
{
404
unsigned int sum = 0;
405
const unsigned char * const bytes_end = bytes + size;
406
407
while (bytes != bytes_end)
408
sum += *bytes++;
409
410
return sum;
411
}
412
413
414
static void dump_binary(const char * const filename, const unsigned char * const bytes,
415
unsigned int size)
416
{
417
FILE *f;
418
419
// if file already exists, do nothing
420
f = fopen(filename, "r");
421
if (f == NULL)
422
{
423
// else we write bytes to the file
424
f= fopen(filename, "wb");
425
if (f != NULL) {
426
if (fwrite(bytes, 1, size, f) != size)
427
{
428
DebugMessage(M64MSG_ERROR, "Writing error on %s", filename);
429
}
430
fclose(f);
431
}
432
else
433
{
434
DebugMessage(M64MSG_ERROR, "Couldn't open %s for writing !", filename);
435
}
436
}
437
else
438
{
439
fclose(f);
440
}
441
}
442
443
static void dump_task(const char * const filename, const OSTask_t * const task)
444
{
445
FILE *f;
446
447
f = fopen(filename, "r");
448
if (f == NULL)
449
{
450
f = fopen(filename, "w");
451
fprintf(f,
452
"type = %d\n"
453
"flags = %d\n"
454
"ucode_boot = %#08x size = %#x\n"
455
"ucode = %#08x size = %#x\n"
456
"ucode_data = %#08x size = %#x\n"
457
"dram_stack = %#08x size = %#x\n"
458
"output_buff = %#08x *size = %#x\n"
459
"data = %#08x size = %#x\n"
460
"yield_data = %#08x size = %#x\n",
461
task->type, task->flags,
462
task->ucode_boot, task->ucode_boot_size,
463
task->ucode, task->ucode_size,
464
task->ucode_data, task->ucode_data_size,
465
task->dram_stack, task->dram_stack_size,
466
task->output_buff, task->output_buff_size,
467
task->data_ptr, task->data_size,
468
task->yield_data_ptr, task->yield_data_size);
469
fclose(f);
470
}
471
else
472
{
473
fclose(f);
474
}
475
}
476
477
478