From e89af68f4de955ab557165f532e707e1ef923d25 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Sat, 2 May 2009 16:15:52 +0000 Subject: [PATCH] DSPLLE: Split the huge DSPInterpreter.cpp into separate files for the different categories of ops. Minor cleanups. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3134 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/DSPCore/DSPCore.vcproj | 28 +- Source/Core/DSPCore/Src/DSPInterpreter.cpp | 1802 ----------------- Source/Core/DSPCore/Src/DSPTables.cpp | 2 +- Source/Core/DSPCore/Src/DspIntArithmetic.cpp | 695 +++++++ Source/Core/DSPCore/Src/DspIntBranch.cpp | 250 +++ Source/Core/DSPCore/Src/DspIntLoadStore.cpp | 264 +++ Source/Core/DSPCore/Src/DspIntMisc.cpp | 200 ++ Source/Core/DSPCore/Src/DspIntMultiplier.cpp | 486 +++++ Source/Core/DSPCore/Src/SConscript | 6 +- Source/Core/DSPCore/Src/gdsp_aram.cpp | 1 - .../Core/DSPCore/Src/gdsp_condition_codes.cpp | 2 +- Source/Core/DSPCore/Src/gdsp_ext_op.cpp | 43 +- Source/Core/DSPCore/Src/gdsp_interface.cpp | 36 +- Source/Core/DSPCore/Src/gdsp_opcodes_helper.h | 62 +- .../Plugin_DSP_HLE/Src/UCodes/UCode_Jac.cpp | 8 +- .../Plugin_DSP_HLE/Src/UCodes/UCodes.cpp | 18 +- 16 files changed, 1993 insertions(+), 1910 deletions(-) delete mode 100644 Source/Core/DSPCore/Src/DSPInterpreter.cpp create mode 100644 Source/Core/DSPCore/Src/DspIntArithmetic.cpp create mode 100644 Source/Core/DSPCore/Src/DspIntBranch.cpp create mode 100644 Source/Core/DSPCore/Src/DspIntLoadStore.cpp create mode 100644 Source/Core/DSPCore/Src/DspIntMisc.cpp create mode 100644 Source/Core/DSPCore/Src/DspIntMultiplier.cpp diff --git a/Source/Core/DSPCore/DSPCore.vcproj b/Source/Core/DSPCore/DSPCore.vcproj index 73ae94b8c6..268d721ab2 100644 --- a/Source/Core/DSPCore/DSPCore.vcproj +++ b/Source/Core/DSPCore/DSPCore.vcproj @@ -402,6 +402,30 @@ + + + + + + + + + + + + @@ -446,10 +470,6 @@ RelativePath=".\Src\DSPHost.h" > - - diff --git a/Source/Core/DSPCore/Src/DSPInterpreter.cpp b/Source/Core/DSPCore/Src/DSPInterpreter.cpp deleted file mode 100644 index 2886f09ccb..0000000000 --- a/Source/Core/DSPCore/Src/DSPInterpreter.cpp +++ /dev/null @@ -1,1802 +0,0 @@ -// Copyright (C) 2003-2009 Dolphin Project. - -// 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, version 2.0. - -// 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 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -// Additional copyrights go to Duddie and Tratax (c) 2004 - -#include "DSPInterpreter.h" - -#include "Common.h" -#include "gdsp_memory.h" -#include "gdsp_interpreter.h" -#include "gdsp_condition_codes.h" -#include "gdsp_registers.h" -#include "gdsp_opcodes_helper.h" -#include "gdsp_ext_op.h" - -namespace DSPInterpreter { - -void unknown(const UDSPInstruction& opc) -{ - //_assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception"); - ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc.hex, g_dsp.pc); -} - -// Generic call implementation -// CALLcc addressA -// 0000 0010 1011 cccc -// aaaa aaaa aaaa aaaa -// Call function if condition cc has been met. Push program counter of -// instruction following "call" to $st0. Set program counter to address -// represented by value that follows this "call" instruction. -void call(const UDSPInstruction& opc) -{ - u16 dest = dsp_fetch_code(); - - if (CheckCondition(opc.hex & 0xf)) - { - dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); - g_dsp.pc = dest; - } -} - -// Generic callr implementation -// CALLRcc $R -// 0001 0111 rrr1 cccc -// Call functionif condition cc has been met.Push program counter of -// instruction following "call" tocall stack $st0. Set program counter to -// register $R. -void callr(const UDSPInstruction& opc) -{ - u16 addr; - u8 reg; - - if (CheckCondition(opc.hex & 0xf)) - { - reg = (opc.hex >> 5) & 0x7; - addr = dsp_op_read_reg(reg); - dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); - g_dsp.pc = addr; - } -} - -// Generic if implementation -// IFcc -// 0000 0010 0111 cccc -// Execute following opcode if the condition has been met. -void ifcc(const UDSPInstruction& opc) -{ - if (!CheckCondition(opc.hex & 0xf)) - { - // skip the next opcode - we have to lookup its size. - g_dsp.pc += opSize[dsp_peek_code()]; - } -} - -// Generic jmp implementation -// Jcc addressA -// 0000 0010 1001 cccc -// aaaa aaaa aaaa aaaa -// Jump to addressA if condition cc has been met. Set program counter to -// address represented by value that follows this "jmp" instruction. -void jcc(const UDSPInstruction& opc) -{ - u16 dest = dsp_fetch_code(); - - if (CheckCondition(opc.hex & 0xf)) - { - g_dsp.pc = dest; - } -} - -// Generic jmpr implementation -// JMPcc $R -// 0001 0111 rrr0 cccc -// Jump to address; set program counter to a value from register $R. -void jmprcc(const UDSPInstruction& opc) -{ - if (CheckCondition(opc.hex & 0xf)) - { - u8 reg = (opc.hex >> 5) & 0x7; - g_dsp.pc = dsp_op_read_reg(reg); - } -} - -// Generic ret implementation -// RETcc -// 0000 0010 1101 cccc -// Return from subroutine if condition cc has been met. Pops stored PC -// from call stack $st0 and sets $pc to this location. -void ret(const UDSPInstruction& opc) -{ - if (CheckCondition(opc.hex & 0xf)) - { - g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); - } -} - -// RTI -// 0000 0010 1111 1111 -// Return from exception. Pops stored status register $sr from data stack -// $st1 and program counter PC from call stack $st0 and sets $pc to this -// location. -// FIXME: is it also conditional? unknown opcodes 0x02fx -void rti(const UDSPInstruction& opc) -{ - g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D); - g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); - - g_dsp.exception_in_progress_hack = false; -} - -// HALT -// 0000 0000 0020 0001 -// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR. -void halt(const UDSPInstruction& opc) -{ - g_dsp.cr |= 0x4; - g_dsp.pc--; -} - - -// LOOP handling: Loop stack is used to control execution of repeated blocks of -// instructions. Whenever there is value on stack $st2 and current PC is equal -// value at $st2, then value at stack $st3 is decremented. If value is not zero -// then PC is modified with calue from call stack $st0. Otherwise values from -// callstack $st0 and both loop stacks $st2 and $st3 are poped and execution -// continues at next opcode. - - -// LOOP $R -// 0000 0000 010r rrrr -// Repeatedly execute following opcode until counter specified by value -// from register $R reaches zero. Each execution decrement counter. Register -// $R remains unchanged. If register $R is set to zero at the beginning of loop -// then looped instruction will not get executed. -// Actually, this instruction simply prepares the loop stacks for the above. -// The looping hardware takes care of the rest. -void loop(const UDSPInstruction& opc) -{ - u16 reg = opc.hex & 0x1f; - u16 cnt = g_dsp.r[reg]; - u16 loop_pc = g_dsp.pc; - - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } -} - -// LOOPI #I -// 0001 0000 iiii iiii -// Repeatedly execute following opcode until counter specified by -// immediate value I reaches zero. Each execution decrement counter. If -// immediate value I is set to zero at the beginning of loop then looped -// instruction will not get executed. -// Actually, this instruction simply prepares the loop stacks for the above. -// The looping hardware takes care of the rest. -void loopi(const UDSPInstruction& opc) -{ - u16 cnt = opc.hex & 0xff; - u16 loop_pc = g_dsp.pc; - - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } -} - - -// BLOOP $R, addrA -// 0000 0000 011r rrrr -// aaaa aaaa aaaa aaaa -// Repeatedly execute block of code starting at following opcode until -// counter specified by value from register $R reaches zero. Block ends at -// specified address addrA inclusive, ie. opcode at addrA is the last opcode -// included in loop. Counter is pushed on loop stack $st3, end of block address -// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0. -// Up to 4 nested loops is allowed. -void bloop(const UDSPInstruction& opc) -{ - u16 reg = opc.hex & 0x1f; - u16 cnt = g_dsp.r[reg]; - u16 loop_pc = dsp_fetch_code(); - - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } - else - { - g_dsp.pc = loop_pc; - g_dsp.pc += opSize[dsp_peek_code()]; - } -} - -// BLOOPI #I, addrA -// 0001 0001 iiii iiii -// aaaa aaaa aaaa aaaa -// Repeatedly execute block of code starting at following opcode until -// counter specified by immediate value I reaches zero. Block ends at specified -// address addrA inclusive, ie. opcode at addrA is the last opcode included in -// loop. Counter is pushed on loop stack $st3, end of block address is pushed -// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4 -// nested loops is allowed. -void bloopi(const UDSPInstruction& opc) -{ - u16 cnt = opc.hex & 0xff; - u16 loop_pc = dsp_fetch_code(); - - if (cnt) - { - dsp_reg_store_stack(0, g_dsp.pc); - dsp_reg_store_stack(2, loop_pc); - dsp_reg_store_stack(3, cnt); - } - else - { - g_dsp.pc = loop_pc; - g_dsp.pc += opSize[dsp_peek_code()]; - } -} - -//------------------------------------------------------------- - -// MRR $D, $S -// 0001 11dd ddds ssss -// Move value from register $S to register $D. -// FIXME: Perform additional operation depending on destination register. -void mrr(const UDSPInstruction& opc) -{ - u8 sreg = opc.hex & 0x1f; - u8 dreg = (opc.hex >> 5) & 0x1f; - - u16 val = dsp_op_read_reg(sreg); - dsp_op_write_reg(dreg, val); -} - -// LRR $D, @$S -// 0001 1000 0ssd dddd -// Move value from data memory pointed by addressing register $S to register $D. -// FIXME: Perform additional operation depending on destination register. -void lrr(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 5) & 0x3; - u8 dreg = opc.hex & 0x1f; - - u16 val = dsp_dmem_read(g_dsp.r[sreg]); - dsp_op_write_reg(dreg, val); -} - -// LRRD $D, @$S -// 0001 1000 1ssd dddd -// Move value from data memory pointed by addressing register $S toregister $D. -// Decrement register $S. -// FIXME: Perform additional operation depending on destination register. -void lrrd(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 5) & 0x3; - u8 dreg = opc.hex & 0x1f; - - u16 val = dsp_dmem_read(g_dsp.r[sreg]); - dsp_op_write_reg(dreg, val); - dsp_decrement_addr_reg(sreg); -} - -// LRRI $D, @$S -// 0001 1001 0ssd dddd -// Move value from data memory pointed by addressing register $S to register $D. -// Increment register $S. -// FIXME: Perform additional operation depending on destination register. -void lrri(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 5) & 0x3; - u8 dreg = opc.hex & 0x1f; - - u16 val = dsp_dmem_read(g_dsp.r[sreg]); - dsp_op_write_reg(dreg, val); - dsp_increment_addr_reg(sreg); -} - -// LRRN $D, @$S -// 0001 1001 1ssd dddd -// Move value from data memory pointed by addressing register $S to register $D. -// Add indexing register $(0x4+S) to register $S. -// FIXME: Perform additional operation depending on destination register. -void lrrn(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 5) & 0x3; - u8 dreg = opc.hex & 0x1f; - - u16 val = dsp_dmem_read(g_dsp.r[sreg]); - dsp_op_write_reg(dreg, val); - g_dsp.r[sreg] += g_dsp.r[DSP_REG_IX0 + sreg]; -} - -// SRR @$D, $S -// 0001 1010 0dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. -// FIXME: Perform additional operation depending on source register. -void srr(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 5) & 0x3; - u8 sreg = opc.hex & 0x1f; - - u16 val = dsp_op_read_reg(sreg); - dsp_dmem_write(g_dsp.r[dreg], val); -} - -// SRRD @$D, $S -// 0001 1010 1dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. Decrement register $D. -// FIXME: Perform additional operation depending on source register. -void srrd(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 5) & 0x3; - u8 sreg = opc.hex & 0x1f; - - u16 val = dsp_op_read_reg(sreg); - dsp_dmem_write(g_dsp.r[dreg], val); - dsp_decrement_addr_reg(dreg); -} - -// SRRI @$D, $S -// 0001 1011 0dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. Increment register $D. -// FIXME: Perform additional operation depending on source register. -void srri(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 5) & 0x3; - u8 sreg = opc.hex & 0x1f; - - u16 val = dsp_op_read_reg(sreg); - dsp_dmem_write(g_dsp.r[dreg], val); - dsp_increment_addr_reg(dreg); -} - -// SRRN @$D, $S -// 0001 1011 1dds ssss -// Store value from source register $S to a memory location pointed by -// addressing register $D. Add DSP_REG_IX0 register to register $D. -// FIXME: Perform additional operation depending on source register. -void srrn(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 5) & 0x3; - u8 sreg = opc.hex & 0x1f; - - u16 val = dsp_op_read_reg(sreg); - dsp_dmem_write(g_dsp.r[dreg], val); - g_dsp.r[dreg] += g_dsp.r[DSP_REG_IX0 + dreg]; -} - -// ILRR $acD.m, @$arS -// 0000 001d 0001 00ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. -void ilrr(const UDSPInstruction& opc) -{ - u16 reg = opc.hex & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); - - g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); -} - -// ILRRD $acD.m, @$arS -// 0000 001d 0001 01ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. Decrement addressing register $arS. -void ilrrd(const UDSPInstruction& opc) -{ - u16 reg = opc.hex & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); - - g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); - - dsp_decrement_addr_reg(reg); -} - -// ILRRI $acD.m, @$S -// 0000 001d 0001 10ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. Increment addressing register $arS. -void ilrri(const UDSPInstruction& opc) -{ - u16 reg = opc.hex & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); - - g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); - - dsp_increment_addr_reg(reg); -} - -// ILRRN $acD.m, @$arS -// 0000 001d 0001 11ss -// Move value from instruction memory pointed by addressing register -// $arS to mid accumulator register $acD.m. Add corresponding indexing -// register $ixS to addressing register $arS. -void ilrrn(const UDSPInstruction& opc) -{ - u16 reg = opc.hex & 0x3; - u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); - - g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); - - g_dsp.r[reg] += g_dsp.r[DSP_REG_IX0 + reg]; -} - -// LRI $D, #I -// 0000 0000 100d dddd -// iiii iiii iiii iiii -// Load immediate value I to register $D. -// FIXME: Perform additional operation depending on destination register. - -// DSPSpy discovery: This, and possibly other instructions that load a register, -// has a different behaviour in S16 mode if loaded to AC0.M: The value gets sign extended -// to the whole accumulator! This does not happen in s40 mode. -void lri(const UDSPInstruction& opc) -{ - u8 reg = opc.hex & DSP_REG_MASK; - u16 imm = dsp_fetch_code(); - dsp_op_write_reg(reg, imm); - dsp_conditional_extend_accum(reg); -} - -// LRIS $(0x18+D), #I -// 0000 1ddd iiii iiii -// Load immediate value I (8-bit sign extended) to accumulator register. -// FIXME: Perform additional operation depending on destination register. -void lris(const UDSPInstruction& opc) -{ - u8 reg = ((opc.hex >> 8) & 0x7) + DSP_REG_AXL0; - u16 imm = (s8)opc.hex; - dsp_op_write_reg(reg, imm); - dsp_conditional_extend_accum(reg); -} - -// LR $D, @M -// 0000 0000 110d dddd -// mmmm mmmm mmmm mmmm -// Move value from data memory pointed by address M to register $D. -// FIXME: Perform additional operation depending on destination register. -void lr(const UDSPInstruction& opc) -{ - u8 reg = opc.hex & DSP_REG_MASK; - u16 addr = dsp_fetch_code(); - u16 val = dsp_dmem_read(addr); - dsp_op_write_reg(reg, val); - dsp_conditional_extend_accum(reg); -} - -// SR @M, $S -// 0000 0000 111s ssss -// mmmm mmmm mmmm mmmm -// Store value from register $S to a memory pointed by address M. -// FIXME: Perform additional operation depending on destination register. -void sr(const UDSPInstruction& opc) -{ - u8 reg = opc.hex & DSP_REG_MASK; - u16 addr = dsp_fetch_code(); - u16 val = dsp_op_read_reg(reg); - dsp_dmem_write(addr, val); -} - -// SI @M, #I -// 0001 0110 mmmm mmmm -// iiii iiii iiii iiii -// Store 16-bit immediate value I to a memory location pointed by address -// M (M is 8-bit value sign extended). -void si(const UDSPInstruction& opc) -{ - u16 addr = (s8)opc.hex; - u16 imm = dsp_fetch_code(); - dsp_dmem_write(addr, imm); -} - -// TSTAXH $axR.h -// 1000 011r xxxx xxxx -// Test high part of secondary accumulator $axR.h. -void tstaxh(const UDSPInstruction& opc) -{ - u8 reg = (opc.hex >> 8) & 0x1; - s16 val = dsp_get_ax_h(reg); - - Update_SR_Register16(val); -} - -// TSTAXL $acR -// 1000 r001 xxxx xxxx -// r specifies one of the main accumulators. -// Definitely not a test instruction - it changes the accums. -// Not affected by m0/m2. Not affected by s16/s40. -void tstaxl(const UDSPInstruction& opc) -{ - // This is probably all wrong. - //u8 reg = (opc.hex >> 8) & 0x1; - //s16 val = dsp_get_ax_l(reg); - //Update_SR_Register16(val); -} - -// CLR $acR -// 1000 r001 xxxx xxxx -// Clears accumulator $acR -void clr(const UDSPInstruction& opc) -{ - u8 reg = (opc.hex >> 11) & 0x1; - - dsp_set_long_acc(reg, 0); - - Update_SR_Register64((s64)0); // really? -} - -// CLRL $acR.l -// 1111 110r xxxx xxxx -// Clears $acR.l - low 16 bits of accumulator $acR. -void clrl(const UDSPInstruction& opc) -{ - u16 reg = DSP_REG_ACL0 + ((opc.hex >> 11) & 0x1); - g_dsp.r[reg] = 0; - - // Should this be 64bit? - // nakee: it says the whole reg in duddie's doc sounds weird - Update_SR_Register64((s64)reg); -} - -// CLRP -// 1000 0100 xxxx xxxx -// Clears product register $prod. -void clrp(const UDSPInstruction& opc) -{ - // Magic numbers taken from duddie's doc - g_dsp.r[0x14] = 0x0000; - g_dsp.r[0x15] = 0xfff0; - g_dsp.r[0x16] = 0x00ff; - g_dsp.r[0x17] = 0x0010; -} - -// MULC $acS.m, $axT.h -// 110s t000 xxxx xxxx -// Multiply mid part of accumulator register $acS.m by high part $axS.h of -// secondary accumulator $axS (treat them both as signed). -void mulc(const UDSPInstruction& opc) -{ - // math new prod - u8 sreg = (opc.hex >> 11) & 0x1; - u8 treg = (opc.hex >> 12) & 0x1; - - s64 prod = dsp_get_acc_m(sreg) * dsp_get_ax_h(treg) * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); -} - -// MULCMVZ $acS.m, $axT.h, $acR -// 110s t01r xxxx xxxx -// (fixed possible bug in duddie's description, s->t) -// Multiply mid part of accumulator register $acS.m by high part $axT.h of -// secondary accumulator $axT (treat them both as signed). Move product -// register before multiplication to accumulator $acR, set low part of -// accumulator $acR.l to zero. -void mulcmvz(const UDSPInstruction& opc) -{ - s64 TempProd = dsp_get_long_prod(); - - // update prod - u8 sreg = (opc.hex >> 12) & 0x1; - u8 treg = (opc.hex >> 11) & 0x1; - s64 Prod = (s64)dsp_get_acc_m(sreg) * (s64)dsp_get_ax_h(treg) * GetMultiplyModifier(); - dsp_set_long_prod(Prod); - - // update acc - u8 rreg = (opc.hex >> 8) & 0x1; - s64 acc = TempProd & ~0xffff; // clear lower 4 bytes - dsp_set_long_acc(rreg, acc); - - Update_SR_Register64(acc); -} - -// MULCMV $acS.m, $axT.h, $acR -// 110s t11r xxxx xxxx -// Multiply mid part of accumulator register $acS.m by high part $axT.h of -// secondary accumulator $axT (treat them both as signed). Move product -// register before multiplication to accumulator $acR. -// possible mistake in duddie's doc axT.h rather than axS.h -void mulcmv(const UDSPInstruction& opc) -{ - s64 tempProd = dsp_get_long_prod(); - - // update prod - u8 sreg = (opc.hex >> 12) & 0x1; - u8 treg = (opc.hex >> 11) & 0x1; - s64 prod = (s64)dsp_get_acc_m(sreg) * (s64)dsp_get_ax_h(treg) * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - // update acc - u8 rreg = (opc.hex >> 8) & 0x1; - dsp_set_long_acc(rreg, tempProd); - - Update_SR_Register64(tempProd); -} - -// CMPAR $acS axR.h -// 1100 0001 xxxx xxxx -// Compares accumulator $acS with accumulator axR.h. -// Not described by Duddie's doc - at least not as a separate instruction. -void cmpar(const UDSPInstruction& opc) -{ - u8 rreg = ((opc.hex >> 12) & 0x1) + DSP_REG_AXH0; - u8 sreg = (opc.hex >> 11) & 0x1; - - // we compare - s64 rr = (s16)g_dsp.r[rreg]; - rr <<= 16; - - s64 sr = dsp_get_long_acc(sreg); - - Update_SR_Register64(sr - rr); -} - -// CMP -// 1000 0010 xxxx xxxx -// Compares accumulator $ac0 with accumulator $ac1. -void cmp(const UDSPInstruction& opc) -{ - s64 acc0 = dsp_get_long_acc(0); - s64 acc1 = dsp_get_long_acc(1); - - Update_SR_Register64(acc0 - acc1); -} - -// TST -// 1011 r001 xxxx xxxx -// Test accumulator %acR. -void tst(const UDSPInstruction& opc) -{ - s8 reg = (opc.hex >> 11) & 0x1; - s64 acc = dsp_get_long_acc(reg); - - Update_SR_Register64(acc); -} - -// ADDAXL $acD, $axS.l -// 0111 00sd xxxx xxxx -// Adds secondary accumulator $axS.l to accumulator register $acD. -void addaxl(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 9) & 0x1; - u8 dreg = (opc.hex >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(dreg); - s64 acx = dsp_get_ax_l(sreg); - - acc += acx; - - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// ADDARN $arD, $ixS -// 0000 0000 0001 ssdd -// Adds indexing register $ixS to an addressing register $arD. -void addarn(const UDSPInstruction& opc) -{ - u8 dreg = opc.hex & 0x3; - u8 sreg = (opc.hex >> 2) & 0x3; - - g_dsp.r[dreg] += (s16)g_dsp.r[DSP_REG_IX0 + sreg]; -} - -// MULCAC $acS.m, $axT.h, $acR -// 110s t10r xxxx xxxx -// Multiply mid part of accumulator register $acS.m by high part $axS.h of -// secondary accumulator $axS (treat them both as signed). Add product -// register before multiplication to accumulator $acR. -void mulcac(const UDSPInstruction& opc) -{ - s64 TempProd = dsp_get_long_prod(); - - // update prod - u8 sreg = (opc.hex >> 12) & 0x1; - u8 treg = (opc.hex >> 11) & 0x1; - s64 Prod = (s64)dsp_get_acc_m(sreg) * (s64)dsp_get_ax_h(treg) * GetMultiplyModifier(); - dsp_set_long_prod(Prod); - - // update acc - u8 rreg = (opc.hex >> 8) & 0x1; - s64 acc = TempProd + dsp_get_long_acc(rreg); - dsp_set_long_acc(rreg, acc); - - Update_SR_Register64(acc); -} - -// MOVR $acD, $axS.R -// 0110 0srd xxxx xxxx -// Moves register $axS.R (sign extended) to middle accumulator $acD.hm. -// Sets $acD.l to 0. -void movr(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; - - s64 acc = (s16)g_dsp.r[sreg]; - acc <<= 16; - acc &= ~0xffff; - - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// MOVAX $acD, $axS -// 0110 10sd xxxx xxxx -// Moves secondary accumulator $axS to accumulator $axD. -void movax(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - u8 sreg = (opc.hex >> 9) & 0x1; - - s64 acx = dsp_get_long_acx(sreg); - dsp_set_long_acc(dreg, acx); - - Update_SR_Register64(acx); -} - -// XORR $acD.m, $axS.h -// 0011 00sd xxxx xxxx -// Logic XOR (exclusive or) middle part of accumulator $acD.m with -// high part of secondary accumulator $axS.h. -void xorr(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 9) & 0x1; - u8 dreg = (opc.hex >> 8) & 0x1; - - g_dsp.r[0x1e + dreg] ^= g_dsp.r[0x1a + sreg]; - - s64 acc = dsp_get_long_acc(dreg); - - Update_SR_Register64(acc); -} - -// ANDR $acD.m, $axS.h -// 0011 01sd xxxx xxxx -// Logic AND middle part of accumulator $acD.m with high part of -// secondary accumulator $axS.h. -void andr(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 9) & 0x1; - u8 dreg = (opc.hex >> 8) & 0x1; - - g_dsp.r[0x1e + dreg] &= g_dsp.r[0x1a + sreg]; - - s64 acc = dsp_get_long_acc(dreg); - - Update_SR_Register64(acc); -} - -// ORR $acD.m, $axS.h -// 0011 10sd xxxx xxxx -// Logic OR middle part of accumulator $acD.m with high part of -// secondary accumulator $axS.h. -void orr(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 9) & 0x1; - u8 dreg = (opc.hex >> 8) & 0x1; - - g_dsp.r[0x1e + dreg] |= g_dsp.r[0x1a + sreg]; - - s64 acc = dsp_get_long_acc(dreg); - - Update_SR_Register64(acc); -} - -// ANDC $acD.m, $ac(1-D).m -// 0011 110d xxxx xxxx -// Logic AND middle part of accumulator $acD.m with middle part of -// accumulator $ax(1-D).m.s -void andc(const UDSPInstruction& opc) -{ - u8 D = (opc.hex >> 8) & 0x1; - - u16 ac1 = dsp_get_acc_m(D); - u16 ac2 = dsp_get_acc_m(1 - D); - - dsp_set_long_acc(D, ac1 & ac2); - - Update_SR_Register64(dsp_get_long_acc(D)); -} - -// ORC $acD.m, $ac(1-D).m -// 0011 111d xxxx xxxx -// Logic OR middle part of accumulator $acD.m with middle part of -// accumulator $ax(1-D).m. -void orc(const UDSPInstruction& opc) -{ - u8 D = (opc.hex >> 8) & 0x1; - - u16 ac1 = dsp_get_acc_m(D); - u16 ac2 = dsp_get_acc_m(1 - D); - - dsp_set_long_acc(D, ac1 | ac2); - - Update_SR_Register64(dsp_get_long_acc(D)); -} - -void orf(const UDSPInstruction& opc) -{ - ERROR_LOG(DSPLLE, "orf not implemented"); -} - - -//------------------------------------------------------------- - -// NX -// 1000 -000 xxxx xxxx -// No operation, but can be extended with extended opcode. -void nx(const UDSPInstruction& opc) -{ - // This opcode is supposed to do nothing - it's used if you want to use - // an opcode extension but not do anything. At least according to duddie. -} - - -// Hermes switched andf and andcf, so check to make sure they are still correct -// ANDCF $acD.m, #I -// 0000 001r 1100 0000 -// iiii iiii iiii iiii -// Set logic zero (LZ) flag in status register $sr if result of logic AND of -// accumulator mid part $acD.m with immediate value I is equal I. -void andcf(const UDSPInstruction& opc) -{ - u8 reg = (opc.hex >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - u16 val = dsp_get_acc_m(reg); - - Update_SR_LZ(((val & imm) == imm)?0:1); -} - -// Hermes switched andf and andcf, so check to make sure they are still correct - -// ANDF $acD.m, #I -// 0000 001r 1010 0000 -// iiii iiii iiii iiii -// Set logic zero (LZ) flag in status register $sr if result of logical AND -// operation of accumulator mid part $acD.m with immediate value I is equal -// immediate value 0. -void andf(const UDSPInstruction& opc) -{ - u8 reg; - u16 imm; - u16 val; - - reg = 0x1e + ((opc.hex >> 8) & 0x1); - imm = dsp_fetch_code(); - val = g_dsp.r[reg]; - - Update_SR_LZ(((val & imm) == 0)?0:1); -} - -// CMPI $amD, #I -// 0000 001r 1000 0000 -// iiii iiii iiii iiii -// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. -// Although flags are being set regarding whole accumulator register. -void cmpi(const UDSPInstruction& opc) -{ - int reg = (opc.hex >> 8) & 0x1; - - // Immediate is considered to be at M level in the 40-bit accumulator. - s64 imm = (s64)(s16)dsp_fetch_code() << 16; - s64 val = dsp_get_long_acc(reg); - s64 res = val - imm; - - Update_SR_Register64(res); -} - -// XORI $acD.m, #I -// 0000 001r 0010 0000 -// iiii iiii iiii iiii -// Logic exclusive or (XOR) of accumulator mid part $acD.m with -// immediate value I. -void xori(const UDSPInstruction& opc) -{ - u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); - u16 imm = dsp_fetch_code(); - g_dsp.r[reg] ^= imm; - - Update_SR_Register16((s16)g_dsp.r[reg]); -} - -// ANDI $acD.m, #I -// 0000 001r 0100 0000 -// iiii iiii iiii iiii -// Logic AND of accumulator mid part $acD.m with immediate value I. -void andi(const UDSPInstruction& opc) -{ - u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); - u16 imm = dsp_fetch_code(); - g_dsp.r[reg] &= imm; - - Update_SR_Register16((s16)g_dsp.r[reg]); -} - - -// F|RES: i am not sure if this shouldnt be the whole ACC -// ORI $acD.m, #I -// 0000 001r 0110 0000 -// iiii iiii iiii iiii -// Logic OR of accumulator mid part $acD.m with immediate value I. -void ori(const UDSPInstruction& opc) -{ - u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); - u16 imm = dsp_fetch_code(); - g_dsp.r[reg] |= imm; - - Update_SR_Register16((s16)g_dsp.r[reg]); -} - -//------------------------------------------------------------- - - -// ADD $acD, $ac(1-D) -// 0100 110d xxxx xxxx -// Adds accumulator $ac(1-D) to accumulator register $acD. -void add(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - s64 acc0 = dsp_get_long_acc(0); - s64 acc1 = dsp_get_long_acc(1); - - s64 res = acc0 + acc1; - - dsp_set_long_acc(areg, res); - - Update_SR_Register64(res); -} - -//------------------------------------------------------------- - -// ADDP $acD -// 0100 111d xxxx xxxx -// Adds product register to accumulator register. -void addp(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - s64 acc = dsp_get_long_acc(dreg); - acc += dsp_get_long_prod(); - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// SUBP $acD -// 0101 111d xxxx xxxx -// Subtracts product register from accumulator register. -void subp(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - s64 acc = dsp_get_long_acc(dreg); - acc -= dsp_get_long_prod(); - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// CMPIS $acD, #I -// 0000 011d iiii iiii -// Compares accumulator with short immediate. Comaprison is executed -// by subtracting short immediate (8bit sign extended) from mid accumulator -// $acD.hm and computing flags based on whole accumulator $acD. -void cmpis(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(areg); - s64 val = (s8)opc.hex; - val <<= 16; - - s64 res = acc - val; - - Update_SR_Register64(res); -} - -// ADDPAXZ $acD, $axS -// 1111 10sd xxxx xxxx -// Adds secondary accumulator $axS to product register and stores result -// in accumulator register. Low 16-bits of $acD ($acD.l) are set to 0. -void addpaxz(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - u8 sreg = (opc.hex >> 9) & 0x1; - - s64 prod = dsp_get_long_prod() & ~0x0ffff; - s64 ax_h = dsp_get_long_acx(sreg); - s64 acc = (prod + ax_h) & ~0x0ffff; - - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// MOVPZ $acD -// 1111 111d xxxx xxxx -// Moves multiply product from $prod register to accumulator $acD -// register and sets $acD.l to 0 -void movpz(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x01; - - // overwrite acc and clear low part - s64 prod = dsp_get_long_prod(); - s64 acc = prod & ~0xffff; - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// DECM $acsD -// 0111 100d xxxx xxxx -// Decrement 24-bit mid-accumulator $acsD. -void decm(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x01; - - s64 sub = 0x10000; - s64 acc = dsp_get_long_acc(dreg); - acc -= sub; - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// DEC $acD -// 0111 101d xxxx xxxx -// Decrement accumulator $acD. -void dec(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x01; - - s64 acc = dsp_get_long_acc(dreg) - 1; - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// INCM $acsD -// 0111 010d xxxx xxxx -// Increment 24-bit mid-accumulator $acsD. -void incm(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - - s64 sub = 0x10000; - s64 acc = dsp_get_long_acc(dreg); - acc += sub; - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// INC $acD -// 0111 011d xxxx xxxx -// Increment accumulator $acD. -void inc(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(dreg) + 1; - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// NEG $acD -// 0111 110d xxxx xxxx -// Negate accumulator $acD. -void neg(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(areg); - acc = 0 - acc; - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// MOVNP $acD -// 0111 111d xxxx xxxx -// Moves negative of multiply product from $prod register to accumulator -// $acD register. -void movnp(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - - s64 prod = dsp_get_long_prod(); - s64 acc = -prod; - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// MOV $acD, $ac(1-D) -// 0110 110d xxxx xxxx -// Moves accumulator $ax(1-D) to accumulator $axD. -void mov(const UDSPInstruction& opc) -{ - u8 D = (opc.hex >> 8) & 0x1; - u64 acc = dsp_get_long_acc(1 - D); - dsp_set_long_acc(D, acc); - - Update_SR_Register64(acc); -} - -// ADDAX $acD, $axS -// 0100 10sd xxxx xxxx -// Adds secondary accumulator $axS to accumulator register $acD. -void addax(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - u8 sreg = (opc.hex >> 9) & 0x1; - - s64 ax = dsp_get_long_acx(sreg); - s64 acc = dsp_get_long_acc(areg); - acc += ax; - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// ADDR $acD, $(DSP_REG_AXL0+S) -// 0100 0ssd xxxx xxxx -// Adds register $(DSP_REG_AXL0+S) to accumulator $acD register. -void addr(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; - - s64 ax = (s16)g_dsp.r[sreg]; - ax <<= 16; - - s64 acc = dsp_get_long_acc(areg); - acc += ax; - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// SUBR $acD, $(DSP_REG_AXL0+S) -// 0101 0ssd xxxx xxxx -// Subtracts register $(DSP_REG_AXL0+S) from accumulator $acD register. -void subr(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; - - s64 ax = (s16)g_dsp.r[sreg]; - ax <<= 16; - - s64 acc = dsp_get_long_acc(areg); - acc -= ax; - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// SUBAX $acD, $axS -// 0101 10sd xxxx xxxx -// Subtracts secondary accumulator $axS from accumulator register $acD. -void subax(const UDSPInstruction& opc) -{ - int regD = (opc.hex >> 8) & 0x1; - int regS = (opc.hex >> 9) & 0x1; - - s64 acc = dsp_get_long_acc(regD) - dsp_get_long_acx(regS); - - dsp_set_long_acc(regD, acc); - Update_SR_Register64(acc); -} - -// ADDIS $acD, #I -// 0000 010d iiii iiii -// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm. -void addis(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - - s64 Imm = (s8)(u8)opc.hex; - Imm <<= 16; - s64 acc = dsp_get_long_acc(areg); - acc += Imm; - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// ADDI $amR, #I -// 0000 001r 0000 0000 -// iiii iiii iiii iiii -// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. -void addi(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - - s64 sub = (s16)dsp_fetch_code(); - sub <<= 16; - s64 acc = dsp_get_long_acc(areg); - acc += sub; - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// LSL16 $acR -// 1111 000r xxxx xxxx -// Logically shifts left accumulator $acR by 16. -void lsl16(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(areg); - acc <<= 16; - dsp_set_long_acc(areg, acc); - Update_SR_Register64(acc); -} - -// MADD $axS.l, $axS.h -// 1111 001s xxxx xxxx -// Multiply low part $axS.l of secondary accumulator $axS by high part -// $axS.h of secondary accumulator $axS (treat them both as signed) and add -// result to product register. -void madd(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 8) & 0x1; - - s64 prod = dsp_get_long_prod(); - prod += (s64)dsp_get_ax_l(sreg) * (s64)dsp_get_ax_h(sreg) * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); -} - -// MSUB $axS.l, $axS.h -// 1111 011s xxxx xxxx -// Multiply low part $axS.l of secondary accumulator $axS by high part -// $axS.h of secondary accumulator $axS (treat them both as signed) and -// subtract result from product register. -void msub(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 8) & 0x1; - - s64 prod = dsp_get_long_prod(); - prod -= (s64)dsp_get_ax_l(sreg) * (s64)dsp_get_ax_h(sreg) * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); - -} - -// LSR16 $acR -// 1111 010r xxxx xxxx -// Logically shifts right accumulator $acR by 16. -void lsr16(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - - u64 acc = dsp_get_long_acc(areg); - - acc >>= 16; - dsp_set_long_acc(areg, acc); - Update_SR_Register64(acc); -} - -// ASR16 $acR -// 1001 r001 xxxx xxxx -// Arithmetically shifts right accumulator $acR by 16. -void asr16(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 11) & 0x1; - - s64 acc = dsp_get_long_acc(areg); - - acc >>= 16; - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// LSL $acR, #I -// 0001 010r 00ii iiii -// Logically shifts left accumulator $acR by number specified by value I. -void lsl(const UDSPInstruction& opc) -{ - u16 shift = opc.ushift; - u64 acc = dsp_get_long_acc(opc.areg); - - acc <<= shift; - dsp_set_long_acc(opc.areg, acc); - Update_SR_Register64(acc); -} - -// LSR $acR, #I -// 0001 010r 01ii iiii -// Logically shifts left accumulator $acR by number specified by value -// calculated by negating sign extended bits 0-6. -void lsr(const UDSPInstruction& opc) -{ - u16 shift = -opc.ushift; - u64 acc = dsp_get_long_acc(opc.areg); - // Lop off the extraneous sign extension our 64-bit fake accum causes - acc &= 0x000000FFFFFFFFFFULL; - acc >>= shift; - dsp_set_long_acc(opc.areg, (s64)acc); - Update_SR_Register64(acc); -} - -// ASL $acR, #I -// 0001 010r 10ii iiii -// Logically shifts left accumulator $acR by number specified by value I. -void asl(const UDSPInstruction& opc) -{ - u16 shift = opc.ushift; - - // arithmetic shift - u64 acc = dsp_get_long_acc(opc.areg); - acc <<= shift; - - dsp_set_long_acc(opc.areg, acc); - - Update_SR_Register64(acc); -} - -// ASR $acR, #I -// 0001 010r 11ii iiii -// Arithmetically shifts right accumulator $acR by number specified by -// value calculated by negating sign extended bits 0-6. -void asr(const UDSPInstruction& opc) -{ - u16 shift = -opc.ushift; - - // arithmetic shift - s64 acc = dsp_get_long_acc(opc.areg); - acc >>= shift; - - dsp_set_long_acc(opc.areg, acc); - - Update_SR_Register64(acc); -} - -//------------------------------------------------------------- -// DAR $arD ? -// 0000 0000 0000 01dd -// Decrement address register $arD. -void dar(const UDSPInstruction& opc) -{ - dsp_decrement_addr_reg(opc.hex & 0x3); -} - -// IAR $arD ? -// 0000 0000 0000 10dd -// Increment address register $arD. -void iar(const UDSPInstruction& opc) -{ - dsp_increment_addr_reg(opc.hex & 0x3); -} - -//------------------------------------------------------------- - -// SBCLR #I -// 0001 0011 0000 0iii -// bit of status register $sr. Bit number is calculated by adding 6 to -// immediate value I. -void sbclr(const UDSPInstruction& opc) -{ - u8 bit = (opc.hex & 0xff) + 6; - g_dsp.r[DSP_REG_SR] &= ~(1 << bit); -} - -// SBSET #I -// 0001 0010 0000 0iii -// Set bit of status register $sr. Bit number is calculated by adding 6 to -// immediate value I. -void sbset(const UDSPInstruction& opc) -{ - u8 bit = (opc.hex & 0xff) + 6; - g_dsp.r[DSP_REG_SR] |= (1 << bit); -} - - -// FIXME inside -// This is a bunch of flag setters, flipping bits in SR. So far so good, -// but it's harder to know exactly what effect they have. -// M0/M2 change the multiplier mode (it can multiply by 2 for free). -// -// SET16 changes something very important: see the LRI instruction above. -// Hermes' demo sets the following defaults: -// SET40 -// CLR15 -// M0 -void srbith(const UDSPInstruction& opc) -{ - switch ((opc.hex >> 8) & 0xf) - { - // M0 seems to be the default. M2 is used in functions in Zelda - // and then reset with M0 at the end. Like the other bits here, it's - // done around loops with lots of multiplications. - // I've confirmed with DSPSpy that they flip this bit. - case 0xa: // M2 - g_dsp.r[DSP_REG_SR] &= ~SR_MUL_MODIFY; - break; - case 0xb: // M0 - g_dsp.r[DSP_REG_SR] |= SR_MUL_MODIFY; - break; - - // If set, treat multiplicands as unsigned 16-bit ints. - // If clear, treat them as signed. - case 0xc: // CLR15 - g_dsp.r[DSP_REG_SR] &= ~SR_MUL_UNSIGNED; - break; - case 0xd: // SET15 - g_dsp.r[DSP_REG_SR] |= SR_MUL_UNSIGNED; - break; - - // Automatic 40-bit sign extension when loading ACx.M. - // 40 seems to be the default. - // Confirmed these by using DSPSpy and copying the value of SR to R00 after setting. - case 0xe: // SET16 (really, clear SR's 0x4000) - g_dsp.r[DSP_REG_SR] &= ~SR_40_MODE_BIT; - break; - - case 0xf: // SET40 (really, set SR's 0x4000) - g_dsp.r[DSP_REG_SR] |= SR_40_MODE_BIT; - break; - - default: - break; - } -} - -//------------------------------------------------------------- - -// MOVP $acD -// 0110 111d xxxx xxxx -// Moves multiply product from $prod register to accumulator $acD register. -void movp(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - - s64 prod = dsp_get_long_prod(); - dsp_set_long_acc(dreg, prod); - - Update_SR_Register64(prod); -} - -// MUL $axS.l, $axS.h -// 1001 s000 xxxx xxxx -// Multiply low part $axS.l of secondary accumulator $axS by high part -// $axS.h of secondary accumulator $axS (treat them both as signed). -void mul(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 11) & 0x1; - s64 prod = (s64)dsp_get_ax_h(sreg) * (s64)dsp_get_ax_l(sreg) * GetMultiplyModifier(); - - dsp_set_long_prod(prod); - - // FIXME: no update in duddie's docs - Update_SR_Register64(prod); -} - -// MULAC $axS.l, $axS.h, $acR -// 1001 s10r xxxx xxxx -// Add product register to accumulator register $acR. Multiply low part -// $axS.l of secondary accumulator $axS by high part $axS.h of secondary -// accumulator $axS (treat them both as signed). -void mulac(const UDSPInstruction& opc) -{ - // add old prod to acc - u8 rreg = (opc.hex >> 8) & 0x1; - s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - dsp_set_long_acc(rreg, acR); - - // calculate new prod - u8 sreg = (opc.hex >> 11) & 0x1; - s64 prod = dsp_get_ax_l(sreg) * dsp_get_ax_h(sreg) * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - // FIXME: no update in duddie's docs - Update_SR_Register64(prod); -} - -// MULMV $axS.l, $axS.h, $acR -// 1001 s11r xxxx xxxx -// Move product register to accumulator register $acR. Multiply low part -// $axS.l of secondary accumulator $axS by high part $axS.h of secondary -// accumulator $axS (treat them both as signed). -void mulmv(const UDSPInstruction& opc) -{ - u8 rreg = (opc.hex >> 8) & 0x1; - u8 sreg = ((opc.hex >> 11) & 0x1); - s64 prod = dsp_get_long_prod(); - s64 acc = prod; - dsp_set_long_acc(rreg, acc); - - s64 val1 = (s16)g_dsp.r[sreg + DSP_REG_AXL0]; - s64 val2 = (s16)g_dsp.r[sreg + DSP_REG_AXH0]; - - prod = val1 * val2 * GetMultiplyModifier(); - - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); -} - -// MULMVZ $axS.l, $axS.h, $acR -// 1001 s01r xxxx xxxx -// Move product register to accumulator register $acR and clear low part -// of accumulator register $acR.l. Multiply low part $axS.l of secondary -// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat -// them both as signed). -void mulmvz(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 11) & 0x1; - u8 rreg = (opc.hex >> 8) & 0x1; - - // overwrite acc and clear low part - s64 prod = dsp_get_long_prod(); - s64 acc = prod & ~0xffff; - dsp_set_long_acc(rreg, acc); - - // math prod - prod = (s64)(s16)g_dsp.r[DSP_REG_AXL0 + sreg] * (s64)(s16)g_dsp.r[DSP_REG_AXH0 + sreg] * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); -} - -// MULX $ax0.S, $ax1.T -// 101s t000 xxxx xxxx -// Multiply one part $ax0 by one part $ax1 (treat them both as signed). -// Part is selected by S and T bits. Zero selects low part, one selects high part. -void mulx(const UDSPInstruction& opc) -{ - u8 sreg = ((opc.hex >> 12) & 0x1); - u8 treg = ((opc.hex >> 11) & 0x1); - - s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - - s64 prod = val1 * val2 * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); -} - -// MULXAC $ax0.S, $ax1.T, $acR -// 101s t01r xxxx xxxx -// Add product register to accumulator register $acR. Multiply one part -// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and -// T bits. Zero selects low part, one selects high part. -void mulxac(const UDSPInstruction& opc) -{ - // add old prod to acc - u8 rreg = (opc.hex >> 8) & 0x1; - s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - dsp_set_long_acc(rreg, acR); - - // math new prod - u8 sreg = (opc.hex >> 12) & 0x1; - u8 treg = (opc.hex >> 11) & 0x1; - - s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - - s64 prod = val1 * val2 * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); -} - -// MULXMV $ax0.S, $ax1.T, $acR -// 101s t11r xxxx xxxx -// Move product register to accumulator register $acR. Multiply one part -// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and -// T bits. Zero selects low part, one selects high part. -void mulxmv(const UDSPInstruction& opc) -{ - // add old prod to acc - u8 rreg = ((opc.hex >> 8) & 0x1); - s64 acR = dsp_get_long_prod(); - dsp_set_long_acc(rreg, acR); - - // math new prod - u8 sreg = (opc.hex >> 12) & 0x1; - u8 treg = (opc.hex >> 11) & 0x1; - - s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - - s64 prod = val1 * val2 * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); -} - -// MULXMV $ax0.S, $ax1.T, $acR -// 101s t01r xxxx xxxx -// Move product register to accumulator register $acR and clear low part -// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 (treat -// them both as signed). Part is selected by S and T bits. Zero selects low part, -// one selects high part. -void mulxmvz(const UDSPInstruction& opc) -{ - // overwrite acc and clear low part - u8 rreg = (opc.hex >> 8) & 0x1; - s64 prod = dsp_get_long_prod(); - s64 acc = prod & ~0xffff; - dsp_set_long_acc(rreg, acc); - - // math prod - u8 sreg = (opc.hex >> 12) & 0x1; - u8 treg = (opc.hex >> 11) & 0x1; - - s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - - prod = val1 * val2 * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); -} - -// SUB $acD, $ac(1-D) -// 0101 110d xxxx xxxx -// Subtracts accumulator $ac(1-D) from accumulator register $acD. -void sub(const UDSPInstruction& opc) -{ - u8 D = (opc.hex >> 8) & 0x1; - s64 acc1 = dsp_get_long_acc(D); - s64 acc2 = dsp_get_long_acc(1 - D); - - acc1 -= acc2; - - dsp_set_long_acc(D, acc1); - - Update_SR_Register64(acc1); -} - - -//------------------------------------------------------------- -// -// --- Table E -// -//------------------------------------------------------------- - -// MADDX ax0.S ax1.T -// 1110 00st xxxx xxxx -// Multiply one part of secondary accumulator $ax0 (selected by S) by -// one part of secondary accumulator $ax1 (selected by T) (treat them both as -// signed) and add result to product register. -void maddx(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 9) & 0x1; - u8 treg = (opc.hex >> 8) & 0x1; - - s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - - s64 prod = dsp_get_long_prod(); - prod += val1 * val2 * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); - -} - -// MSUBX $(0x18+S*2), $(0x19+T*2) -// 1110 01st xxxx xxxx -// Multiply one part of secondary accumulator $ax0 (selected by S) by -// one part of secondary accumulator $ax1 (selected by T) (treat them both as -// signed) and subtract result from product register. -void msubx(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 9) & 0x1; - u8 treg = (opc.hex >> 8) & 0x1; - - s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - - s64 prod = dsp_get_long_prod(); - prod -= val1 * val2 * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); -} - -// MADDC $acS.m, $axT.h -// 1110 10st xxxx xxxx -// Multiply middle part of accumulator $acS.m by high part of secondary -// accumulator $axT.h (treat them both as signed) and add result to product -// register. -void maddc(const UDSPInstruction& opc) -{ - u32 sreg = (opc.hex >> 9) & 0x1; - u32 treg = (opc.hex >> 8) & 0x1; - - s64 val1 = dsp_get_acc_m(sreg); - s64 val2 = dsp_get_ax_h(treg); - - s64 prod = dsp_get_long_prod(); - prod += val1 * val2 * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); -} - -// MSUBC $acS.m, $axT.h -// 1110 11st xxxx xxxx -// Multiply middle part of accumulator $acS.m by high part of secondary -// accumulator $axT.h (treat them both as signed) and subtract result from -// product register. -void msubc(const UDSPInstruction& opc) -{ - u32 sreg = (opc.hex >> 9) & 0x1; - u32 treg = (opc.hex >> 8) & 0x1; - - s64 val1 = dsp_get_acc_m(sreg); - s64 val2 = dsp_get_ax_h(treg); - - s64 prod = dsp_get_long_prod(); - prod -= val1 * val2 * GetMultiplyModifier(); - dsp_set_long_prod(prod); - - Update_SR_Register64(prod); -} - -// SRS @M, $(0x18+S) -// 0010 1sss mmmm mmmm -// Store value from register $(0x18+S) to a memory pointed by address M. -// (8-bit sign extended). -// FIXME: Perform additional operation depending on destination register. -// Note: pc+=2 in duddie's doc seems wrong -void srs(const UDSPInstruction& opc) -{ - u8 reg = ((opc.hex >> 8) & 0x7) + 0x18; - u16 addr = (u16)(s16)(s8)opc.hex; - dsp_dmem_write(addr, g_dsp.r[reg]); -} - -// LRS $(0x18+D), @M -// 0010 0ddd mmmm mmmm -// Move value from data memory pointed by address M (8-bit sign -// extended) to register $(0x18+D). -// FIXME: Perform additional operation depending on destination register. -// Note: pc+=2 in duddie's doc seems wrong -void lrs(const UDSPInstruction& opc) -{ - u8 reg = ((opc.hex >> 8) & 0x7) + 0x18; - u16 addr = (u16)(s16)(s8)opc.hex; - g_dsp.r[reg] = dsp_dmem_read(addr); -} - -} // namespace diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp index 058f50671a..0eab6484ed 100644 --- a/Source/Core/DSPCore/Src/DSPTables.cpp +++ b/Source/Core/DSPCore/Src/DSPTables.cpp @@ -243,7 +243,7 @@ const DSPOPCTemplate opcodes[] = {"CMP", 0x8200, 0xffff, DSPInterpreter::cmp, nop, 1 | P_EXT, 0, {}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // This op does NOT exist, at least not under this name, in duddie's docs! - {"CMPAR" , 0xc100, 0xe7ff, DSPInterpreter::cmpar, nop, 1 | P_EXT, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, + {"CMPAR" , 0xc100, 0xe7ff, DSPInterpreter::cmpar, nop, 1 | P_EXT, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, {"CLRL", 0xfc00, 0xffff, DSPInterpreter::clrl, nop, 1 | P_EXT, 1, {{P_ACCL, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acl0 {"CLR", 0x8100, 0xf7ff, DSPInterpreter::clr, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, dsp_op_ext_ops_pro, dsp_op_ext_ops_epi}, // clear acc0 diff --git a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp new file mode 100644 index 0000000000..4fb0ef1236 --- /dev/null +++ b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp @@ -0,0 +1,695 @@ +// Copyright (C) 2003-2009 Dolphin Project. + +// 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, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" + +#include "gdsp_condition_codes.h" +#include "gdsp_opcodes_helper.h" + +// Arithmetic and accumulator control. + +namespace DSPInterpreter { + +// CLR $acR +// 1000 r001 xxxx xxxx +// Clears accumulator $acR +void clr(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 11) & 0x1; + + dsp_set_long_acc(reg, 0); + + Update_SR_Register64((s64)0); // really? +} + +// CLRL $acR.l +// 1111 110r xxxx xxxx +// Clears $acR.l - low 16 bits of accumulator $acR. +void clrl(const UDSPInstruction& opc) +{ + u16 reg = DSP_REG_ACL0 + ((opc.hex >> 11) & 0x1); + g_dsp.r[reg] = 0; + + // Should this be 64bit? + // nakee: it says the whole reg in duddie's doc sounds weird + Update_SR_Register64((s64)reg); +} + + +// ADDAXL $acD, $axS.l +// 0111 00sd xxxx xxxx +// Adds secondary accumulator $axS.l to accumulator register $acD. +void addaxl(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 acx = dsp_get_ax_l(sreg); + + acc += acx; + + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// TSTAXH $axR.h +// 1000 011r xxxx xxxx +// Test high part of secondary accumulator $axR.h. +void tstaxh(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 8) & 0x1; + s16 val = dsp_get_ax_h(reg); + + Update_SR_Register16(val); +} + +// SUB $acD, $ac(1-D) +// 0101 110d xxxx xxxx +// Subtracts accumulator $ac(1-D) from accumulator register $acD. +void sub(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + s64 acc1 = dsp_get_long_acc(D); + s64 acc2 = dsp_get_long_acc(1 - D); + + acc1 -= acc2; + + dsp_set_long_acc(D, acc1); + + Update_SR_Register64(acc1); +} + +// MOVR $acD, $axS.R +// 0110 0srd xxxx xxxx +// Moves register $axS.R (sign extended) to middle accumulator $acD.hm. +// Sets $acD.l to 0. +// TODO: Check what happens to acD.h. +void movr(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; + + s64 acc = (s16)g_dsp.r[sreg]; + acc <<= 16; + acc &= ~0xffff; + + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// MOVAX $acD, $axS +// 0110 10sd xxxx xxxx +// Moves secondary accumulator $axS to accumulator $axD. +void movax(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + + s64 acx = dsp_get_long_acx(sreg); + dsp_set_long_acc(dreg, acx); + + Update_SR_Register64(acx); +} + +// XORR $acD.m, $axS.h +// 0011 00sd xxxx xxxx +// Logic XOR (exclusive or) middle part of accumulator $acD.m with +// high part of secondary accumulator $axS.h. +void xorr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + g_dsp.r[DSP_REG_ACM0 + dreg] ^= g_dsp.r[DSP_REG_AXH0 + sreg]; + + s64 acc = dsp_get_long_acc(dreg); + Update_SR_Register64(acc); +} + +// ANDR $acD.m, $axS.h +// 0011 01sd xxxx xxxx +// Logic AND middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +void andr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + g_dsp.r[DSP_REG_ACM0 + dreg] &= g_dsp.r[DSP_REG_AXH0 + sreg]; + + s64 acc = dsp_get_long_acc(dreg); + + Update_SR_Register64(acc); +} + +// ORR $acD.m, $axS.h +// 0011 10sd xxxx xxxx +// Logic OR middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +void orr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + g_dsp.r[DSP_REG_ACM0 + dreg] |= g_dsp.r[DSP_REG_AXH0 + sreg]; + + s64 acc = dsp_get_long_acc(dreg); + + Update_SR_Register64(acc); +} + +// ANDC $acD.m, $ac(1-D).m +// 0011 110d xxxx xxxx +// Logic AND middle part of accumulator $acD.m with middle part of +// accumulator $ax(1-D).m.s +void andc(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + + u16 ac1 = dsp_get_acc_m(D); + u16 ac2 = dsp_get_acc_m(1 - D); + + dsp_set_long_acc(D, ac1 & ac2); + + Update_SR_Register64(dsp_get_long_acc(D)); +} + +// ORC $acD.m, $ac(1-D).m +// 0011 111d xxxx xxxx +// Logic OR middle part of accumulator $acD.m with middle part of +// accumulator $ax(1-D).m. +void orc(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + + u16 ac1 = dsp_get_acc_m(D); + u16 ac2 = dsp_get_acc_m(1 - D); + + dsp_set_long_acc(D, ac1 | ac2); + + Update_SR_Register64(dsp_get_long_acc(D)); +} + +void orf(const UDSPInstruction& opc) +{ + ERROR_LOG(DSPLLE, "orf not implemented"); +} + +// Hermes switched andf and andcf, so check to make sure they are still correct +// ANDCF $acD.m, #I +// 0000 001r 1100 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logic AND of +// accumulator mid part $acD.m with immediate value I is equal I. +void andcf(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + u16 val = dsp_get_acc_m(reg); + + Update_SR_LZ(((val & imm) == imm) ? 0 : 1); +} + +// Hermes switched andf and andcf, so check to make sure they are still correct + +// ANDF $acD.m, #I +// 0000 001r 1010 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logical AND +// operation of accumulator mid part $acD.m with immediate value I is equal +// immediate value 0. +void andf(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + u16 val = g_dsp.r[reg]; + + Update_SR_LZ(((val & imm) == 0) ? 0 : 1); +} + +// CMPI $amD, #I +// 0000 001r 1000 0000 +// iiii iiii iiii iiii +// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. +// Although flags are being set regarding whole accumulator register. +void cmpi(const UDSPInstruction& opc) +{ + int reg = (opc.hex >> 8) & 0x1; + + // Immediate is considered to be at M level in the 40-bit accumulator. + s64 imm = (s64)(s16)dsp_fetch_code() << 16; + s64 val = dsp_get_long_acc(reg); + Update_SR_Register64(val - imm); +} + +// XORI $acD.m, #I +// 0000 001r 0010 0000 +// iiii iiii iiii iiii +// Logic exclusive or (XOR) of accumulator mid part $acD.m with +// immediate value I. +void xori(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + g_dsp.r[reg] ^= imm; + + Update_SR_Register16((s16)g_dsp.r[reg]); +} + +// ANDI $acD.m, #I +// 0000 001r 0100 0000 +// iiii iiii iiii iiii +// Logic AND of accumulator mid part $acD.m with immediate value I. +void andi(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + g_dsp.r[reg] &= imm; + + Update_SR_Register16((s16)g_dsp.r[reg]); +} + + +// F|RES: i am not sure if this shouldnt be the whole ACC +// ORI $acD.m, #I +// 0000 001r 0110 0000 +// iiii iiii iiii iiii +// Logic OR of accumulator mid part $acD.m with immediate value I. +void ori(const UDSPInstruction& opc) +{ + u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); + u16 imm = dsp_fetch_code(); + g_dsp.r[reg] |= imm; + + Update_SR_Register16((s16)g_dsp.r[reg]); +} + +//------------------------------------------------------------- + + +// ADD $acD, $ac(1-D) +// 0100 110d xxxx xxxx +// Adds accumulator $ac(1-D) to accumulator register $acD. +void add(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + s64 acc0 = dsp_get_long_acc(0); + s64 acc1 = dsp_get_long_acc(1); + + s64 res = acc0 + acc1; + + dsp_set_long_acc(areg, res); + + Update_SR_Register64(res); +} + +// ADDP $acD +// 0100 111d xxxx xxxx +// Adds product register to accumulator register. +void addp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + s64 acc = dsp_get_long_acc(dreg); + acc += dsp_get_long_prod(); + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// SUBP $acD +// 0101 111d xxxx xxxx +// Subtracts product register from accumulator register. +void subp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + s64 acc = dsp_get_long_acc(dreg); + acc -= dsp_get_long_prod(); + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + + +// CMPIS $acD, #I +// 0000 011d iiii iiii +// Compares accumulator with short immediate. Comaprison is executed +// by subtracting short immediate (8bit sign extended) from mid accumulator +// $acD.hm and computing flags based on whole accumulator $acD. +void cmpis(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + s64 val = (s8)opc.hex; + val <<= 16; + + s64 res = acc - val; + + Update_SR_Register64(res); +} + + +// DECM $acsD +// 0111 100d xxxx xxxx +// Decrement 24-bit mid-accumulator $acsD. +void decm(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + acc -= sub; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// DEC $acD +// 0111 101d xxxx xxxx +// Decrement accumulator $acD. +void dec(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + s64 acc = dsp_get_long_acc(dreg) - 1; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// INCM $acsD +// 0111 010d xxxx xxxx +// Increment 24-bit mid-accumulator $acsD. +void incm(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + acc += sub; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// INC $acD +// 0111 011d xxxx xxxx +// Increment accumulator $acD. +void inc(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg) + 1; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// NEG $acD +// 0111 110d xxxx xxxx +// Negate accumulator $acD. +void neg(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + acc = 0 - acc; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// MOV $acD, $ac(1-D) +// 0110 110d xxxx xxxx +// Moves accumulator $ax(1-D) to accumulator $axD. +void mov(const UDSPInstruction& opc) +{ + u8 D = (opc.hex >> 8) & 0x1; + u64 acc = dsp_get_long_acc(1 - D); + dsp_set_long_acc(D, acc); + + Update_SR_Register64(acc); +} + +// ADDAX $acD, $axS +// 0100 10sd xxxx xxxx +// Adds secondary accumulator $axS to accumulator register $acD. +void addax(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + + s64 ax = dsp_get_long_acx(sreg); + s64 acc = dsp_get_long_acc(areg); + acc += ax; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// ADDR $acD, $(DSP_REG_AXL0+S) +// 0100 0ssd xxxx xxxx +// Adds register $(DSP_REG_AXL0+S) to accumulator $acD register. +void addr(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; + + s64 ax = (s16)g_dsp.r[sreg]; + ax <<= 16; + + s64 acc = dsp_get_long_acc(areg); + acc += ax; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// SUBR $acD, $(DSP_REG_AXL0+S) +// 0101 0ssd xxxx xxxx +// Subtracts register $(DSP_REG_AXL0+S) from accumulator $acD register. +void subr(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; + + s64 ax = (s16)g_dsp.r[sreg]; + ax <<= 16; + + s64 acc = dsp_get_long_acc(areg); + acc -= ax; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// SUBAX $acD, $axS +// 0101 10sd xxxx xxxx +// Subtracts secondary accumulator $axS from accumulator register $acD. +void subax(const UDSPInstruction& opc) +{ + int regD = (opc.hex >> 8) & 0x1; + int regS = (opc.hex >> 9) & 0x1; + + s64 acc = dsp_get_long_acc(regD) - dsp_get_long_acx(regS); + + dsp_set_long_acc(regD, acc); + Update_SR_Register64(acc); +} + +// ADDIS $acD, #I +// 0000 010d iiii iiii +// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm. +void addis(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 Imm = (s8)(u8)opc.hex; + Imm <<= 16; + s64 acc = dsp_get_long_acc(areg); + acc += Imm; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// ADDI $amR, #I +// 0000 001r 0000 0000 +// iiii iiii iiii iiii +// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. +void addi(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 sub = (s16)dsp_fetch_code(); + sub <<= 16; + s64 acc = dsp_get_long_acc(areg); + acc += sub; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// LSL16 $acR +// 1111 000r xxxx xxxx +// Logically shifts left accumulator $acR by 16. +void lsl16(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + acc <<= 16; + dsp_set_long_acc(areg, acc); + Update_SR_Register64(acc); +} + +// LSR16 $acR +// 1111 010r xxxx xxxx +// Logically shifts right accumulator $acR by 16. +void lsr16(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + u64 acc = dsp_get_long_acc(areg); + + acc >>= 16; + dsp_set_long_acc(areg, acc); + Update_SR_Register64(acc); +} + +// ASR16 $acR +// 1001 r001 xxxx xxxx +// Arithmetically shifts right accumulator $acR by 16. +void asr16(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 11) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + + acc >>= 16; + dsp_set_long_acc(areg, acc); + + Update_SR_Register64(acc); +} + +// LSL $acR, #I +// 0001 010r 00ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +void lsl(const UDSPInstruction& opc) +{ + u16 shift = opc.ushift; + u64 acc = dsp_get_long_acc(opc.areg); + + acc <<= shift; + dsp_set_long_acc(opc.areg, acc); + Update_SR_Register64(acc); +} + +// LSR $acR, #I +// 0001 010r 01ii iiii +// Logically shifts left accumulator $acR by number specified by value +// calculated by negating sign extended bits 0-6. +void lsr(const UDSPInstruction& opc) +{ + u16 shift = -opc.ushift; + u64 acc = dsp_get_long_acc(opc.areg); + // Lop off the extraneous sign extension our 64-bit fake accum causes + acc &= 0x000000FFFFFFFFFFULL; + acc >>= shift; + dsp_set_long_acc(opc.areg, (s64)acc); + Update_SR_Register64(acc); +} + +// ASL $acR, #I +// 0001 010r 10ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +void asl(const UDSPInstruction& opc) +{ + u16 shift = opc.ushift; + + // arithmetic shift + u64 acc = dsp_get_long_acc(opc.areg); + acc <<= shift; + + dsp_set_long_acc(opc.areg, acc); + + Update_SR_Register64(acc); +} + +// ASR $acR, #I +// 0001 010r 11ii iiii +// Arithmetically shifts right accumulator $acR by number specified by +// value calculated by negating sign extended bits 0-6. +void asr(const UDSPInstruction& opc) +{ + u16 shift = -opc.ushift; + + // arithmetic shift + s64 acc = dsp_get_long_acc(opc.areg); + acc >>= shift; + + dsp_set_long_acc(opc.areg, acc); + + Update_SR_Register64(acc); +} + +// CMPAR $acS axR.h +// 1100 0001 xxxx xxxx +// Compares accumulator $acS with accumulator axR.h. +// Not described by Duddie's doc - at least not as a separate instruction. +void cmpar(const UDSPInstruction& opc) +{ + u8 rreg = ((opc.hex >> 12) & 0x1) + DSP_REG_AXH0; + u8 sreg = (opc.hex >> 11) & 0x1; + + // we compare + s64 rr = (s16)g_dsp.r[rreg]; + rr <<= 16; + + s64 sr = dsp_get_long_acc(sreg); + + Update_SR_Register64(sr - rr); +} + +// CMP +// 1000 0010 xxxx xxxx +// Compares accumulator $ac0 with accumulator $ac1. +void cmp(const UDSPInstruction& opc) +{ + s64 acc0 = dsp_get_long_acc(0); + s64 acc1 = dsp_get_long_acc(1); + + Update_SR_Register64(acc0 - acc1); +} + +// TST +// 1011 r001 xxxx xxxx +// Test accumulator %acR. +void tst(const UDSPInstruction& opc) +{ + s8 reg = (opc.hex >> 11) & 0x1; + s64 acc = dsp_get_long_acc(reg); + + Update_SR_Register64(acc); +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntBranch.cpp b/Source/Core/DSPCore/Src/DspIntBranch.cpp new file mode 100644 index 0000000000..78ef2adf46 --- /dev/null +++ b/Source/Core/DSPCore/Src/DspIntBranch.cpp @@ -0,0 +1,250 @@ +// Copyright (C) 2003-2009 Dolphin Project. + +// 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, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" +#include "DSPCore.h" + +#include "gdsp_condition_codes.h" +#include "gdsp_opcodes_helper.h" +#include "gdsp_memory.h" + + +namespace DSPInterpreter { + +// Generic call implementation +// CALLcc addressA +// 0000 0010 1011 cccc +// aaaa aaaa aaaa aaaa +// Call function if condition cc has been met. Push program counter of +// instruction following "call" to $st0. Set program counter to address +// represented by value that follows this "call" instruction. +void call(const UDSPInstruction& opc) +{ + // must be outside the if. + u16 dest = dsp_fetch_code(); + if (CheckCondition(opc.hex & 0xf)) + { + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + g_dsp.pc = dest; + } +} + +// Generic callr implementation +// CALLRcc $R +// 0001 0111 rrr1 cccc +// Call functionif condition cc has been met.Push program counter of +// instruction following "call" tocall stack $st0. Set program counter to +// register $R. +void callr(const UDSPInstruction& opc) +{ + if (CheckCondition(opc.hex & 0xf)) + { + u8 reg = (opc.hex >> 5) & 0x7; + u16 addr = dsp_op_read_reg(reg); + dsp_reg_store_stack(DSP_STACK_C, g_dsp.pc); + g_dsp.pc = addr; + } +} + +// Generic if implementation +// IFcc +// 0000 0010 0111 cccc +// Execute following opcode if the condition has been met. +void ifcc(const UDSPInstruction& opc) +{ + if (!CheckCondition(opc.hex & 0xf)) + { + // skip the next opcode - we have to lookup its size. + g_dsp.pc += opSize[dsp_peek_code()]; + } +} + +// Generic jmp implementation +// Jcc addressA +// 0000 0010 1001 cccc +// aaaa aaaa aaaa aaaa +// Jump to addressA if condition cc has been met. Set program counter to +// address represented by value that follows this "jmp" instruction. +void jcc(const UDSPInstruction& opc) +{ + u16 dest = dsp_fetch_code(); + if (CheckCondition(opc.hex & 0xf)) + { + g_dsp.pc = dest; + } +} + +// Generic jmpr implementation +// JMPcc $R +// 0001 0111 rrr0 cccc +// Jump to address; set program counter to a value from register $R. +void jmprcc(const UDSPInstruction& opc) +{ + if (CheckCondition(opc.hex & 0xf)) + { + u8 reg = (opc.hex >> 5) & 0x7; + g_dsp.pc = dsp_op_read_reg(reg); + } +} + +// Generic ret implementation +// RETcc +// 0000 0010 1101 cccc +// Return from subroutine if condition cc has been met. Pops stored PC +// from call stack $st0 and sets $pc to this location. +void ret(const UDSPInstruction& opc) +{ + if (CheckCondition(opc.hex & 0xf)) + { + g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + } +} + +// RTI +// 0000 0010 1111 1111 +// Return from exception. Pops stored status register $sr from data stack +// $st1 and program counter PC from call stack $st0 and sets $pc to this +// location. +// FIXME: is it also conditional? unknown opcodes 0x02fx +void rti(const UDSPInstruction& opc) +{ + g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(DSP_STACK_D); + g_dsp.pc = dsp_reg_load_stack(DSP_STACK_C); + + g_dsp.exception_in_progress_hack = false; +} + +// HALT +// 0000 0000 0020 0001 +// Stops execution of DSP code. Sets bit DSP_CR_HALT in register DREG_CR. +void halt(const UDSPInstruction& opc) +{ + g_dsp.cr |= 0x4; + g_dsp.pc--; +} + + +// LOOP handling: Loop stack is used to control execution of repeated blocks of +// instructions. Whenever there is value on stack $st2 and current PC is equal +// value at $st2, then value at stack $st3 is decremented. If value is not zero +// then PC is modified with calue from call stack $st0. Otherwise values from +// callstack $st0 and both loop stacks $st2 and $st3 are poped and execution +// continues at next opcode. + + +// LOOP $R +// 0000 0000 010r rrrr +// Repeatedly execute following opcode until counter specified by value +// from register $R reaches zero. Each execution decrement counter. Register +// $R remains unchanged. If register $R is set to zero at the beginning of loop +// then looped instruction will not get executed. +// Actually, this instruction simply prepares the loop stacks for the above. +// The looping hardware takes care of the rest. +void loop(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x1f; + u16 cnt = g_dsp.r[reg]; + u16 loop_pc = g_dsp.pc; + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } +} + +// LOOPI #I +// 0001 0000 iiii iiii +// Repeatedly execute following opcode until counter specified by +// immediate value I reaches zero. Each execution decrement counter. If +// immediate value I is set to zero at the beginning of loop then looped +// instruction will not get executed. +// Actually, this instruction simply prepares the loop stacks for the above. +// The looping hardware takes care of the rest. +void loopi(const UDSPInstruction& opc) +{ + u16 cnt = opc.hex & 0xff; + u16 loop_pc = g_dsp.pc; + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } +} + + +// BLOOP $R, addrA +// 0000 0000 011r rrrr +// aaaa aaaa aaaa aaaa +// Repeatedly execute block of code starting at following opcode until +// counter specified by value from register $R reaches zero. Block ends at +// specified address addrA inclusive, ie. opcode at addrA is the last opcode +// included in loop. Counter is pushed on loop stack $st3, end of block address +// is pushed on loop stack $st2 and repeat address is pushed on call stack $st0. +// Up to 4 nested loops is allowed. +void bloop(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x1f; + u16 cnt = g_dsp.r[reg]; + u16 loop_pc = dsp_fetch_code(); + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + g_dsp.pc = loop_pc; + g_dsp.pc += opSize[dsp_peek_code()]; + } +} + +// BLOOPI #I, addrA +// 0001 0001 iiii iiii +// aaaa aaaa aaaa aaaa +// Repeatedly execute block of code starting at following opcode until +// counter specified by immediate value I reaches zero. Block ends at specified +// address addrA inclusive, ie. opcode at addrA is the last opcode included in +// loop. Counter is pushed on loop stack $st3, end of block address is pushed +// on loop stack $st2 and repeat address is pushed on call stack $st0. Up to 4 +// nested loops is allowed. +void bloopi(const UDSPInstruction& opc) +{ + u16 cnt = opc.hex & 0xff; + u16 loop_pc = dsp_fetch_code(); + + if (cnt) + { + dsp_reg_store_stack(0, g_dsp.pc); + dsp_reg_store_stack(2, loop_pc); + dsp_reg_store_stack(3, cnt); + } + else + { + g_dsp.pc = loop_pc; + g_dsp.pc += opSize[dsp_peek_code()]; + } +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntLoadStore.cpp b/Source/Core/DSPCore/Src/DspIntLoadStore.cpp new file mode 100644 index 0000000000..93396b43f8 --- /dev/null +++ b/Source/Core/DSPCore/Src/DspIntLoadStore.cpp @@ -0,0 +1,264 @@ +// Copyright (C) 2003-2009 Dolphin Project. + +// 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, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + +#include "DSPInterpreter.h" + +#include "gdsp_memory.h" +#include "gdsp_opcodes_helper.h" + +namespace DSPInterpreter { + +// SRS @M, $(0x18+S) +// 0010 1sss mmmm mmmm +// Store value from register $(0x18+S) to a memory pointed by address M. +// (8-bit sign extended). +// FIXME: Perform additional operation depending on destination register. +// Note: pc+=2 in duddie's doc seems wrong +void srs(const UDSPInstruction& opc) +{ + u8 reg = ((opc.hex >> 8) & 0x7) + 0x18; + u16 addr = (u16)(s16)(s8)opc.hex; + dsp_dmem_write(addr, g_dsp.r[reg]); +} + +// LRS $(0x18+D), @M +// 0010 0ddd mmmm mmmm +// Move value from data memory pointed by address M (8-bit sign +// extended) to register $(0x18+D). +// FIXME: Perform additional operation depending on destination register. +// Note: pc+=2 in duddie's doc seems wrong +void lrs(const UDSPInstruction& opc) +{ + u8 reg = ((opc.hex >> 8) & 0x7) + 0x18; + u16 addr = (u16)(s16)(s8)opc.hex; + g_dsp.r[reg] = dsp_dmem_read(addr); +} + +// LR $D, @M +// 0000 0000 110d dddd +// mmmm mmmm mmmm mmmm +// Move value from data memory pointed by address M to register $D. +// FIXME: Perform additional operation depending on destination register. +void lr(const UDSPInstruction& opc) +{ + u8 reg = opc.hex & DSP_REG_MASK; + u16 addr = dsp_fetch_code(); + u16 val = dsp_dmem_read(addr); + dsp_op_write_reg(reg, val); + dsp_conditional_extend_accum(reg); +} + +// SR @M, $S +// 0000 0000 111s ssss +// mmmm mmmm mmmm mmmm +// Store value from register $S to a memory pointed by address M. +// FIXME: Perform additional operation depending on destination register. +void sr(const UDSPInstruction& opc) +{ + u8 reg = opc.hex & DSP_REG_MASK; + u16 addr = dsp_fetch_code(); + u16 val = dsp_op_read_reg(reg); + dsp_dmem_write(addr, val); +} + +// SI @M, #I +// 0001 0110 mmmm mmmm +// iiii iiii iiii iiii +// Store 16-bit immediate value I to a memory location pointed by address +// M (M is 8-bit value sign extended). +void si(const UDSPInstruction& opc) +{ + u16 addr = (s8)opc.hex; + u16 imm = dsp_fetch_code(); + dsp_dmem_write(addr, imm); +} + +// LRR $D, @$S +// 0001 1000 0ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// FIXME: Perform additional operation depending on destination register. +void lrr(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); +} + +// LRRD $D, @$S +// 0001 1000 1ssd dddd +// Move value from data memory pointed by addressing register $S toregister $D. +// Decrement register $S. +// FIXME: Perform additional operation depending on destination register. +void lrrd(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); + dsp_decrement_addr_reg(sreg); +} + +// LRRI $D, @$S +// 0001 1001 0ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// Increment register $S. +// FIXME: Perform additional operation depending on destination register. +void lrri(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); + dsp_increment_addr_reg(sreg); +} + +// LRRN $D, @$S +// 0001 1001 1ssd dddd +// Move value from data memory pointed by addressing register $S to register $D. +// Add indexing register $(0x4+S) to register $S. +// FIXME: Perform additional operation depending on destination register. +void lrrn(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 5) & 0x3; + u8 dreg = opc.hex & 0x1f; + + u16 val = dsp_dmem_read(g_dsp.r[sreg]); + dsp_op_write_reg(dreg, val); + g_dsp.r[sreg] += g_dsp.r[DSP_REG_IX0 + sreg]; +} + +// SRR @$D, $S +// 0001 1010 0dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. +// FIXME: Perform additional operation depending on source register. +void srr(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); +} + +// SRRD @$D, $S +// 0001 1010 1dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Decrement register $D. +// FIXME: Perform additional operation depending on source register. +void srrd(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); + dsp_decrement_addr_reg(dreg); +} + +// SRRI @$D, $S +// 0001 1011 0dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Increment register $D. +// FIXME: Perform additional operation depending on source register. +void srri(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); + dsp_increment_addr_reg(dreg); +} + +// SRRN @$D, $S +// 0001 1011 1dds ssss +// Store value from source register $S to a memory location pointed by +// addressing register $D. Add DSP_REG_IX0 register to register $D. +// FIXME: Perform additional operation depending on source register. +void srrn(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 5) & 0x3; + u8 sreg = opc.hex & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_dmem_write(g_dsp.r[dreg], val); + g_dsp.r[dreg] += g_dsp.r[DSP_REG_IX0 + dreg]; +} + +// ILRR $acD.m, @$arS +// 0000 001d 0001 00ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. +void ilrr(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); +} + +// ILRRD $acD.m, @$arS +// 0000 001d 0001 01ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Decrement addressing register $arS. +void ilrrd(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); + + dsp_decrement_addr_reg(reg); +} + +// ILRRI $acD.m, @$S +// 0000 001d 0001 10ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Increment addressing register $arS. +void ilrri(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); + + dsp_increment_addr_reg(reg); +} + +// ILRRN $acD.m, @$arS +// 0000 001d 0001 11ss +// Move value from instruction memory pointed by addressing register +// $arS to mid accumulator register $acD.m. Add corresponding indexing +// register $ixS to addressing register $arS. +void ilrrn(const UDSPInstruction& opc) +{ + u16 reg = opc.hex & 0x3; + u16 dreg = DSP_REG_ACM0 + ((opc.hex >> 8) & 1); + + g_dsp.r[dreg] = dsp_imem_read(g_dsp.r[reg]); + + g_dsp.r[reg] += g_dsp.r[DSP_REG_IX0 + reg]; +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntMisc.cpp b/Source/Core/DSPCore/Src/DspIntMisc.cpp new file mode 100644 index 0000000000..ef1680321b --- /dev/null +++ b/Source/Core/DSPCore/Src/DspIntMisc.cpp @@ -0,0 +1,200 @@ +// Copyright (C) 2003-2009 Dolphin Project. + +// 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, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +#include "DSPInterpreter.h" + +#include "DSPCore.h" + +#include "gdsp_registers.h" +#include "gdsp_opcodes_helper.h" + +namespace DSPInterpreter { + +void unknown(const UDSPInstruction& opc) +{ + //_assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception"); + ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc.hex, g_dsp.pc); +} + +// MRR $D, $S +// 0001 11dd ddds ssss +// Move value from register $S to register $D. +// FIXME: Perform additional operation depending on destination register. +void mrr(const UDSPInstruction& opc) +{ + u8 sreg = opc.hex & 0x1f; + u8 dreg = (opc.hex >> 5) & 0x1f; + + u16 val = dsp_op_read_reg(sreg); + dsp_op_write_reg(dreg, val); +} + +// LRI $D, #I +// 0000 0000 100d dddd +// iiii iiii iiii iiii +// Load immediate value I to register $D. +// FIXME: Perform additional operation depending on destination register. + +// DSPSpy discovery: This, and possibly other instructions that load a register, +// has a different behaviour in S40 mode if loaded to AC0.M: The value gets sign extended +// to the whole accumulator! This does not happen in S16 mode. +void lri(const UDSPInstruction& opc) +{ + u8 reg = opc.hex & DSP_REG_MASK; + u16 imm = dsp_fetch_code(); + dsp_op_write_reg(reg, imm); + dsp_conditional_extend_accum(reg); +} + +// LRIS $(0x18+D), #I +// 0000 1ddd iiii iiii +// Load immediate value I (8-bit sign extended) to accumulator register. +// FIXME: Perform additional operation depending on destination register. +void lris(const UDSPInstruction& opc) +{ + u8 reg = ((opc.hex >> 8) & 0x7) + DSP_REG_AXL0; + u16 imm = (s8)opc.hex; + dsp_op_write_reg(reg, imm); + dsp_conditional_extend_accum(reg); +} + + +// TSTAXL $acR +// 1000 r001 xxxx xxxx +// r specifies one of the main accumulators. +// Definitely not a test instruction - it changes the accums. +// Not affected by m0/m2. Not affected by s16/s40. +void tstaxl(const UDSPInstruction& opc) +{ + // This is probably all wrong. + //u8 reg = (opc.hex >> 8) & 0x1; + //s16 val = dsp_get_ax_l(reg); + //Update_SR_Register16(val); +} + +// ADDARN $arD, $ixS +// 0000 0000 0001 ssdd +// Adds indexing register $ixS to an addressing register $arD. +void addarn(const UDSPInstruction& opc) +{ + u8 dreg = opc.hex & 0x3; + u8 sreg = (opc.hex >> 2) & 0x3; + + g_dsp.r[dreg] += (s16)g_dsp.r[DSP_REG_IX0 + sreg]; +} + +// NX +// 1000 -000 xxxx xxxx +// No operation, but can be extended with extended opcode. +void nx(const UDSPInstruction& opc) +{ + // This opcode is supposed to do nothing - it's used if you want to use + // an opcode extension but not do anything. At least according to duddie. +} + +//------------------------------------------------------------- +// DAR $arD ? +// 0000 0000 0000 01dd +// Decrement address register $arD. +void dar(const UDSPInstruction& opc) +{ + dsp_decrement_addr_reg(opc.hex & 0x3); +} + +// IAR $arD ? +// 0000 0000 0000 10dd +// Increment address register $arD. +void iar(const UDSPInstruction& opc) +{ + dsp_increment_addr_reg(opc.hex & 0x3); +} + +// SBCLR #I +// 0001 0011 0000 0iii +// bit of status register $sr. Bit number is calculated by adding 6 to +// immediate value I. +void sbclr(const UDSPInstruction& opc) +{ + u8 bit = (opc.hex & 0xff) + 6; + g_dsp.r[DSP_REG_SR] &= ~(1 << bit); +} + +// SBSET #I +// 0001 0010 0000 0iii +// Set bit of status register $sr. Bit number is calculated by adding 6 to +// immediate value I. +void sbset(const UDSPInstruction& opc) +{ + u8 bit = (opc.hex & 0xff) + 6; + g_dsp.r[DSP_REG_SR] |= (1 << bit); +} + + +// FIXME inside +// This is a bunch of flag setters, flipping bits in SR. So far so good, +// but it's harder to know exactly what effect they have. +// M0/M2 change the multiplier mode (it can multiply by 2 for free). +// +// SET16 changes something very important: see the LRI instruction above. +// Hermes' demo sets the following defaults: +// SET40 +// CLR15 +// M0 +void srbith(const UDSPInstruction& opc) +{ + switch ((opc.hex >> 8) & 0xf) + { + // M0 seems to be the default. M2 is used in functions in Zelda + // and then reset with M0 at the end. Like the other bits here, it's + // done around loops with lots of multiplications. + // I've confirmed with DSPSpy that they flip this bit. + case 0xa: // M2 + g_dsp.r[DSP_REG_SR] &= ~SR_MUL_MODIFY; + break; + case 0xb: // M0 + g_dsp.r[DSP_REG_SR] |= SR_MUL_MODIFY; + break; + + // If set, treat multiplicands as unsigned. + // If clear, treat them as signed. + case 0xc: // CLR15 + g_dsp.r[DSP_REG_SR] &= ~SR_MUL_UNSIGNED; + break; + case 0xd: // SET15 + g_dsp.r[DSP_REG_SR] |= SR_MUL_UNSIGNED; + break; + + // Automatic 40-bit sign extension when loading ACx.M. + // 40 seems to be the default. + // Confirmed these by using DSPSpy and copying the value of SR to R00 after setting. + case 0xe: // SET16 (really, clear SR's 0x4000) + g_dsp.r[DSP_REG_SR] &= ~SR_40_MODE_BIT; + break; + + case 0xf: // SET40 (really, set SR's 0x4000) + g_dsp.r[DSP_REG_SR] |= SR_40_MODE_BIT; + break; + + default: + break; + } +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp new file mode 100644 index 0000000000..0a2a0e46c2 --- /dev/null +++ b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp @@ -0,0 +1,486 @@ +// Copyright (C) 2003-2009 Dolphin Project. + +// 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, version 2.0. + +// 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 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +// Additional copyrights go to Duddie and Tratax (c) 2004 + + +// Multiplier and product register control + +#include "DSPInterpreter.h" + +#include "gdsp_condition_codes.h" +#include "gdsp_opcodes_helper.h" +#include "gdsp_registers.h" + +namespace DSPInterpreter { + +// CLRP +// 1000 0100 xxxx xxxx +// Clears product register $prod. +void clrp(const UDSPInstruction& opc) +{ + // Magic numbers taken from duddie's doc + // These are probably a bad idea to put here. + g_dsp.r[0x14] = 0x0000; + g_dsp.r[0x15] = 0xfff0; + g_dsp.r[0x16] = 0x00ff; + g_dsp.r[0x17] = 0x0010; +} + +// MOVP $acD +// 0110 111d xxxx xxxx +// Moves multiply product from $prod register to accumulator $acD register. +void movp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_get_long_prod(); + dsp_set_long_acc(dreg, prod); + + Update_SR_Register64(prod); +} + +// MOVNP $acD +// 0111 111d xxxx xxxx +// Moves negative of multiply product from $prod register to accumulator +// $acD register. +void movnp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_get_long_prod(); + s64 acc = -prod; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// ADDPAXZ $acD, $axS +// 1111 10sd xxxx xxxx +// Adds secondary accumulator $axS to product register and stores result +// in accumulator register. Low 16-bits of $acD ($acD.l) are set to 0. +void addpaxz(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + + s64 prod = dsp_get_long_prod() & ~0x0ffff; + s64 ax_h = dsp_get_long_acx(sreg); + s64 acc = (prod + ax_h) & ~0x0ffff; + + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + +// MOVPZ $acD +// 1111 111d xxxx xxxx +// Moves multiply product from $prod register to accumulator $acD +// register and sets $acD.l to 0 +void movpz(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + // overwrite acc and clear low part + s64 prod = dsp_get_long_prod(); + s64 acc = prod & ~0xffff; + dsp_set_long_acc(dreg, acc); + + Update_SR_Register64(acc); +} + + +// MULC $acS.m, $axT.h +// 110s t000 xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axS.h of +// secondary accumulator $axS (treat them both as signed). +void mulc(const UDSPInstruction& opc) +{ + // math new prod + u8 sreg = (opc.hex >> 11) & 0x1; + u8 treg = (opc.hex >> 12) & 0x1; + + s64 prod = dsp_get_acc_m(sreg) * dsp_get_ax_h(treg) * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +// MULCMVZ $acS.m, $axT.h, $acR +// 110s t01r xxxx xxxx +// (fixed possible bug in duddie's description, s->t) +// Multiply mid part of accumulator register $acS.m by high part $axT.h of +// secondary accumulator $axT (treat them both as signed). Move product +// register before multiplication to accumulator $acR, set low part of +// accumulator $acR.l to zero. +void mulcmvz(const UDSPInstruction& opc) +{ + s64 TempProd = dsp_get_long_prod(); + + // update prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + s64 Prod = (s64)dsp_get_acc_m(sreg) * (s64)dsp_get_ax_h(treg) * GetMultiplyModifier(); + dsp_set_long_prod(Prod); + + // update acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acc = TempProd & ~0xffff; // clear lower 4 bytes + dsp_set_long_acc(rreg, acc); + + Update_SR_Register64(acc); +} + +// MULCMV $acS.m, $axT.h, $acR +// 110s t11r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axT.h of +// secondary accumulator $axT (treat them both as signed). Move product +// register before multiplication to accumulator $acR. +// possible mistake in duddie's doc axT.h rather than axS.h +void mulcmv(const UDSPInstruction& opc) +{ + s64 tempProd = dsp_get_long_prod(); + + // update prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + s64 prod = (s64)dsp_get_acc_m(sreg) * (s64)dsp_get_ax_h(treg) * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + // update acc + u8 rreg = (opc.hex >> 8) & 0x1; + dsp_set_long_acc(rreg, tempProd); + + Update_SR_Register64(tempProd); +} + +// MULCAC $acS.m, $axT.h, $acR +// 110s t10r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axS.h of +// secondary accumulator $axS (treat them both as signed). Add product +// register before multiplication to accumulator $acR. +void mulcac(const UDSPInstruction& opc) +{ + s64 TempProd = dsp_get_long_prod(); + + // update prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + s64 Prod = (s64)dsp_get_acc_m(sreg) * (s64)dsp_get_ax_h(treg) * GetMultiplyModifier(); + dsp_set_long_prod(Prod); + + // update acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acc = TempProd + dsp_get_long_acc(rreg); + dsp_set_long_acc(rreg, acc); + + Update_SR_Register64(acc); +} + + +// MUL $axS.l, $axS.h +// 1001 s000 xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed). +void mul(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 11) & 0x1; + s64 prod = (s64)dsp_get_ax_h(sreg) * (s64)dsp_get_ax_l(sreg) * GetMultiplyModifier(); + + dsp_set_long_prod(prod); + + // FIXME: no update in duddie's docs + Update_SR_Register64(prod); +} + +// MULAC $axS.l, $axS.h, $acR +// 1001 s10r xxxx xxxx +// Add product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). +void mulac(const UDSPInstruction& opc) +{ + // add old prod to acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + dsp_set_long_acc(rreg, acR); + + // calculate new prod + u8 sreg = (opc.hex >> 11) & 0x1; + s64 prod = dsp_get_ax_l(sreg) * dsp_get_ax_h(sreg) * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + // FIXME: no update in duddie's docs + Update_SR_Register64(prod); +} + +// MULMV $axS.l, $axS.h, $acR +// 1001 s11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). +void mulmv(const UDSPInstruction& opc) +{ + u8 rreg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 11) & 0x1); + s64 prod = dsp_get_long_prod(); + s64 acc = prod; + dsp_set_long_acc(rreg, acc); + + s64 val1 = (s16)g_dsp.r[sreg + DSP_REG_AXL0]; + s64 val2 = (s16)g_dsp.r[sreg + DSP_REG_AXH0]; + + prod = val1 * val2 * GetMultiplyModifier(); + + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +// MULMVZ $axS.l, $axS.h, $acR +// 1001 s01r xxxx xxxx +// Move product register to accumulator register $acR and clear low part +// of accumulator register $acR.l. Multiply low part $axS.l of secondary +// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat +// them both as signed). +void mulmvz(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 11) & 0x1; + u8 rreg = (opc.hex >> 8) & 0x1; + + // overwrite acc and clear low part + s64 prod = dsp_get_long_prod(); + s64 acc = prod & ~0xffff; + dsp_set_long_acc(rreg, acc); + + // math prod + prod = (s64)(s16)g_dsp.r[DSP_REG_AXL0 + sreg] * (s64)(s16)g_dsp.r[DSP_REG_AXH0 + sreg] * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +// MULX $ax0.S, $ax1.T +// 101s t000 xxxx xxxx +// Multiply one part $ax0 by one part $ax1 (treat them both as signed). +// Part is selected by S and T bits. Zero selects low part, one selects high part. +void mulx(const UDSPInstruction& opc) +{ + u8 sreg = ((opc.hex >> 12) & 0x1); + u8 treg = ((opc.hex >> 11) & 0x1); + + s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = val1 * val2 * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +// MULXAC $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Add product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and +// T bits. Zero selects low part, one selects high part. +void mulxac(const UDSPInstruction& opc) +{ + // add old prod to acc + u8 rreg = (opc.hex >> 8) & 0x1; + s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + dsp_set_long_acc(rreg, acR); + + // math new prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + + s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = val1 * val2 * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +// MULXMV $ax0.S, $ax1.T, $acR +// 101s t11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and +// T bits. Zero selects low part, one selects high part. +void mulxmv(const UDSPInstruction& opc) +{ + // add old prod to acc + u8 rreg = ((opc.hex >> 8) & 0x1); + s64 acR = dsp_get_long_prod(); + dsp_set_long_acc(rreg, acR); + + // math new prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + + s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = val1 * val2 * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +// MULXMV $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Move product register to accumulator register $acR and clear low part +// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 (treat +// them both as signed). Part is selected by S and T bits. Zero selects low part, +// one selects high part. +void mulxmvz(const UDSPInstruction& opc) +{ + // overwrite acc and clear low part + u8 rreg = (opc.hex >> 8) & 0x1; + s64 prod = dsp_get_long_prod(); + s64 acc = prod & ~0xffff; + dsp_set_long_acc(rreg, acc); + + // math prod + u8 sreg = (opc.hex >> 12) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + + s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + prod = val1 * val2 * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +// MADDX ax0.S ax1.T +// 1110 00st xxxx xxxx +// Multiply one part of secondary accumulator $ax0 (selected by S) by +// one part of secondary accumulator $ax1 (selected by T) (treat them both as +// signed) and add result to product register. +void maddx(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 treg = (opc.hex >> 8) & 0x1; + + s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_get_long_prod(); + prod += val1 * val2 * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +// MSUBX $(0x18+S*2), $(0x19+T*2) +// 1110 01st xxxx xxxx +// Multiply one part of secondary accumulator $ax0 (selected by S) by +// one part of secondary accumulator $ax1 (selected by T) (treat them both as +// signed) and subtract result from product register. +void msubx(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 treg = (opc.hex >> 8) & 0x1; + + s64 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + s64 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + + s64 prod = dsp_get_long_prod(); + prod -= val1 * val2 * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +// MADDC $acS.m, $axT.h +// 1110 10st xxxx xxxx +// Multiply middle part of accumulator $acS.m by high part of secondary +// accumulator $axT.h (treat them both as signed) and add result to product +// register. +void maddc(const UDSPInstruction& opc) +{ + u32 sreg = (opc.hex >> 9) & 0x1; + u32 treg = (opc.hex >> 8) & 0x1; + + s64 val1 = dsp_get_acc_m(sreg); + s64 val2 = dsp_get_ax_h(treg); + + s64 prod = dsp_get_long_prod(); + prod += val1 * val2 * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +// MSUBC $acS.m, $axT.h +// 1110 11st xxxx xxxx +// Multiply middle part of accumulator $acS.m by high part of secondary +// accumulator $axT.h (treat them both as signed) and subtract result from +// product register. +void msubc(const UDSPInstruction& opc) +{ + u32 sreg = (opc.hex >> 9) & 0x1; + u32 treg = (opc.hex >> 8) & 0x1; + + s64 val1 = dsp_get_acc_m(sreg); + s64 val2 = dsp_get_ax_h(treg); + + s64 prod = dsp_get_long_prod(); + prod -= val1 * val2 * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + + + +// MADD $axS.l, $axS.h +// 1111 001s xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed) and add +// result to product register. +void madd(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_get_long_prod(); + prod += (s64)dsp_get_ax_l(sreg) * (s64)dsp_get_ax_h(sreg) * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +// MSUB $axS.l, $axS.h +// 1111 011s xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed) and +// subtract result from product register. +void msub(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 8) & 0x1; + + s64 prod = dsp_get_long_prod(); + prod -= (s64)dsp_get_ax_l(sreg) * (s64)dsp_get_ax_h(sreg) * GetMultiplyModifier(); + dsp_set_long_prod(prod); + + Update_SR_Register64(prod); +} + +} // namespace diff --git a/Source/Core/DSPCore/Src/SConscript b/Source/Core/DSPCore/Src/SConscript index 6f577930b0..e122e5fa85 100644 --- a/Source/Core/DSPCore/Src/SConscript +++ b/Source/Core/DSPCore/Src/SConscript @@ -13,7 +13,11 @@ files = [ "gdsp_memory.cpp", "gdsp_registers.cpp", "DSPAnalyzer.cpp", - "DSPInterpreter.cpp", + "DSPIntArithmetic.cpp", + "DSPIntBranch.cpp", + "DSPIntLoadStore.cpp", + "DSPIntMisc.cpp", + "DSPIntMultiplier.cpp", "DSPJit.cpp", "DSPCodeUtil.cpp", "LabelMap.cpp", diff --git a/Source/Core/DSPCore/Src/gdsp_aram.cpp b/Source/Core/DSPCore/Src/gdsp_aram.cpp index 1c6955e98b..1ca84a3c5d 100644 --- a/Source/Core/DSPCore/Src/gdsp_aram.cpp +++ b/Source/Core/DSPCore/Src/gdsp_aram.cpp @@ -96,7 +96,6 @@ u16 dsp_read_aram() // TODO: Take ifx GAIN into account. - // check for loop if (Address >= EndAddress) { diff --git a/Source/Core/DSPCore/Src/gdsp_condition_codes.cpp b/Source/Core/DSPCore/Src/gdsp_condition_codes.cpp index a4f3767a62..b7130886e0 100644 --- a/Source/Core/DSPCore/Src/gdsp_condition_codes.cpp +++ b/Source/Core/DSPCore/Src/gdsp_condition_codes.cpp @@ -95,7 +95,7 @@ inline bool isSign() { } inline bool isZero() { - return (g_dsp.r[DSP_REG_SR] & 0x04); + return (g_dsp.r[DSP_REG_SR] & 0x04) ? true : false; } //see gdsp_registers.h for flags diff --git a/Source/Core/DSPCore/Src/gdsp_ext_op.cpp b/Source/Core/DSPCore/Src/gdsp_ext_op.cpp index e352899839..2ec0ec310e 100644 --- a/Source/Core/DSPCore/Src/gdsp_ext_op.cpp +++ b/Source/Core/DSPCore/Src/gdsp_ext_op.cpp @@ -255,7 +255,7 @@ void dsp_op_ext_s(const UDSPInstruction& opc) void dsp_op_ext_l(const UDSPInstruction& opc) { u8 sreg = opc.hex & 0x3; - u8 dreg = ((opc.hex >> 3) & 0x7) + 0x18; + u8 dreg = ((opc.hex >> 3) & 0x7) + DSP_REG_AXL0; u16 val = dsp_dmem_read(g_dsp.r[sreg]); g_dsp.r[dreg] = val; @@ -289,7 +289,7 @@ void dsp_op_ext_ls_pro(const UDSPInstruction& opc) void dsp_op_ext_ls_epi(const UDSPInstruction& opc) { - u8 dreg = ((opc.hex >> 4) & 0x3) + 0x18; + u8 dreg = ((opc.hex >> 4) & 0x3) + DSP_REG_AXL0; u16 val = dsp_dmem_read(g_dsp.r[0x00]); dsp_op_write_reg(dreg, val); @@ -400,14 +400,11 @@ void dsp_op_ext_ops_pro(const UDSPInstruction& opc) case 0x09: case 0x0a: case 0x0b: - - if (opc.hex & 0x2) { + if (opc.hex & 0x2) dsp_op_ext_sl_pro(opc.hex); - } - else { + else dsp_op_ext_ls_pro(opc.hex); - } - + break; case 0x0c: @@ -423,26 +420,24 @@ void dsp_op_ext_ops_pro(const UDSPInstruction& opc) void dsp_op_ext_ops_epi(const UDSPInstruction& opc) { if ((opc.hex & 0xFF) == 0) - { return; - } switch ((opc.hex >> 4) & 0xf) { - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - if (opc.hex & 0x2) - { - dsp_op_ext_sl_epi(opc.hex); - } - else - { - dsp_op_ext_ls_epi(opc.hex); - } - break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + if (opc.hex & 0x2) + { + dsp_op_ext_sl_epi(opc.hex); + } + else + { + dsp_op_ext_ls_epi(opc.hex); + } + break; - return; + return; } } diff --git a/Source/Core/DSPCore/Src/gdsp_interface.cpp b/Source/Core/DSPCore/Src/gdsp_interface.cpp index 225815c80f..84125c939f 100644 --- a/Source/Core/DSPCore/Src/gdsp_interface.cpp +++ b/Source/Core/DSPCore/Src/gdsp_interface.cpp @@ -35,8 +35,6 @@ #include "gdsp_interpreter.h" #include "gdsp_interface.h" -// #include "Tools.h" - void gdsp_dma(); Common::CriticalSection g_CriticalSection; @@ -119,8 +117,6 @@ u16 gdsp_mbox_read_l(u8 mbx) void gdsp_ifx_write(u16 addr, u16 val) { - addr &= 0xff; - switch (addr & 0xff) { case 0xfb: // DIRQ @@ -137,7 +133,7 @@ void gdsp_ifx_write(u16 addr, u16 val) break; case 0xcb: // DSBL - gdsp_ifx_regs[addr] = val; + gdsp_ifx_regs[addr & 0xFF] = val; gdsp_dma(); gdsp_ifx_regs[DSP_DSCR] &= ~0x0004; break; @@ -146,7 +142,7 @@ void gdsp_ifx_write(u16 addr, u16 val) case 0xce: case 0xcf: case 0xc9: - gdsp_ifx_regs[addr] = val; + gdsp_ifx_regs[addr & 0xFF] = val; break; default: @@ -154,7 +150,7 @@ void gdsp_ifx_write(u16 addr, u16 val) DEBUG_LOG(DSPLLE, "%04x MW %s (%04x)\n", g_dsp.pc, reg_names[addr - 0xa0], val); else DEBUG_LOG(DSPLLE, "%04x MW %04x (%04x)\n", g_dsp.pc, addr, val);*/ - gdsp_ifx_regs[addr] = val; + gdsp_ifx_regs[addr & 0xFF] = val; break; } } @@ -162,42 +158,30 @@ void gdsp_ifx_write(u16 addr, u16 val) u16 gdsp_ifx_read(u16 addr) { - u16 val; - - addr &= 0xff; - switch (addr & 0xff) { case 0xfc: // DMBH - val = gdsp_mbox_read_h(GDSP_MBOX_DSP); - break; + return gdsp_mbox_read_h(GDSP_MBOX_DSP); case 0xfe: // CMBH - val = gdsp_mbox_read_h(GDSP_MBOX_CPU); - break; + return gdsp_mbox_read_h(GDSP_MBOX_CPU); case 0xff: // CMBL - val = gdsp_mbox_read_l(GDSP_MBOX_CPU); - break; + return gdsp_mbox_read_l(GDSP_MBOX_CPU); case 0xc9: - val = gdsp_ifx_regs[addr]; - break; + return gdsp_ifx_regs[addr & 0xFF]; case 0xdd: - val = dsp_read_aram(); - break; + return dsp_read_aram(); default: - val = gdsp_ifx_regs[addr]; + return gdsp_ifx_regs[addr & 0xFF]; /* if ((addr & 0xff) >= 0xc0 && reg_names[addr & 0x3f]) printf("%04x MR %s (%04x)\n", g_dsp.pc, reg_names[addr & 0x3f], val); else printf("%04x MR %04x (%04x)\n", g_dsp.pc, addr, val);*/ - break; } - - return val; } @@ -206,7 +190,7 @@ void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size) UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false); u8* dst = ((u8*)g_dsp.iram); - for (u32 i = 0; i < size; i += 2) + for (int i = 0; i < size; i += 2) { // TODO : this may be different on Wii. *(u16*)&dst[dsp_addr + i] = Common::swap16(*(const u16*)&g_dsp.cpu_ram[(addr + i) & 0x0fffffff]); diff --git a/Source/Core/DSPCore/Src/gdsp_opcodes_helper.h b/Source/Core/DSPCore/Src/gdsp_opcodes_helper.h index 2a071bb563..00f8d7c6b7 100644 --- a/Source/Core/DSPCore/Src/gdsp_opcodes_helper.h +++ b/Source/Core/DSPCore/Src/gdsp_opcodes_helper.h @@ -1,6 +1,6 @@ /*==================================================================== - filename: opcodes.h + filename: gdsp_opcodes_helper.h project: GameCube DSP Tool (gcdsp) created: 2005.03.04 mail: duddie@walla.com @@ -90,10 +90,10 @@ inline void dsp_increment_addr_reg(int reg) inline u16 dsp_op_read_reg(u8 reg) { switch (reg & 0x1f) { - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: + 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]; @@ -111,10 +111,10 @@ inline void dsp_op_write_reg(u8 reg, u16 val) break; // Stack registers. - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: + case DSP_REG_ST0: + case DSP_REG_ST1: + case DSP_REG_ST2: + case DSP_REG_ST3: dsp_reg_store_stack(reg - 0x0c, val); break; @@ -140,26 +140,19 @@ inline void dsp_conditional_extend_accum(u8 reg) } } - - // --------------------------------------------------------------------------------------- -// // --- prod -// // --------------------------------------------------------------------------------------- - inline s64 dsp_get_long_prod() { #if PROFILE ProfilerAddDelta(g_dsp.err_pc, 1); #endif - s64 val; - s64 low_prod; - val = (s8)g_dsp.r[0x16]; + s64 val = (s8)g_dsp.r[0x16]; val <<= 32; - low_prod = g_dsp.r[0x15]; + s64 low_prod = g_dsp.r[0x15]; low_prod += g_dsp.r[0x17]; low_prod <<= 16; low_prod |= g_dsp.r[0x14]; @@ -167,9 +160,8 @@ inline s64 dsp_get_long_prod() return val; } -// For accurate emulation, this is wrong - it should take the two multiplicands -// as input and set the two mid stages accordingly. most likely it's doing something -// pretty simple. +// 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 @@ -195,8 +187,8 @@ inline s64 dsp_get_long_acc(int reg) #endif _assert_(reg < 2); - s64 high = (s64)(s8)g_dsp.r[0x10 + reg] << 32; - u32 mid_low = ((u32)g_dsp.r[0x1e + reg] << 16) | g_dsp.r[0x1c + reg]; + 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; } @@ -207,32 +199,32 @@ inline void dsp_set_long_acc(int _reg, s64 val) #endif _assert_(_reg < 2); - g_dsp.r[0x1c + _reg] = (u16)val; + g_dsp.r[DSP_REG_ACL0 + _reg] = (u16)val; val >>= 16; - g_dsp.r[0x1e + _reg] = (u16)val; + g_dsp.r[DSP_REG_ACM0 + _reg] = (u16)val; val >>= 16; - g_dsp.r[0x10 + _reg] = (u16)(s16)(s8)(u8)val; + g_dsp.r[DSP_REG_ACH0 + _reg] = (u16)(s16)(s8)(u8)val; } inline s16 dsp_get_acc_l(int _reg) { _assert_(_reg < 2); - return g_dsp.r[0x1c + _reg]; + return g_dsp.r[DSP_REG_ACL0 + _reg]; } inline s16 dsp_get_acc_m(int _reg) { _assert_(_reg < 2); - return g_dsp.r[0x1e + _reg]; + return g_dsp.r[DSP_REG_ACM0 + _reg]; } inline s16 dsp_get_acc_h(int _reg) { _assert_(_reg < 2); - return g_dsp.r[0x10 + _reg]; + return g_dsp.r[DSP_REG_ACH0 + _reg]; } @@ -240,30 +232,26 @@ inline s16 dsp_get_acc_h(int _reg) // --- AX - extra accumulators (32-bit) // --------------------------------------------------------------------------------------- -inline s64 dsp_get_long_acx(int _reg) +inline s32 dsp_get_long_acx(int _reg) { #if PROFILE ProfilerAddDelta(g_dsp.err_pc, 1); #endif _assert_(_reg < 2); - s64 val = (s16)g_dsp.r[0x1a + _reg]; - val <<= 16; - s64 low_acc = g_dsp.r[0x18 + _reg]; - val |= low_acc; - return val; + 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[0x18 + _reg]; + 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[0x1a + _reg]; + return (s16)g_dsp.r[DSP_REG_AXH0 + _reg]; } #endif diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Jac.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Jac.cpp index 4e666ae964..7d471565b3 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Jac.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Jac.cpp @@ -129,9 +129,9 @@ void CUCode_Jac::ExecuteList() } break; - // ============================================================================== - // UpdateDSPChannel - // ============================================================================== + // ============================================================================== + // UpdateDSPChannel + // ============================================================================== case 0x2000: case 0x4000: // animal crossing { @@ -153,7 +153,7 @@ void CUCode_Jac::ExecuteList() break; } - // sync, we are rdy + // sync, we are ready. m_rMailHandler.PushMail(DSP_SYNC); m_rMailHandler.PushMail(0xF3550000 | sync); } diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp index d52e5bc91b..13e0c6020a 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCodes.cpp @@ -40,13 +40,6 @@ IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler) case 0x65d6cc6f: // CARD return new CUCode_CARD(_rMailHandler); - case 0x088e38a5: // IPL - JAP - case 0xd73338cf: // IPL - case 0x42f64ac4: // Luigi (after fix) - case 0x4be6a5cb: // AC, Pikmin (after fix) - INFO_LOG(CONSOLE, "JAC ucode chosen\n"); - return new CUCode_Jac(_rMailHandler); - case 0x3ad3b7ac: // Naruto3 case 0x3daf59b9: // Alien Hominid case 0x4e8a8b21: // spdemo, ctaxi, 18 wheeler, disney, monkeyball2,cubivore,puzzlecollection,wario, @@ -59,6 +52,13 @@ IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler) INFO_LOG(CONSOLE, "AX ucode chosen, yay!\n"); return new CUCode_AX(_rMailHandler); + case 0x088e38a5: // IPL - JAP + case 0xd73338cf: // IPL + case 0x42f64ac4: // Luigi (after fix) + case 0x4be6a5cb: // AC, Pikmin (after fix) + INFO_LOG(CONSOLE, "JAC ucode chosen\n"); + return new CUCode_Jac(_rMailHandler); + case 0x6CA33A6D: // DK Jungle Beat case 0x86840740: // zelda case 0x56d36052: // mario @@ -83,8 +83,8 @@ IUCode* UCodeFactory(u32 _CRC, CMailHandler& _rMailHandler) return new CUCode_AXWii(_rMailHandler, _CRC); default: - PanicAlert("Unknown ucode (CRC = %08x) - forcing AX/AXWii", _CRC); - if(g_dspInitialize.bWii) + PanicAlert("DSPHLE: Unknown ucode (CRC = %08x) - forcing AX/AXWii.\n\nTry LLE plugin if this is homebrew.", _CRC); + if (g_dspInitialize.bWii) return new CUCode_AXWii(_rMailHandler, _CRC); return new CUCode_AX(_rMailHandler); }