forked from dolphin-emu/dolphin
		
	Applied the logic from r6691 to the LLE dec/add/sub functions so they work without ToMask. This should give a modest speedup for these. Pierre's AR inc was already perfect and I only adjusted its logic a bit for visual consistency between the interpreter and JIT code. Also applied Pierre's optimization from the LLE inc to the Int inc. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6707 8ced0084-cf51-0410-be5f-012b33b47a6e
		
			
				
	
	
		
			387 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			387 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*====================================================================
 | 
						|
 | 
						|
   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.sr |= flag;
 | 
						|
}
 | 
						|
 | 
						|
inline bool dsp_SR_is_flag_set(int flag)
 | 
						|
{
 | 
						|
	return (g_dsp.r.sr & flag) != 0;
 | 
						|
}
 | 
						|
 | 
						|
// ---------------------------------------------------------------------------------------
 | 
						|
// --- AR increments, decrements
 | 
						|
// ---------------------------------------------------------------------------------------
 | 
						|
 | 
						|
inline u16 dsp_increase_addr_reg(u16 reg, s16 _ix)
 | 
						|
{
 | 
						|
	u32 ar = g_dsp.r.ar[reg];
 | 
						|
	u32 wr = g_dsp.r.wr[reg];
 | 
						|
	s32 ix = _ix;
 | 
						|
	
 | 
						|
	u32 mx = (wr | 1) << 1;
 | 
						|
	u32 nar = ar + ix;
 | 
						|
	u32 dar = (nar ^ ar ^ ix) & mx;
 | 
						|
 | 
						|
	if (ix >= 0)
 | 
						|
	{
 | 
						|
		if (dar > wr) //overflow
 | 
						|
			nar -= wr + 1;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if ((((nar + wr + 1) ^ nar) & dar) <= wr) //underflow or below min for mask
 | 
						|
			nar += wr + 1;
 | 
						|
	}
 | 
						|
	return nar;
 | 
						|
}
 | 
						|
 | 
						|
inline u16 dsp_decrease_addr_reg(u16 reg, s16 _ix) 
 | 
						|
{
 | 
						|
	u32 ar = g_dsp.r.ar[reg];
 | 
						|
	u32 wr = g_dsp.r.wr[reg];
 | 
						|
	s32 ix = _ix;
 | 
						|
 | 
						|
	u32 mx = (wr | 1) << 1;
 | 
						|
	u32 nar = ar - ix;
 | 
						|
	u32 dar = (nar ^ ar ^ ~ix) & mx;
 | 
						|
 | 
						|
	if ((u32)ix > 0xFFFF8000) //(ix < 0 && ix != -0x8000)
 | 
						|
	{
 | 
						|
		if (dar > wr) //overflow
 | 
						|
			nar -= wr + 1;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if ((((nar + wr + 1) ^ nar) & dar) <= wr) //underflow or below min for mask
 | 
						|
			nar += wr + 1;
 | 
						|
	}
 | 
						|
	return nar;
 | 
						|
}
 | 
						|
 | 
						|
inline u16 dsp_increment_addr_reg(u16 reg) 
 | 
						|
{
 | 
						|
	u32 ar = g_dsp.r.ar[reg];
 | 
						|
	u32 wr = g_dsp.r.wr[reg];
 | 
						|
 | 
						|
	u32 nar = ar + 1;
 | 
						|
	
 | 
						|
	if ((nar ^ ar) > ((wr | 1) << 1))
 | 
						|
		nar -= wr + 1;
 | 
						|
	return nar;
 | 
						|
}
 | 
						|
 | 
						|
