#ifndef _RSP_H_ #define _RSP_H_ #include "Rsp_#1.1.h" RSP_INFO RSP; #ifdef _MSC_VER #define INLINE __inline #define NOINLINE __declspec(noinline) #define ALIGNED _declspec(align(16)) #else #define INLINE inline #define NOINLINE __attribute__((noinline)) #define ALIGNED __attribute__((aligned(16))) #endif /* * Streaming SIMD Extensions version import management */ #ifdef ARCH_MIN_SSSE3 #define ARCH_MIN_SSE2 #include #endif #ifdef ARCH_MIN_SSE2 #include #endif typedef unsigned char byte; NOINLINE void message(const char* body, int priority) { /* Avoid SHELL32/ADVAPI32/USER32 dependencies by using standard C to print. */ char argv[4096] = "CMD /Q /D /C \"TITLE RSP Message&&ECHO "; int i = 0; int j = strlen(argv); priority &= 03; if (priority < MINIMUM_MESSAGE_PRIORITY) return; /* * I'm just using system() to call the Windows command shell to print text. * When the subsystem permits, use printf to trace messages, not this crap. * I don't use WIN32 MessageBox because that's just extra OS dependencies. :P */ while (body[i] != '\0') { if (body[i] == '\n') { argv[j + 0] = '&'; argv[j + 1] = '&'; argv[j + 2] = 'E'; argv[j + 3] = 'C'; argv[j + 4] = 'H'; argv[j + 5] = 'O'; argv[j + 6] = ' '; ++i; j += 7; continue; } argv[j++] = body[i++]; } strcat(argv, "&&PAUSE&&EXIT\""); system(argv); return; } /* * Update RSP configuration memory from local file resource. */ #define CHARACTERS_PER_LINE (80) /* typical standard DOS text file limit per line */ NOINLINE void update_conf(const char* source) { FILE* stream; char line[CHARACTERS_PER_LINE] = ""; char key[CHARACTERS_PER_LINE], value[CHARACTERS_PER_LINE]; register int i, test; stream = fopen(source, "r"); if (stream == NULL) { /* try GetModulePath or whatever to correct the path? */ message("Failed to read config.", 3); return; } do { int bvalue; line[0] = '\0'; key[0] = '\0'; value[0] = '\0'; for (i = 0; i < CHARACTERS_PER_LINE; i++) { test = fgetc(stream); if (test < 0) /* either EOF or invalid ASCII characters */ break; line[i] = (char)(test); if (line[i] == '\n') break; } line[i] = '\0'; for (i = 0; i < CHARACTERS_PER_LINE && line[i] != '='; i++); line[i] = '\0'; strcpy(key, line); strcpy(value, line + i + 1); bvalue = atoi(value); if (strcmp(key, "DisplayListToGraphicsPlugin") == 0) CFG_HLE_GFX = (byte)(bvalue); else if (strcmp(key, "AudioListToAudioPlugin") == 0) CFG_HLE_AUD = (byte)(bvalue); else if (strcmp(key, "WaitForCPUHost") == 0) CFG_WAIT_FOR_CPU_HOST = bvalue; else if (strcmp(key, "SupportCPUSemaphoreLock") == 0) CFG_MEND_SEMAPHORE_LOCK = bvalue; } while (test != EOF); fclose(stream); return; } #ifndef EMULATE_STATIC_PC static int stage; #endif static int temp_PC; #ifdef WAIT_FOR_CPU_HOST static short MFC0_count[32]; /* Keep one C0 MF status read count for each scalar register. */ #endif #ifdef SP_EXECUTE_LOG static FILE *output_log; extern void step_SP_commands(unsigned long inst); #endif extern void export_SP_memory(void); NOINLINE void trace_RSP_registers(void); #include "su.h" #include "vu/vu.h" /* Allocate the RSP CPU loop to its own functional space. */ NOINLINE 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); } } #endif NOINLINE void export_data_cache(void) { FILE* out; register unsigned long addr; out = fopen("rcpcache.dhex", "wb"); #if (0) for (addr = 0x00000000; addr < 0x00001000; addr += 0x00000001) fputc(RSP.DMEM[BES(addr & 0x00000FFF)], out); #else for (addr = 0x00000000; addr < 0x00001000; addr += 0x00000004) { fputc(RSP.DMEM[addr + 0x000 + BES(0x000)], out); fputc(RSP.DMEM[addr + 0x001 + MES(0x000)], out); fputc(RSP.DMEM[addr + 0x002 - MES(0x000)], out); fputc(RSP.DMEM[addr + 0x003 - BES(0x000)], out); } #endif fclose(out); return; } NOINLINE void export_instruction_cache(void) { FILE* out; register unsigned long addr; out = fopen("rcpcache.ihex", "wb"); #if (0) for (addr = 0x00000000; addr < 0x00001000; addr += 0x00000001) fputc(RSP.IMEM[BES(addr & 0x00000FFF)], out); #else for (addr = 0x00000000; addr < 0x00001000; addr += 0x00000004) { fputc(RSP.IMEM[addr + 0x000 + BES(0x000)], out); fputc(RSP.IMEM[addr + 0x001 + MES(0x000)], out); fputc(RSP.IMEM[addr + 0x002 - MES(0x000)], out); fputc(RSP.IMEM[addr + 0x003 - BES(0x000)], out); } #endif fclose(out); return; } void export_SP_memory(void) { export_data_cache(); export_instruction_cache(); return; } const char CR_names[16][14] = { "SP_MEM_ADDR ","SP_DRAM_ADDR ","SP_DMA_RD_LEN","SP_DMA_WR_LEN", "SP_STATUS ","SP_DMA_FULL ","SP_DMA_BUSY ","SP_SEMAPHORE ", "CMD_START ","CMD_END ","CMD_CURRENT ","CMD_STATUS ", "CMD_CLOCK ","CMD_BUSY ","CMD_PIPE_BUSY","CMD_TMEM_BUSY", }; const char SR_names[32][5] = { "zero","$at:"," v0:"," v1:"," a0:"," a1:"," a2:"," a3:", " t0:"," t1:"," t2:"," t3:"," t4:"," t5:"," t6:"," t7:", " s0:"," s1:"," s2:"," s3:"," s4:"," s5:"," s6:"," s7:", " t8:"," t9:"," k0:"," k1:"," gp:","$sp:","$s8:","$ra:", }; NOINLINE void trace_RSP_registers(void) { register int i; FILE* out; 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. */ for (i = 0; i < 8; i++) fprintf(out, "%s: %08lX %s: %08lX\n", CR_names[i+0], *(CR[i+0]), CR_names[i+8], *(CR[i+8])); fprintf(out, "SP_PC_REG: %08lX\n\n", *RSP.SP_PC_REG); /* (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. */ for (i = 0; i < 16; i++) fprintf(out, "%s %08X, %s %08X,\n", SR_names[i+0], SR[i+0], SR_names[i+16], SR[i+16]); fprintf(out, "\n"); for (i = 0; i < 10; i++) fprintf( out, " $v%i: [%04hX][%04hX][%04hX][%04hX][%04hX][%04hX][%04hX][%04hX]\n", i, VR[i][00], VR[i][01], VR[i][02], VR[i][03], VR[i][04], VR[i][05], VR[i][06], VR[i][07]); for (i = 10; i < 32; i++) /* decimals "10" and higher with two characters */ fprintf( out, "$v%i: [%04hX][%04hX][%04hX][%04hX][%04hX][%04hX][%04hX][%04hX]\n", i, VR[i][00], VR[i][01], VR[i][02], VR[i][03], VR[i][04], VR[i][05], VR[i][06], VR[i][07]); fprintf(out, "\n"); /* * 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: 0x%04X\n", get_VCO()); fprintf(out, "$vcc: 0x%04X\n", get_VCC()); fprintf(out, "$vce: 0x%02X\n\n", get_VCE()); /* * 48-bit RSP accumulators * Most vector unit patents traditionally call this register file "VACC". * However, typically in discussion about SGI's implementation, we say "ACC". */ for (i = 0; i < 8; i++) fprintf( out, "ACC[%o]: [%04X][%04X][%04X]\n", i, VACC_H[i], VACC_M[i], VACC_L[i]); /* * special-purpose vector unit registers for vector divide operations only */ fprintf(out, "\nDivIn: %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