/*==================================================================== filename: gdsp_opcodes_helper.h project: GameCube DSP Tool (gcdsp) created: 2005.03.04 mail: duddie@walla.com Copyright (c) 2005 Duddie 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. ====================================================================*/ #ifndef _DSP_INT_UTIL_H #define _DSP_INT_UTIL_H #include "Common.h" #include "DSPInterpreter.h" #include "DSPCore.h" #include "DSPMemoryMap.h" #include "DSPStacks.h" // --------------------------------------------------------------------------------------- // --- SR // --------------------------------------------------------------------------------------- inline void dsp_SR_set_flag(int flag) { g_dsp.r[DSP_REG_SR] |= flag; } inline bool dsp_SR_is_flag_set(int flag) { return (g_dsp.r[DSP_REG_SR] & flag) != 0; } // --------------------------------------------------------------------------------------- // --- AR increments, decrements // --------------------------------------------------------------------------------------- // // HORRIBLE UGLINESS, someone please fix. // See http://code.google.com/p/dolphin-emu/source/detail?r=3125 // // increment, decrement 100% ok (as far as i can tell), increase, decrease still probs // NextPowerOf2()-1 inline u16 ToMask(u16 a) { a = a | (a >> 8); a = a | (a >> 4); a = a | (a >> 2); return a | (a >> 1); } inline u16 dsp_increment_addr_reg(u16 reg, u16 ar) { u16 wr = g_dsp.r[DSP_REG_WR0 + reg]; u16 tmb = ToMask(wr); if ((ar & tmb) == tmb) ar-=wr; else ar++; return ar; } inline u16 dsp_increment_addr_reg(u16 reg) { return dsp_increment_addr_reg(reg, g_dsp.r[reg]); } inline u16 dsp_decrement_addr_reg(u16 reg, u16 ar) { u16 wr = g_dsp.r[DSP_REG_WR0 + reg]; u16 tmb = ToMask(wr); u16 min = (tmb+1-ar)&tmb; if ((wr < min) || !min) ar+=wr; else ar--; return ar; } inline u16 dsp_decrement_addr_reg(u16 reg) { return dsp_decrement_addr_reg(reg, g_dsp.r[reg]); } inline u16 dsp_increase_addr_reg(u16 reg, s16 ix) { u16 ar = g_dsp.r[reg]; if (ix > 0) { for (s32 i = 0; i < ix; i++) { ar = dsp_increment_addr_reg(reg, ar); } } else if (ix < 0) { for (s32 i = 0; i < (-ix); i++) { ar = dsp_decrement_addr_reg(reg, ar); } } return ar; } inline u16 dsp_decrease_addr_reg(u16 reg, s16 ix) { u16 ar = g_dsp.r[reg]; if (ix > 0) { for (s32 i = 0; i < ix; i++) { ar = dsp_decrement_addr_reg(reg, ar); } } else if (ix < 0) { for (s32 i = 0; i < (-ix); i++) { ar = dsp_increment_addr_reg(reg, ar); } } return ar; } // --------------------------------------------------------------------------------------- // --- reg // --------------------------------------------------------------------------------------- inline u16 dsp_op_read_reg(int reg) { switch (reg & 0x1f) { case DSP_REG_ST0: case DSP_REG_ST1: case DSP_REG_ST2: case DSP_REG_ST3: return dsp_reg_load_stack(reg - 0x0c); default: return g_dsp.r[reg]; } } inline void dsp_op_write_reg(int reg, u16 val) { switch (reg & 0x1f) { // 8-bit sign extended registers. Should look at prod.h too... case DSP_REG_ACH0: case DSP_REG_ACH1: // sign extend from the bottom 8 bits. g_dsp.r[reg] = (u16)(s16)(s8)(u8)val; break; case DSP_REG_ACM0: case DSP_REG_ACM1: g_dsp.r[reg] = val; break; // Stack registers. case DSP_REG_ST0: case DSP_REG_ST1: case DSP_REG_ST2: case DSP_REG_ST3: dsp_reg_store_stack(reg - 0x0c, val); break; default: g_dsp.r[reg] = val; break; } } inline void dsp_conditional_extend_accum(int reg) { switch (reg) { case DSP_REG_ACM0: case DSP_REG_ACM1: if (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT) { // Sign extend into whole accum. u16 val = g_dsp.r[reg]; g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = (val & 0x8000) ? 0xFFFF : 0x0000; g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; } } } // --------------------------------------------------------------------------------------- // --- prod // --------------------------------------------------------------------------------------- inline s64 dsp_get_long_prod() { #if PROFILE ProfilerAddDelta(g_dsp.err_pc, 1); #endif s64 val = (s8)(u8)g_dsp.r[DSP_REG_PRODH]; val <<= 32; s64 low_prod = g_dsp.r[DSP_REG_PRODM]; low_prod += g_dsp.r[DSP_REG_PRODM2]; low_prod <<= 16; low_prod |= g_dsp.r[DSP_REG_PRODL]; val += low_prod; return val; } inline s64 dsp_get_long_prod_round_prodl() { return (dsp_get_long_prod() + 0x7fff) & ~0xffff; } // For accurate emulation, this is wrong - but the real prod registers behave // in completely bizarre ways. Probably not meaningful to emulate them accurately. inline void dsp_set_long_prod(s64 val) { #if PROFILE ProfilerAddDelta(g_dsp.err_pc, 1); #endif g_dsp.r[DSP_REG_PRODL] = (u16)val; val >>= 16; g_dsp.r[DSP_REG_PRODM] = (u16)val; val >>= 16; g_dsp.r[DSP_REG_PRODH] = (u8)val; g_dsp.r[DSP_REG_PRODM2] = 0; } // --------------------------------------------------------------------------------------- // --- ACC - main accumulators (40-bit) // --------------------------------------------------------------------------------------- inline s64 dsp_get_long_acc(int reg) { #if PROFILE ProfilerAddDelta(g_dsp.err_pc, 1); #endif _assert_(reg < 2); s64 high = (s64)(s8)g_dsp.r[DSP_REG_ACH0 + reg] << 32; u32 mid_low = ((u32)g_dsp.r[DSP_REG_ACM0 + reg] << 16) | g_dsp.r[DSP_REG_ACL0 + reg]; return high | mid_low; } inline void dsp_set_long_acc(int _reg, s64 val) { #if PROFILE ProfilerAddDelta(g_dsp.err_pc, 1); #endif _assert_(_reg < 2); g_dsp.r[DSP_REG_ACL0 + _reg] = (u16)val; val >>= 16; g_dsp.r[DSP_REG_ACM0 + _reg] = (u16)val; val >>= 16; g_dsp.r[DSP_REG_ACH0 + _reg] = (u16)(s16)(s8)(u8)val; } inline s64 dsp_convert_long_acc(s64 val) // s64 -> s40 { return ((s64)(s8)(val >> 32))<<32 | (u32)val; } inline s16 dsp_get_acc_l(int _reg) { _assert_(_reg < 2); return g_dsp.r[DSP_REG_ACL0 + _reg]; } inline s16 dsp_get_acc_m(int _reg) { _assert_(_reg < 2); return g_dsp.r[DSP_REG_ACM0 + _reg]; } inline s16 dsp_get_acc_h(int _reg) { _assert_(_reg < 2); return g_dsp.r[DSP_REG_ACH0 + _reg]; } // --------------------------------------------------------------------------------------- // --- AX - extra accumulators (32-bit) // --------------------------------------------------------------------------------------- inline s32 dsp_get_long_acx(int _reg) { #if PROFILE ProfilerAddDelta(g_dsp.err_pc, 1); #endif _assert_(_reg < 2); return ((u32)g_dsp.r[DSP_REG_AXH0 + _reg] << 16) | g_dsp.r[DSP_REG_AXL0 + _reg]; } inline s16 dsp_get_ax_l(int _reg) { _assert_(_reg < 2); return (s16)g_dsp.r[DSP_REG_AXL0 + _reg]; } inline s16 dsp_get_ax_h(int _reg) { _assert_(_reg < 2); return (s16)g_dsp.r[DSP_REG_AXH0 + _reg]; } #endif