inline u16 dsp_decrement_addr_reg(u16 reg) 
 | 
						|
{
 | 
						|
	u32 ar = g_dsp.r.ar[reg];
 | 
						|
	u32 wr = g_dsp.r.wr[reg];
 | 
						|
	
 | 
						|
	u32 nar = ar + wr;
 | 
						|
 | 
						|
	if (((nar ^ ar) & ((wr | 1) << 1)) > wr)
 | 
						|
		nar -= wr + 1;
 | 
						|
	return nar;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// ---------------------------------------------------------------------------------------
 | 
						|
// --- 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 - DSP_REG_ST0);
 | 
						|
	case DSP_REG_AR0:
 | 
						|
	case DSP_REG_AR1:
 | 
						|
	case DSP_REG_AR2:
 | 
						|
	case DSP_REG_AR3:
 | 
						|
		return g_dsp.r.ar[reg - DSP_REG_AR0];
 | 
						|
	case DSP_REG_IX0:
 | 
						|
	case DSP_REG_IX1:
 | 
						|
	case DSP_REG_IX2:
 | 
						|
	case DSP_REG_IX3:
 | 
						|
		return g_dsp.r.ix[reg - DSP_REG_IX0];
 | 
						|
	case DSP_REG_WR0:
 | 
						|
	case DSP_REG_WR1:
 | 
						|
	case DSP_REG_WR2:
 | 
						|
	case DSP_REG_WR3:
 | 
						|
		return g_dsp.r.wr[reg - DSP_REG_WR0];
 | 
						|
	case DSP_REG_ACH0:
 | 
						|
	case DSP_REG_ACH1:
 | 
						|
		return g_dsp.r.ac[reg - DSP_REG_ACH0].h;
 | 
						|
	case DSP_REG_CR:     return g_dsp.r.cr;
 | 
						|
	case DSP_REG_SR:     return g_dsp.r.sr;
 | 
						|
	case DSP_REG_PRODL:  return g_dsp.r.prod.l;
 | 
						|
	case DSP_REG_PRODM:  return g_dsp.r.prod.m;
 | 
						|
	case DSP_REG_PRODH:  return g_dsp.r.prod.h;
 | 
						|
	case DSP_REG_PRODM2: return g_dsp.r.prod.m2;
 | 
						|
	case DSP_REG_AXL0:
 | 
						|
	case DSP_REG_AXL1:
 | 
						|
		return g_dsp.r.ax[reg - DSP_REG_AXL0].l;
 | 
						|
	case DSP_REG_AXH0:
 | 
						|
	case DSP_REG_AXH1:
 | 
						|
		return g_dsp.r.ax[reg - DSP_REG_AXH0].h;
 | 
						|
	case DSP_REG_ACL0:
 | 
						|
	case DSP_REG_ACL1:
 | 
						|
		return g_dsp.r.ac[reg - DSP_REG_ACL0].l;
 | 
						|
	case DSP_REG_ACM0:
 | 
						|
	case DSP_REG_ACM1:
 | 
						|
		return g_dsp.r.ac[reg - DSP_REG_ACM0].m;
 | 
						|
	default:
 | 
						|
		_assert_msg_(DSP_INT, 0, "cannot happen");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
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.ac[reg-DSP_REG_ACH0].h = (u16)(s16)(s8)(u8)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 - DSP_REG_ST0, val);
 | 
						|
		break;
 | 
						|
 | 
						|
	case DSP_REG_AR0:
 | 
						|
	case DSP_REG_AR1:
 | 
						|
	case DSP_REG_AR2:
 | 
						|
	case DSP_REG_AR3:
 | 
						|
		g_dsp.r.ar[reg - DSP_REG_AR0] = val;
 | 
						|
		break;
 | 
						|
	case DSP_REG_IX0:
 | 
						|
	case DSP_REG_IX1:
 | 
						|
	case DSP_REG_IX2:
 | 
						|
	case DSP_REG_IX3:
 | 
						|
		g_dsp.r.ix[reg - DSP_REG_IX0] = val;
 | 
						|
		break;
 | 
						|
	case DSP_REG_WR0:
 | 
						|
	case DSP_REG_WR1:
 | 
						|
	case DSP_REG_WR2:
 | 
						|
	case DSP_REG_WR3:
 | 
						|
		g_dsp.r.wr[reg - DSP_REG_WR0] = val;
 | 
						|
		break;
 | 
						|
	case DSP_REG_CR:     g_dsp.r.cr = val; break;
 | 
						|
	case DSP_REG_SR:     g_dsp.r.sr = val; break;
 | 
						|
	case DSP_REG_PRODL:  g_dsp.r.prod.l = val; break;
 | 
						|
	case DSP_REG_PRODM:  g_dsp.r.prod.m = val; break;
 | 
						|
	case DSP_REG_PRODH:  g_dsp.r.prod.h = val; break;
 | 
						|
	case DSP_REG_PRODM2: g_dsp.r.prod.m2 = val; break;
 | 
						|
	case DSP_REG_AXL0:
 | 
						|
	case DSP_REG_AXL1:
 | 
						|
		g_dsp.r.ax[reg - DSP_REG_AXL0].l = val;
 | 
						|
		break;
 | 
						|
	case DSP_REG_AXH0:
 | 
						|
	case DSP_REG_AXH1:
 | 
						|
		g_dsp.r.ax[reg - DSP_REG_AXH0].h = val;
 | 
						|
		break;
 | 
						|
	case DSP_REG_ACL0:
 | 
						|
	case DSP_REG_ACL1:
 | 
						|
		g_dsp.r.ac[reg - DSP_REG_ACL0].l = val;
 | 
						|
		break;
 | 
						|
	case DSP_REG_ACM0:
 | 
						|
	case DSP_REG_ACM1:
 | 
						|
		g_dsp.r.ac[reg - DSP_REG_ACM0].m = val;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
