mirror of
https://github.com/mupen64plus-ae/mupen64plus-rsp-cxd4.git
synced 2024-11-23 13:40:01 +00:00
433 lines
20 KiB
C
433 lines
20 KiB
C
#ifndef _RSP_H_
|
|
#define _RSP_H_
|
|
|
|
#include "Rsp_#1.1.h"
|
|
RSP_INFO RSP;
|
|
|
|
#ifdef _MSC_VER
|
|
#define INLINE __inline
|
|
INLINE int MessageBoxA(
|
|
HWND hWnd, const char *lpText, const char *lpCaption, unsigned int uType)
|
|
{
|
|
uType = 0x00000000;
|
|
if (*(lpText + 0) == *(lpCaption + 0)) /* unused variables */
|
|
hWnd = NULL;
|
|
return (0);
|
|
} /* not going to maintain message boxes on the Microsoft compilers */
|
|
INLINE void message(char *body, int priority)
|
|
{
|
|
priority ^= priority;
|
|
*(body + 0) = '\0';
|
|
return; /* Why? Because I am keeping Win32-only builds dependency-free. */
|
|
} /* The primary target is GNU/GCC (cross-OS portability, free of APIs). */
|
|
#else
|
|
#define INLINE inline
|
|
__declspec(dllimport) int __stdcall MessageBoxA(
|
|
HWND hWnd,
|
|
const char *lpText,
|
|
const char *lpCaption,
|
|
unsigned int uType);
|
|
/* No need to import the Windows API, just a message trace function. */
|
|
const unsigned int type_index[4] = {
|
|
0x00000000, /* no icon or effect `MB_OK`, for O.K. encounters */
|
|
0x00000020, /* MB_ICONQUESTION -- curious situation in emulator */
|
|
0x00000030, /* MB_ICONEXCLAMATION -- might be missing RSP support */
|
|
0x00000010 /* MB_ICONHAND -- definite error or problem in emulator */
|
|
};
|
|
void message(char *body, int priority)
|
|
{
|
|
priority &= 03;
|
|
if (priority < MINIMUM_MESSAGE_PRIORITY)
|
|
return;
|
|
MessageBoxA(NULL, body, NULL, type_index[priority]);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#define CFG_HLE (conf[0x00])
|
|
#define CFG_HLE_GFX ((CFG_HLE >> 0) & 1)
|
|
#define CFG_HLE_AUD ((CFG_HLE >> 1) & 1)
|
|
#define CFG_HLE_VID ((CFG_HLE >> 2) & 1) /* reserved/unused */
|
|
#define CFG_HLE_JPG ((CFG_HLE >> 3) & 1) /* reserved/unused */
|
|
#define CFG_HLE_005 (0) /* I have no idea what (OSTask.type == 5) is. */
|
|
#define CFG_HLE_HVQ ((CFG_HLE >> 5) & 1) /* reserved/unused */
|
|
#define CFG_HLE_HVQM ((CFG_HLE >> 6) & 1) /* reserved/unused */
|
|
#define CFG_HLE_UNK ((CFG_HLE >> 7) & 1) /* anything else, reserved */
|
|
/*
|
|
* Most of the point behind this config system is to let users use HLE video
|
|
* or audio plugins. The other task types are used less than 1% of the time
|
|
* and only in a few games. They require simulation from within the RSP
|
|
* internally, which I have no intention to ever support. Some good research
|
|
* on a few of these special task types was done by Hacktarux in the MUPEN64
|
|
* HLE RSP plugin, so consider using that instead for complete HLE.
|
|
*/
|
|
|
|
/*
|
|
* Anything between 0x01 and 0x0F of the config file, I have not yet found a
|
|
* use for. That section of bits is currently all reserved for new settings.
|
|
*/
|
|
|
|
#define CFG_WAIT_FOR_CPU_HOST (*(int *)(conf + 0x10) != 0x00000000)
|
|
#define CFG_MEND_SEMAPHORE_LOCK (*(int *)(conf + 0x14) != 0x00000000)
|
|
#define CFG_RESERVED (*(int *)(conf + 0x18) != 0x00000000)
|
|
#define CFG_CHECKSUM (*(unsigned int *)(conf + 0x1C) != 0x00000000)
|
|
|
|
void update_conf(void)
|
|
{
|
|
FILE* stream;
|
|
register int i, test;
|
|
register unsigned int checksum;
|
|
|
|
stream = fopen(filename, "rb");
|
|
if (stream == NULL)
|
|
{
|
|
message("Failed to read config.", 3);
|
|
return;
|
|
}
|
|
for (i = 0; i < 32; i++)
|
|
{
|
|
test = fgetc(stream);
|
|
if (test == EOF)
|
|
{
|
|
message("Config file too small.", 3);
|
|
memset(conf, 0x00, 32);
|
|
return;
|
|
}
|
|
conf[i] = (unsigned char)(test);
|
|
}
|
|
if (test != EOF)
|
|
{
|
|
message("Config file too large.", 3);
|
|
memset(conf, 0x00, 32);
|
|
return;
|
|
}
|
|
/* my own little checksum code, not really useful :P */
|
|
checksum = 0x00000000;
|
|
for (i = 0; i < 32; i++)
|
|
checksum = checksum
|
|
+ !!(conf[i] & 0x80)
|
|
+ !!(conf[i] & 0x40)
|
|
+ !!(conf[i] & 0x20)
|
|
+ !!(conf[i] & 0x10)
|
|
+ !!(conf[i] & 0x08)
|
|
+ !!(conf[i] & 0x04)
|
|
+ !!(conf[i] & 0x02)
|
|
+ !!(conf[i] & 0x01);
|
|
if (checksum != CFG_CHECKSUM)
|
|
{
|
|
message("Checksum mismatch.", 3);
|
|
memset(conf, 0x00, 32);
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static int temp_PC;
|
|
#ifdef WAIT_FOR_CPU_HOST
|
|
static int MFC0_count[32];
|
|
/* Keep one C0 MF status read count for each scalar register. */
|
|
#endif
|
|
|
|
#define BES(address) (address ^ 03)
|
|
/* Do a swap on the byte endian on a 32-bit segment boundary. */
|
|
#define HES(address) (address ^ 02)
|
|
/* Do a swap on the halfword endian on a 32-bit segment boundary. */
|
|
#define MES(address) (address ^ 01)
|
|
/* Do a mixed endian swap, intermediating between byte and halfword bounds. */
|
|
#define WES(address) (address ^ 00)
|
|
/* Because MIPS and Win32 machines are both 32 bits, no endian update needed. */
|
|
|
|
// #define VR_B(v, e) (((unsigned char *)VR[v])[(e) ^ 0x1])
|
|
// #define VR_B(v, e) ((((unsigned char *)(VR+v))[(e) ^ 0x1]))
|
|
#define VR_B(v, e) (*(unsigned char *)(((unsigned char *)(VR+v)) + ((e) ^ 0x1)))
|
|
/* In `vu.h` we have defined `static short VR[32][8]`, a proper two-
|
|
* dimensional array for accurately storing real signal vectors (big endian).
|
|
*
|
|
* The weakness to this is that it fixates all VR indexing to 16-bit shorts.
|
|
* We can still use "pointer" indirection if we need to target by octet.
|
|
*/
|
|
#define VR_S(v, e) (*(short *)((unsigned char *)(*(VR + v)) + ((e + 01) & ~01)))
|
|
/* Say we are emulating: `LSV $v0[0x0], 0x000($0)`.
|
|
* We can accurately use a proper vector file: `VR[0][00] = *(short *)addr`.
|
|
*
|
|
* What about: `LSV $v0[0x1], 0x000($0)`?
|
|
*
|
|
* That is what the macro above is for. `VR_S(0, 0x1) = *(short *)addr`.
|
|
* With this we can span across the vector register element indexing barrier.
|
|
*/
|
|
#define VR_H(v, e) (*(short *)((unsigned char *)(*(VR + v)) + e))
|
|
/* The VR_S macro above is more stable but slower.
|
|
* In some cases, we may as well adjust the elemental offset, if it is odd.
|
|
* If this is made flexible in advance, we can just use this macro to finish.
|
|
*/
|
|
|
|
#define SR_B(s, i) (*(unsigned char *)(((unsigned char *)(SR+s)) + i))
|
|
#define SR_S(s, i) (*(short *)(((unsigned char *)(SR+s)) + HES(i)))
|
|
|
|
#if (0)
|
|
#define MASK_SA(sa) (sa & 31) /* Force masking in software. */
|
|
#else
|
|
#define MASK_SA(sa) (sa) /* Let hardware architecture do the mask for us. */
|
|
#endif
|
|
/* This optimization only works for shift amounts on variable data.
|
|
* Its only use so far is simplifying SLL, SRL, SRA, SLLV, SRLV, and SRAV.
|
|
*
|
|
* Basically, Intel and MIPS versions here are both 32 bits, so they ignore
|
|
* any upper bits of shift amounts past 0b11111 (31 dec) as reserved.
|
|
*/
|
|
|
|
#include "su/su.h"
|
|
#include "vu/vu.h"
|
|
|
|
#ifdef SP_EXECUTE_LOG
|
|
extern void step_SP_commands(unsigned long inst);
|
|
extern void export_SP_memory(void);
|
|
extern void trace_RSP_registers(void);
|
|
static FILE *output_log;
|
|
#endif
|
|
|
|
/* Allocate the RSP CPU loop to its own functional space. */
|
|
extern void run_task(void);
|
|
#include "execute.h"
|
|
|
|
#ifdef SP_EXECUTE_LOG
|
|
void step_SP_commands(unsigned long inst)
|
|
{
|
|
if (output_log)
|
|
{
|
|
const char digits[16] = {
|
|
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
|
|
};
|
|
char text[256];
|
|
char offset[4] = "";
|
|
char code[9] = "";
|
|
unsigned char endian_swap[4];
|
|
|
|
endian_swap[00] = (unsigned char)(inst >> 24);
|
|
endian_swap[01] = (unsigned char)(inst >> 16);
|
|
endian_swap[02] = (unsigned char)(inst >> 8);
|
|
endian_swap[03] = (unsigned char)inst;
|
|
offset[00] = digits[(*RSP.SP_PC_REG & 0xF00) >> 8];
|
|
offset[01] = digits[(*RSP.SP_PC_REG & 0x0F0) >> 4];
|
|
offset[02] = digits[(*RSP.SP_PC_REG & 0x00F) >> 0];
|
|
code[00] = digits[(inst & 0xF0000000) >> 28];
|
|
code[01] = digits[(inst & 0x0F000000) >> 24];
|
|
code[02] = digits[(inst & 0x00F00000) >> 20];
|
|
code[03] = digits[(inst & 0x000F0000) >> 16];
|
|
code[04] = digits[(inst & 0x0000F000) >> 12];
|
|
code[05] = digits[(inst & 0x00000F00) >> 8];
|
|
code[06] = digits[(inst & 0x000000F0) >> 4];
|
|
code[07] = digits[(inst & 0x0000000F) >> 0];
|
|
strcpy(text, offset);
|
|
strcat(text, "\n");
|
|
strcat(text, code);
|
|
message(text, 0); /* PC offset, MIPS hex. */
|
|
if (output_log == NULL) {} else /* Global pointer not updated?? */
|
|
fwrite(endian_swap, 4, 1, output_log);
|
|
}
|
|
}
|
|
|
|
void export_SP_memory(void)
|
|
{ /* cache memory and dynamic RAM shared by CPU */
|
|
FILE *out = fopen("SP_CACHE.BIN", "wb");
|
|
fwrite(RSP.DMEM, sizeof(unsigned char), 0x1FFF + 1, out);
|
|
fclose(out);
|
|
out = fopen("SP_DRAM.BIN", "wb");
|
|
fwrite(RSP.RDRAM, sizeof(unsigned char), 0x3FFFFF + 1, out);
|
|
return;
|
|
}
|
|
|
|
void trace_RSP_registers(void)
|
|
{ /* no interface--using file I/O only */
|
|
FILE *out = fopen("SP_STATE.TXT", "w");
|
|
|
|
fprintf(out, "RCP Communications Register Display\n\n");
|
|
fclose(out);
|
|
out = fopen("SP_STATE.TXT", "a");
|
|
/* The precise names for RSP CP0 registers are somewhat difficult to define.
|
|
* Generally, I have tried to adhere to the names shared from bpoint/zilmar,
|
|
* while also merging the concrete purpose and correct assembler references.
|
|
* Whether or not you find these names agreeable is mostly a matter of seeing
|
|
* them from the RCP's point of view or the CPU host's mapped point of view.
|
|
*/
|
|
fprintf(out, "SP_MEM_ADDR: %08X CMD_START: %08X\n",
|
|
*RSP.SP_MEM_ADDR_REG, *RSP.DPC_START_REG);
|
|
fprintf(out, "SP_DRAM_ADDR: %08X CMD_END: %08X\n",
|
|
*RSP.SP_DRAM_ADDR_REG, *RSP.DPC_END_REG);
|
|
fprintf(out, "SP_DMA_RD_LEN: %08X CMD_CURRENT: %08X\n",
|
|
*RSP.SP_RD_LEN_REG, *RSP.DPC_CURRENT_REG);
|
|
fprintf(out, "SP_DMA_WR_LEN: %08X CMD_STATUS: %08X\n",
|
|
*RSP.SP_WR_LEN_REG, *RSP.DPC_STATUS_REG);
|
|
fprintf(out, "SP_STATUS: %08X CMD_CLOCK: %08X\n",
|
|
*RSP.SP_STATUS_REG, *RSP.DPC_CLOCK_REG);
|
|
fprintf(out, "SP_DMA_FULL: %08X CMD_BUSY: %08X\n",
|
|
*RSP.SP_DMA_FULL_REG, *RSP.DPC_BUFBUSY_REG);
|
|
fprintf(out, "SP_DMA_BUSY: %08X CMD_PIPE_BUSY: %08X\n",
|
|
*RSP.SP_DMA_BUSY_REG, *RSP.DPC_PIPEBUSY_REG);
|
|
fprintf(out, "SP_SEMAPHORE: %08X CMD_TMEM_BUSY: %08X\n",
|
|
*RSP.SP_SEMAPHORE_REG, *RSP.DPC_TMEM_REG);
|
|
fprintf(out, "SP_PC_REG: 04001%03X\n\n", *RSP.SP_PC_REG & 0x00000FFF);
|
|
/* (PC is only from the CPU point of view, mapped between both halves.) */
|
|
/* There is no memory map for remaining registers not shared by the CPU.
|
|
* The scalar register (SR) file is straightforward and based on the
|
|
* GPR file in the MIPS ISA. However, the RSP assembly language is still
|
|
* different enough from the MIPS assembly language, in that tokens such as
|
|
* "$zero" and "$s0" are no longer valid. "$k0", for example, is not a valid
|
|
* RSP register name because on MIPS it was kernel-use, but on the RSP free.
|
|
* To be colorful/readable, however, I have set the modern MIPS names anyway.
|
|
*/
|
|
fprintf(out, "zero %08X, s0: %08X,\n", SR[ 0], SR[16]);
|
|
fprintf(out, "$at: %08X, s1: %08X,\n", SR[ 1], SR[17]);
|
|
fprintf(out, " v0: %08X, s2: %08X,\n", SR[ 2], SR[18]);
|
|
fprintf(out, " v1: %08X, s3: %08X,\n", SR[ 3], SR[19]);
|
|
fprintf(out, " a0: %08X, s4: %08X,\n", SR[ 4], SR[20]);
|
|
fprintf(out, " a1: %08X, s5: %08X,\n", SR[ 5], SR[21]);
|
|
fprintf(out, " a2: %08X, s6: %08X,\n", SR[ 6], SR[22]);
|
|
fprintf(out, " a3: %08X, s7: %08X,\n", SR[ 7], SR[23]);
|
|
fprintf(out, " t0: %08X, t8: %08X,\n", SR[ 8], SR[24]);
|
|
fprintf(out, " t1: %08X, t9: %08X,\n", SR[ 9], SR[25]);
|
|
fprintf(out, " t2: %08X, k0: %08X,\n", SR[10], SR[26]);
|
|
fprintf(out, " t3: %08X, k1: %08X,\n", SR[11], SR[27]);
|
|
fprintf(out, " t4: %08X, gp: %08X,\n", SR[12], SR[28]);
|
|
fprintf(out, " t5: %08X, $sp: %08X,\n", SR[13], SR[29]);
|
|
fprintf(out, " t6: %08X, $fp: %08X,\n", SR[14], SR[30]);
|
|
fprintf(out, " t7: %08X, $ra: %08X\n\n", SR[15], SR[31]);
|
|
/* (Yes, I rebelliously used the MIPS32 "$fp" modern alias over lazy "$s8".) */
|
|
/* The RSP vector registers are incontestedly named $v[n] and nothing else.
|
|
* The problem is organizing the contents by HW/B elements and proper endian.
|
|
*/
|
|
fprintf(out, " $v0: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[ 0][00], VR[ 0][01], VR[ 0][02], VR[ 0][03],
|
|
VR[ 0][04], VR[ 0][05], VR[ 0][06], VR[ 0][07]);
|
|
fprintf(out, " $v1: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[ 1][00], VR[ 1][01], VR[ 1][02], VR[ 1][03],
|
|
VR[ 1][04], VR[ 1][05], VR[ 1][06], VR[ 1][07]);
|
|
fprintf(out, " $v2: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[ 2][00], VR[ 2][01], VR[ 2][02], VR[ 2][03],
|
|
VR[ 2][04], VR[ 2][05], VR[ 2][06], VR[ 2][07]);
|
|
fprintf(out, " $v3: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[ 3][00], VR[ 3][01], VR[ 3][02], VR[ 3][03],
|
|
VR[ 3][04], VR[ 3][05], VR[ 3][06], VR[ 3][07]);
|
|
fprintf(out, " $v4: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[ 4][00], VR[ 4][01], VR[ 4][02], VR[ 4][03],
|
|
VR[ 4][04], VR[ 4][05], VR[ 4][06], VR[ 4][07]);
|
|
fprintf(out, " $v5: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[ 5][00], VR[ 5][01], VR[ 5][02], VR[ 5][03],
|
|
VR[ 5][04], VR[ 5][05], VR[ 5][06], VR[ 5][07]);
|
|
fprintf(out, " $v6: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[ 6][00], VR[ 6][01], VR[ 6][02], VR[ 6][03],
|
|
VR[ 6][04], VR[ 6][05], VR[ 6][06], VR[ 6][07]);
|
|
fprintf(out, " $v7: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[ 7][00], VR[ 7][01], VR[ 7][02], VR[ 7][03],
|
|
VR[ 7][04], VR[ 7][05], VR[ 7][06], VR[ 7][07]);
|
|
fprintf(out, " $v8: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[ 8][00], VR[ 8][01], VR[ 8][02], VR[ 8][03],
|
|
VR[ 8][04], VR[ 8][05], VR[ 8][06], VR[ 8][07]);
|
|
fprintf(out, " $v9: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[ 9][00], VR[ 9][01], VR[ 9][02], VR[ 9][03],
|
|
VR[ 9][04], VR[ 9][05], VR[ 9][06], VR[ 9][07]);
|
|
fprintf(out, "$v10: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[10][00], VR[10][01], VR[10][02], VR[10][03],
|
|
VR[10][04], VR[10][05], VR[10][06], VR[10][07]);
|
|
fprintf(out, "$v11: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[11][00], VR[11][01], VR[11][02], VR[11][03],
|
|
VR[11][04], VR[11][05], VR[11][06], VR[11][07]);
|
|
fprintf(out, "$v12: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[12][00], VR[12][01], VR[12][02], VR[12][03],
|
|
VR[12][04], VR[12][05], VR[12][06], VR[12][07]);
|
|
fprintf(out, "$v13: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[13][00], VR[13][01], VR[13][02], VR[13][03],
|
|
VR[13][04], VR[13][05], VR[13][06], VR[13][07]);
|
|
fprintf(out, "$v14: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[14][00], VR[14][01], VR[14][02], VR[14][03],
|
|
VR[14][04], VR[14][05], VR[14][06], VR[14][07]);
|
|
fprintf(out, "$v15: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[15][00], VR[15][01], VR[15][02], VR[15][03],
|
|
VR[15][04], VR[15][05], VR[15][06], VR[15][07]);
|
|
fprintf(out, "$v16: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[16][00], VR[16][01], VR[16][02], VR[16][03],
|
|
VR[16][04], VR[16][05], VR[16][06], VR[16][07]);
|
|
fprintf(out, "$v17: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[17][00], VR[17][01], VR[17][02], VR[17][03],
|
|
VR[17][04], VR[17][05], VR[17][06], VR[17][07]);
|
|
fprintf(out, "$v18: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[18][00], VR[18][01], VR[18][02], VR[18][03],
|
|
VR[18][04], VR[18][05], VR[18][06], VR[18][07]);
|
|
fprintf(out, "$v19: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[19][00], VR[19][01], VR[19][02], VR[19][03],
|
|
VR[19][04], VR[19][05], VR[19][06], VR[19][07]);
|
|
fprintf(out, "$v20: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[20][00], VR[20][01], VR[20][02], VR[20][03],
|
|
VR[20][04], VR[20][05], VR[20][06], VR[20][07]);
|
|
fprintf(out, "$v21: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[21][00], VR[21][01], VR[21][02], VR[21][03],
|
|
VR[21][04], VR[21][05], VR[21][06], VR[21][07]);
|
|
fprintf(out, "$v22: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[22][00], VR[22][01], VR[22][02], VR[22][03],
|
|
VR[22][04], VR[22][05], VR[22][06], VR[22][07]);
|
|
fprintf(out, "$v23: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[23][00], VR[23][01], VR[23][02], VR[23][03],
|
|
VR[23][04], VR[23][05], VR[23][06], VR[23][07]);
|
|
fprintf(out, "$v24: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[24][00], VR[24][01], VR[24][02], VR[24][03],
|
|
VR[24][04], VR[24][05], VR[24][06], VR[24][07]);
|
|
fprintf(out, "$v25: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[25][00], VR[25][01], VR[25][02], VR[25][03],
|
|
VR[25][04], VR[25][05], VR[25][06], VR[25][07]);
|
|
fprintf(out, "$v26: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[26][00], VR[26][01], VR[26][02], VR[26][03],
|
|
VR[26][04], VR[26][05], VR[26][06], VR[26][07]);
|
|
fprintf(out, "$v27: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[27][00], VR[27][01], VR[27][02], VR[27][03],
|
|
VR[27][04], VR[27][05], VR[27][06], VR[27][07]);
|
|
fprintf(out, "$v28: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[28][00], VR[28][01], VR[28][02], VR[28][03],
|
|
VR[28][04], VR[28][05], VR[28][06], VR[28][07]);
|
|
fprintf(out, "$v29: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[29][00], VR[29][01], VR[29][02], VR[29][03],
|
|
VR[29][04], VR[29][05], VR[29][06], VR[29][07]);
|
|
fprintf(out, "$v30: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n",
|
|
VR[30][00], VR[30][01], VR[30][02], VR[30][03],
|
|
VR[30][04], VR[30][05], VR[30][06], VR[30][07]);
|
|
fprintf(out, "$v31: [%04X][%04X][%04X][%04X][%04X][%04X][%04X][%04X]\n\n"
|
|
, VR[31][00], VR[31][01], VR[31][02], VR[31][03],
|
|
VR[31][04], VR[31][05], VR[31][06], VR[31][07]);
|
|
/* The SU has its fair share of registers, but the VU has its counterparts.
|
|
* Just like we have the scalar 16 system control registers for the RSP CP0,
|
|
* we have also a tiny group of special-purpose, vector control registers.
|
|
*/
|
|
fprintf(out, "$vco: [%02X][%02X]\n", (VCO >> 8), VCO & 0x00FF);
|
|
fprintf(out, "$vcc: [%02X][%02X]\n", (VCC >> 8), VCC & 0x00FF);
|
|
fprintf(out, "$vce: %02X\n\n", VCE); /* 8-bit vector cnd. flags register */
|
|
/* Last and least are the 48-bit accumulator elements, which literally may or
|
|
* may not be considered as "registers" but are still useful to debug, in
|
|
* spite of how near-pointless emulating them is (mostly VSAR/VSAW, VMAC*).
|
|
*
|
|
* I have not confirmed memory endianness controversies for ordering bytes.
|
|
* I decided, better to print 48 bits, not 3 pairs of 16, cause basically
|
|
* every write to the accumulator updates potentially all 48 bits, not 1 HW.
|
|
* ("%012X" seems a better idea than [%04X][%04X][%04X], similar to above.)
|
|
* Without VSAR/VSAW, all single HW R/W's are the low 16 bits of acc. only.
|
|
*/
|
|
fprintf(out, "VACC[0]: %012X\n", VACC[00].DW & 0xFFFFFFFFFFFF);
|
|
fprintf(out, "VACC[1]: %012X\n", VACC[01].DW & 0xFFFFFFFFFFFF);
|
|
fprintf(out, "VACC[2]: %012X\n", VACC[02].DW & 0xFFFFFFFFFFFF);
|
|
fprintf(out, "VACC[3]: %012X\n", VACC[03].DW & 0xFFFFFFFFFFFF);
|
|
fprintf(out, "VACC[4]: %012X\n", VACC[04].DW & 0xFFFFFFFFFFFF);
|
|
fprintf(out, "VACC[5]: %012X\n", VACC[05].DW & 0xFFFFFFFFFFFF);
|
|
fprintf(out, "VACC[6]: %012X\n", VACC[06].DW & 0xFFFFFFFFFFFF);
|
|
fprintf(out, "VACC[7]: %012X\n\n", VACC[07].DW & 0xFFFFFFFFFFFF);
|
|
/* I lied (sort of). Can't possibly forget the internal registers used by
|
|
* the computational vector divide operations! (Hmmm okay now I lied.)
|
|
*/
|
|
fprintf(out, "DivIn: %i\n", DivIn);
|
|
fprintf(out, "DivOut: %i\n", DivOut);
|
|
/* MovIn: This reg. might exist for VMOV, but it is obsolete to emulate. */
|
|
fprintf(out, DPH ? "DPH: true\n" : "DPH: false\n");
|
|
fclose(out);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#endif
|