/*==================================================================== filename: gdsp_interpreter.cpp project: GCemu created: 2004-6-18 mail: duddie@walla.com Copyright (c) 2005 Duddie & Tratax This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ====================================================================*/ #include #include #include "DSPTables.h" #include "gdsp_interface.h" #include "gdsp_opcodes_helper.h" #include "Tools.h" //------------------------------------------------------------------------------- SDSP g_dsp; u16 SDSP::r[32]; u16 SDSP::pc = 0; u16 SDSP::err_pc = 0; u16* SDSP::iram = 0; u16* SDSP::dram = 0; u16* SDSP::irom = 0; u16* SDSP::drom = 0; u16* SDSP::coef = 0; u8* SDSP::cpu_ram = 0; u16 SDSP::cr = 0; u8 SDSP::reg_stack_ptr[4]; u8 SDSP::exceptions; // lets make stack depth to 32 for now u16 SDSP::reg_stack[4][DSP_STACK_DEPTH]; void (*SDSP::irq_request)() = NULL; bool SDSP::exception_in_progress_hack = false; // should be replaced with bit9 in SR? // for debugger only bool SDSP::dump_imem = false; u32 SDSP::iram_crc = 0; u64 SDSP::step_counter = 0; bool gdsp_running; extern volatile u32 dsp_running; static bool cr_halt = true; static bool cr_external_int = false; // SR flag defines. // These are probably not accurate. Do not use yet. #define SR_LOGIC_ZERO 0x0040 // ?? duddie's doc sometimes say & 1<<6, sometimes 1<<14 (0x4000) #define SR_PROD_MUL2 0x2000 #define SR_SIGN 0x0008 #define SR_ARITH_ZERO 0x0002 #define SR_INT_ENABLE 0x0200 void UpdateCachedCR() { cr_halt = (g_dsp.cr & 0x4) != 0; cr_external_int = (g_dsp.cr & 0x02) != 0; } //------------------------------------------------------------------------------- void dbg_error(char* err_msg) { return; } void gdsp_init() { // Why do we have DROM? Does it exist? Has it been dumped? g_dsp.irom = (u16*)malloc(DSP_IROM_SIZE * sizeof(u16)); g_dsp.iram = (u16*)malloc(DSP_IRAM_SIZE * sizeof(u16)); g_dsp.drom = (u16*)malloc(DSP_DROM_SIZE * sizeof(u16)); g_dsp.dram = (u16*)malloc(DSP_DRAM_SIZE * sizeof(u16)); g_dsp.coef = (u16*)malloc(DSP_COEF_SIZE * sizeof(u16)); // Fill memories with junk. for (int i = 0; i < DSP_IRAM_SIZE; i++) { g_dsp.iram[i] = 0x0021; // HALT opcode } for (int i = 0; i < DSP_DRAM_SIZE; i++) { g_dsp.dram[i] = 0x0021; // HALT opcode } // Fill roms with zeros. for (int i = 0; i < 32; i++) { g_dsp.r[i] = 0; } for (int i = 0; i < 4; i++) { g_dsp.reg_stack_ptr[i] = 0; for (int j = 0; j < DSP_STACK_DEPTH; j++) { g_dsp.reg_stack[i][j] = 0; } } // copied from a real console after the custom UCode has been loaded g_dsp.r[0x08] = 0xffff; g_dsp.r[0x09] = 0xffff; g_dsp.r[0x0a] = 0xffff; g_dsp.r[0x0b] = 0xffff; g_dsp.cr = 0x804; gdsp_ifx_init(); UpdateCachedCR(); } void gdsp_reset() { // _assert_msg_(0, "gdsp_reset()"); _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "reset while exception"); g_dsp.pc = DSP_RESET_VECTOR; g_dsp.exception_in_progress_hack = false; } void gdsp_generate_exception(u8 level) { g_dsp.exceptions |= 1 << level; } bool gdsp_load_rom(const char *fname) { FILE *pFile = fopen(fname, "rb"); if (pFile) { size_t size_in_bytes = DSP_IROM_SIZE * sizeof(u16); size_t read_bytes = fread(g_dsp.irom, 1, size_in_bytes, pFile); if (read_bytes != size_in_bytes) { PanicAlert("IROM too short : %i/%i", (int)read_bytes, (int)size_in_bytes); fclose(pFile); return false; } fclose(pFile); return true; } return false; } bool gdsp_load_coef(const char *fname) { FILE *pFile = fopen(fname, "rb"); if (pFile) { size_t size_in_bytes = DSP_COEF_SIZE * sizeof(u16); size_t read_bytes = fread(g_dsp.coef, 1, size_in_bytes, pFile); if (read_bytes != size_in_bytes) { PanicAlert("COEF too short : %i/%i", (int)read_bytes, (int)size_in_bytes); fclose(pFile); return false; } fclose(pFile); return true; } return false; } // Hm, should instructions that change CR use this? Probably not (but they // should call UpdateCachedCR()) void gdsp_write_cr(u16 val) { // reset if (val & 0x0001) { gdsp_reset(); } val &= ~0x0001; // update cr g_dsp.cr = val; UpdateCachedCR(); } // Hm, should instructions that read CR use this? (Probably not). u16 gdsp_read_cr() { if (g_dsp.pc & 0x8000) { g_dsp.cr |= 0x800; } else { g_dsp.cr &= ~0x800; } UpdateCachedCR(); return g_dsp.cr; } // special loop step.. because exception in loop or loopi fails // dunno how we have to fix it // atm we execute this instructions directly inside the loop command // so it cant be interrupted by an exception. // TODO - we really should figure this out - on the real DSP, exception inside // loop should work. Think through the stack management and how it works // with exceptions and in loops. void gdsp_loop_step() { g_dsp.err_pc = g_dsp.pc; u16 opc = dsp_fetch_code(); ComputeInstruction(UDSPInstruction(opc)); } u16 HLE_ROM_80E7_81F8(); void hacks(); void gdsp_step() { g_dsp.step_counter++; if (g_dsp.pc == 0x80e7) { //g_dsp.pc = HLE_ROM_80E7_81F8(); } g_dsp.err_pc = g_dsp.pc; #if PROFILE ProfilerAddDelta(g_dsp.err_pc, 1); if (g_dsp.step_counter == 1) { ProfilerInit(); } if ((g_dsp.step_counter & 0xFFFFF) == 0) { ProfilerDump(g_dsp.step_counter); } #endif u16 opc = dsp_fetch_code(); ComputeInstruction(UDSPInstruction(opc)); u16& rLoopCounter = g_dsp.r[DSP_REG_ST0 + 3]; if (rLoopCounter > 0) { const u16& rCallAddress = g_dsp.r[DSP_REG_ST0 + 0]; const u16& rLoopAddress = g_dsp.r[DSP_REG_ST0 + 2]; if (g_dsp.pc == (rLoopAddress + 1)) { rLoopCounter--; if (rLoopCounter > 0) { g_dsp.pc = rCallAddress; } else { // end of loop dsp_reg_load_stack(0); dsp_reg_load_stack(2); dsp_reg_load_stack(3); } } } // check if there is an external interrupt if (cr_external_int) { if (dsp_SR_is_flag_set(FLAG_ENABLE_INTERUPT) && (g_dsp.exception_in_progress_hack == false)) { // level 7 is the interrupt exception gdsp_generate_exception(7); g_dsp.cr &= ~0x0002; UpdateCachedCR(); } } // check exceptions if ((g_dsp.exceptions != 0) && (!g_dsp.exception_in_progress_hack)) { for (int i = 0; i < 8; i++) { if (g_dsp.exceptions & (1 << i)) { _assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception"); dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); dsp_reg_store_stack(DSP_STACK_D, g_dsp.r[R_SR]); g_dsp.pc = i * 2; g_dsp.exceptions &= ~(1 << i); g_dsp.exception_in_progress_hack = true; break; } } } } bool gdsp_run() { gdsp_running = true; while (!cr_halt) { gdsp_step(); if (!gdsp_running) break; } gdsp_running = false; return true; } bool gdsp_runx(u16 cnt) { gdsp_running = true; while (!(g_dsp.cr & 0x4) && gdsp_running) { gdsp_step(); cnt--; if (cnt == 0) { break; } } gdsp_running = false; return true; } void gdsp_stop() { gdsp_running = false; } /////////////////////////////////////////////////////////////////////////////// // // From fires for fires :) // // #include "disassemble.h" //#include "WaveFile.h" #include "Mixer.h" // u16 r30 = 0, r31 = 0; //extern WaveFileWriter g_wave_writer; extern u16 dsp_swap16(u16 x); void Hacks() { // if (g_wave_writer.GetAudioSize() > 1024*1024*1) /* if (g_dsp.pc == 0x165) { PanicAlert("Opcode_06"); } if (g_dsp.pc == 0x43b) { PanicAlert("Opcode_14"); } if (g_dsp.pc == 0xb37) { PanicAlert("Opcode_08"); }*/ /* if (g_dsp.pc == 0x1bc) { r30 = g_dsp.r[30]; r31 = g_dsp.r[31]; } else if (g_dsp.pc == 0x384) { // if ((r30 == 0x1bc) && (r31 == 0xaff)) { //PanicAlert("%x, %x", r30, r31); const int numSamples = 0x280; static short Buffer[numSamples]; u16 bufferAddr = 0x280; //dsp_dmem_read(0xe44); for (int i=0; i 1024*1024*2) { //PanicAlert("%x", bufferAddr); g_wave_writer.Stop(); exit(1); } } } */ if (g_dsp.pc == 0x468) { int numSamples = g_dsp.r[25] / 2; u16 bufferAddr = g_dsp.r[27]; // PanicAlert("%x %x", bufferAddr, numSamples); short samples[1024]; for (int i=0; iGetMixer()->PushSamples(samples, numSamples / 2, 32000); //sample_rate); // g_wave_writer.AddStereoSamples(samples, numSamples/2); // 2 channels // if (g_wave_writer.GetAudioSize() > 1024*1024*2) // { //PanicAlert("%x", bufferAddr); // g_wave_writer.Stop(); // exit(1); // } } }