inline void dsp_conditional_extend_accum(int reg) 
 | 
						|
{
 | 
						|
	switch (reg) 
 | 
						|
	{
 | 
						|
	case DSP_REG_ACM0:
 | 
						|
	case DSP_REG_ACM1:
 | 
						|
		if (g_dsp.r.sr & SR_40_MODE_BIT)
 | 
						|
		{
 | 
						|
			// Sign extend into whole accum.
 | 
						|
			u16 val = g_dsp.r.ac[reg-DSP_REG_ACM0].m;
 | 
						|
			g_dsp.r.ac[reg - DSP_REG_ACM0].h = (val & 0x8000) ? 0xFFFF : 0x0000;
 | 
						|
			g_dsp.r.ac[reg - DSP_REG_ACM0].l = 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ---------------------------------------------------------------------------------------
 | 
						|
// --- prod
 | 
						|
// ---------------------------------------------------------------------------------------
 | 
						|
 | 
						|
inline s64 dsp_get_long_prod()
 | 
						|
{
 | 
						|
#if PROFILE
 | 
						|
	ProfilerAddDelta(g_dsp.err_pc, 1);
 | 
						|
#endif
 | 
						|
 | 
						|
	s64 val   = (s8)(u8)g_dsp.r.prod.h;
 | 
						|
	val <<= 32;
 | 
						|
	s64 low_prod  = g_dsp.r.prod.m;
 | 
						|
	low_prod += g_dsp.r.prod.m2;
 | 
						|
	low_prod <<= 16;
 | 
						|
	low_prod |= g_dsp.r.prod.l;
 | 
						|
	val += low_prod;
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
inline s64 dsp_get_long_prod_round_prodl()
 | 
						|
{
 | 
						|
	s64 prod = dsp_get_long_prod();
 | 
						|
 | 
						|
	if (prod & 0x10000)
 | 
						|
		prod = (prod + 0x8000) & ~0xffff;
 | 
						|
	else
 | 
						|
		prod = (prod + 0x7fff) & ~0xffff;
 | 
						|
 | 
						|
	return prod;
 | 
						|
}
 | 
						|
 | 
						|
// For accurate emulation, this is wrong - but the real prod registers behave
 | 
						|
// in completely bizarre ways. Not needed to emulate them correctly for game ucodes.
 | 
						|
inline void dsp_set_long_prod(s64 val)
 | 
						|
{
 | 
						|
#if PROFILE
 | 
						|
	ProfilerAddDelta(g_dsp.err_pc, 1);
 | 
						|
#endif
 | 
						|
 | 
						|
	g_dsp.r.prod.l = (u16)val;
 | 
						|
	val >>= 16;
 | 
						|
	g_dsp.r.prod.m = (u16)val;
 | 
						|
	val >>= 16;
 | 
						|
	g_dsp.r.prod.h = /*(s16)(s8)*/(u8)val;//todo: check expansion
 | 
						|
	g_dsp.r.prod.m2 = 0;
 | 
						|
}
 | 
						|
 | 
						|
// ---------------------------------------------------------------------------------------
 | 
						|
// --- ACC - main accumulators (40-bit)
 | 
						|
// ---------------------------------------------------------------------------------------
 | 
						|
 | 
						|
inline s64 dsp_get_long_acc(int reg)
 | 
						|
{
 | 
						|
#if PROFILE
 | 
						|
	ProfilerAddDelta(g_dsp.err_pc, 1);
 | 
						|
#endif
 | 
						|
 | 
						|
	s64 high = (s64)(s8)g_dsp.r.ac[reg].h << 32;
 | 
						|
	u32 mid_low = ((u32)g_dsp.r.ac[reg].m << 16) | g_dsp.r.ac[reg].l;
 | 
						|
	return high | mid_low;
 | 
						|
}
 | 
						|
 | 
						|
inline void dsp_set_long_acc(int _reg, s64 val)
 | 
						|
{
 | 
						|
#if PROFILE
 | 
						|
	ProfilerAddDelta(g_dsp.err_pc, 1);
 | 
						|
#endif
 | 
						|
 | 
						|
	g_dsp.r.ac[_reg].l = (u16)val;
 | 
						|
	val >>= 16;
 | 
						|
	g_dsp.r.ac[_reg].m = (u16)val;
 | 
						|
	val >>= 16;
 | 
						|
	g_dsp.r.ac[_reg].h = (u16)(s16)(s8)(u8)val;
 | 
						|
}
 | 
						|
 | 
						|
inline s64 dsp_convert_long_acc(s64 val) // s64 -> s40
 | 
						|
{
 | 
						|
	return ((s64)(s8)(val >> 32))<<32 | (u32)val;
 | 
						|
}
 | 
						|
 | 
						|
inline s64 dsp_round_long_acc(s64 val)
 | 
						|
{
 | 
						|
	if (val & 0x10000)
 | 
						|
		val = (val + 0x8000) & ~0xffff;
 | 
						|
	else
 | 
						|
		val = (val + 0x7fff) & ~0xffff;
 | 
						|
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
inline s16 dsp_get_acc_l(int _reg)
 | 
						|
{
 | 
						|
	return g_dsp.r.ac[_reg].l;
 | 
						|
}
 | 
						|
 | 
						|
inline s16 dsp_get_acc_m(int _reg)
 | 
						|
{
 | 
						|
	return g_dsp.r.ac[_reg].m;
 | 
						|
}
 | 
						|
 | 
						|
inline s16 dsp_get_acc_h(int _reg)
 | 
						|
{
 | 
						|
	return g_dsp.r.ac[_reg].h;
 | 
						|
}
 | 
						|
 | 
						|
// ---------------------------------------------------------------------------------------
 | 
						|
// --- AX - extra accumulators (32-bit)
 | 
						|
// ---------------------------------------------------------------------------------------
 | 
						|
 | 
						|
inline s32 dsp_get_long_acx(int _reg)
 | 
						|
{
 | 
						|
#if PROFILE
 | 
						|
	ProfilerAddDelta(g_dsp.err_pc, 1);
 | 
						|
#endif
 | 
						|
 | 
						|
	return ((u32)g_dsp.r.ax[_reg].h << 16) | g_dsp.r.ax[_reg].l;
 | 
						|
}
 | 
						|
 | 
						|
inline s16 dsp_get_ax_l(int _reg)
 | 
						|
{
 | 
						|
	return (s16)g_dsp.r.ax[_reg].l;
 | 
						|
}
 | 
						|
 | 
						|
inline s16 dsp_get_ax_h(int _reg)
 | 
						|
{
 | 
						|
	return (s16)g_dsp.r.ax[_reg].h;
 | 
						|
}
 | 
						|
 | 
						|
#endif
 |