home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ST-Computer Leser 2002 January
/
STC_CD_01_2002.iso
/
JAGUAR
/
JAG_SRC
/
SOURCE
/
DSP.C
< prev
next >
Wrap
C/C++ Source or Header
|
2001-07-13
|
29KB
|
817 lines
////////////////////////////////////////////////////////////////////////////////
// Jagulator: Atari Jaguar Console Emulation Project (dsp.c)
// -----------------------------------------------------------------------------
// Jagulator is the Copyright (c) RealityMan 1998-2001 and is provided "as is"
// without any expressed or implied warranty. I have no Trademarks, Legal or
// otherwise. Atari, Jaguar and the Atari Logo are copyright Hasbro Inc. All
// other Copyrights and Trademarks are acknowledged. This project is in no way
// linked to Atari/Hasbro or other associated Atari companies.
//
// 07-07-2001 GH: New Source, Rewritten for Release 1.5.0
// 00-00-0000 GH: All Previous Source Considered as Development Code Only
#include "core.h"
////////////////////////////////////////////////////////////////////////////////
// Globals
DSPSTATE dst; // DSP State Information
dword DincPC; // PC Increment Flag
dword DjmpPC; // PC Jump dst.destination
dword Dbranch; // Branch Flag
////////////////////////////////////////////////////////////////////////////////
// DSP Processor Emulation
DWORD ExecDSP( LPVOID lpParam )
{
dword iw; // Instruction Word
sdword tmpW;
// The DSP Program Counter is directly set via the memory routines
// so it does not explicitly need to be obtained here.
while( dst.dspActive )
{
iw = mem_readword( dst.pc );
dst.src = (iw & 0x03E0) >> 5; // Get Source
dst.dest = (iw & 0x001F); // Get Destination
switch( iw >> 10 )
{
case ADD:
__asm {
mov ecx,[dst.src]
mov edx,[ecx*4+dst.arb]
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
add eax,edx
mov [ecx*4+dst.arb],eax
mov ecx,1
jc d_addend
mov ecx,0
d_addend:
mov [dst.c],ecx
};
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case ADDC:
__asm {
clc
mov ecx,[dst.c]
jcxz d_addc
stc
d_addc:
mov ecx,[dst.src]
mov edx,[ecx*4+dst.arb]
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
adc eax,edx
mov [ecx*4+dst.arb],eax
mov ecx,1
jc d_addcend
mov ecx,0
d_addcend:
mov [dst.c],ecx
};
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case ADDQ:
__asm {
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
mov edx,[dst.src]
add eax,edx
mov [ecx*4+dst.arb],eax
mov ecx,1
jc d_addqend
mov ecx,0
d_addqend:
mov [dst.c],ecx
};
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case ADDQT:
__asm {
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
mov edx,[dst.src]
add eax,edx
mov [ecx*4+dst.arb],eax
};
break;
case SUB:
__asm {
mov ecx,[dst.src]
mov edx,[ecx*4+dst.arb]
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
sub eax,edx
mov [ecx*4+dst.arb],eax
mov ecx,1
jc d_subend
mov ecx,0
d_subend:
mov [dst.c],ecx
};
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case SUBC:
__asm {
clc
mov ecx,[dst.c]
jcxz d_subc
stc
d_subc:
mov ecx,[dst.src]
mov edx,[ecx*4+dst.arb]
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
sbb eax,edx
mov [ecx*4+dst.arb],eax
mov ecx,1
jc d_subcend
mov ecx,0
d_subcend:
mov [dst.c],ecx
};
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case SUBQ:
__asm {
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
mov edx,[dst.src]
sub eax,edx
mov [ecx*4+dst.arb],eax
mov ecx,1
jc d_subqend
mov ecx,0
d_subqend:
mov [dst.c],ecx
};
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case SUBQT:
__asm {
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
mov edx,[dst.src]
sub eax,edx
mov [ecx*4+dst.arb],eax
};
break;
case NEG:
__asm {
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
neg eax
mov [ecx*4+dst.arb],eax
mov ecx,1
jc d_negend
mov ecx,0
d_negend:
mov [dst.c],ecx
};
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case AND:
dst.arb[dst.dest] &= dst.arb[dst.src];
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case OR:
dst.arb[dst.dest] |= dst.arb[dst.src];
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case XOR:
dst.arb[dst.dest] ^= dst.arb[dst.src];
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case NOT:
dst.arb[dst.dest] = dst.arb[dst.dest] ^ 0xFFFFFFFF;
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case BTST:
__asm {
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
mov ecx,[dst.src]
bt eax,ecx
mov ecx,1
jc d_btstend
mov ecx,0
d_btstend:
mov [dst.z],ecx
};
break;
case BSET:
__asm {
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
mov edx,[dst.src]
bts eax,edx
mov [ecx*4+dst.arb],eax
};
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case BCLR:
__asm {
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
mov edx,[dst.src]
btr eax,edx
mov [ecx*4+dst.arb],eax
};
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case MULT:
dst.arb[dst.dest] = (sdword)((word)dst.arb[dst.src] *
(word)dst.arb[dst.dest] );
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case IMULT:
dst.arb[dst.dest] = (sdword)((sword)dst.arb[dst.src] *
(sword)dst.arb[dst.dest] );
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case IMULTN:
// Like IMULT but result not written back to dst.arb[dst.dest]
// but to an accumulator. Used as first part of multiply/accumulate group.
dst.acc = (sdword)((sword)dst.arb[dst.src] *
(sword)dst.arb[dst.dest] );
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case RESMAC:
// Write result register to Register Rn
// Used as last part of multiply/accumulate group.
dst.arb[dst.dest] = dst.acc;
break;
case IMACN:
// Like IMULT but product is added to the previous arithmetic operation.
// Intended to be used after IMULTN.
dst.acc += (sdword)((sword)dst.arb[dst.src] *
(sword)dst.arb[dst.dest] );
break;
case DIV:
if( dst.div16 )
{
#ifdef DEBUG
print( YEL"DSP DIVIDE 16.16 REQUIRED !!!!\n" );
#endif
}
else
{
(dword)dst.arb[dst.dest] = (dword)dst.arb[dst.dest] /
(dword)dst.arb[dst.src];
dst.divrem = (dword)dst.arb[dst.dest] % (dword)dst.arb[dst.src];
}
break;
case ABS:
if( dst.arb[dst.dest] == 0x80000000 )
dst.n = 1;
else
{
if( dst.arb[dst.dest] < 0 )
{
__asm {
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
neg eax
mov [ecx*4+dst.arb],eax
};
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = 0;
dst.c = 1;
}
}
break;
case SH:
// NOTE: Watch the values here carefully
if( dst.arb[dst.src] >= 0 ) // Shift Right
{
dst.c = dst.arb[dst.dest] & 0x01;
tmpW = dst.arb[dst.src];
__asm {
mov edx,[dst.dest]
mov eax,[edx*4+dst.arb]
mov ecx,[tmpW]
shr eax,cl
mov [edx*4+dst.arb],eax
};
}
else // Shift Left
{
dst.c = (dst.arb[dst.dest] >> 31) & 0x01;
// Fix donated by YaK
tmpW = (0xFFFFFFFF - dst.arb[dst.src]) + 1;
__asm {
mov edx,[dst.dest]
mov eax,[edx*4+dst.arb]
mov ecx,[tmpW]
shl eax,cl
mov [edx*4+dst.arb],eax
};
}
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case SHLQ:
dst.c = (dst.arb[dst.dest] >> 31) & 0x01;
dst.arb[dst.dest] <<= (32 - dst.src);
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case SHRQ:
dst.c = dst.arb[dst.dest] & 0x01;
dst.arb[dst.dest] >>= (32 - dst.src);
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case SHA:
// NOTE: Watch the values here carefully
if( dst.arb[dst.src] >= 0 ) // Shift Right
{
dst.c = dst.arb[dst.dest] & 0x01;
tmpW = dst.arb[dst.src];
__asm {
mov edx,[dst.dest]
mov eax,[edx*4+dst.arb]
mov ecx,[tmpW]
sar eax,cl
mov [edx*4+dst.arb],eax
};
}
else // Shift Left
{
dst.c = (dst.arb[dst.dest] >> 31) & 0x01;
// Fix donated by YaK
tmpW = (0xFFFFFFFF - dst.arb[dst.src]) + 1;
__asm {
mov edx,[dst.dest]
mov eax,[edx*4+dst.arb]
mov ecx,[tmpW]
shl eax,cl
mov [edx*4+dst.arb],eax
};
}
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case SHARQ:
dst.c = (dst.arb[dst.dest] & 0x01);
tmpW = dst.arb[dst.dest];
__asm {
mov eax,[tmpW]
mov ecx,[dst.src]
sar eax,cl
mov [tmpW],eax
};
dst.arb[dst.dest] = tmpW;
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case ROR:
dst.c = (dst.arb[dst.dest] >> 31) & 0x01;
__asm {
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
mov edx,[dst.src]
mov ecx,[edx*4+dst.arb]
and ecx,0x1F
ror eax,cl
mov ecx,[dst.dest]
mov [ecx*4+dst.arb],eax
};
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case RORQ:
dst.c = (dst.arb[dst.dest] >> 31) & 0x01;
tmpW = dst.arb[dst.dest];
__asm {
mov eax,[tmpW]
mov ecx,[dst.src]
ror eax,cl
mov [tmpW],eax
};
dst.arb[dst.dest] = tmpW;
dst.z = (dst.arb[dst.dest] == 0) ? 1 : 0;
dst.n = (dst.arb[dst.dest] < 0) ? 1 : 0;
break;
case CMP:
__asm {
mov ecx,[dst.src]
mov edx,[ecx*4+dst.arb]
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
sub eax,edx
lahf
mov [tmpW],eax
};
dst.c = (tmpW & 0x0100) ? 1 : 0;
dst.z = (tmpW & 0x4000) ? 1 : 0;
dst.n = (tmpW & 0x8000) ? 1 : 0;
break;
case CMPQ:
__asm {
mov edx,[dst.src]
bt edx,4
jnc d_cmpq
bts edx,31
d_cmpq:
mov ecx,[dst.dest]
mov eax,[ecx*4+dst.arb]
sub eax,edx
lahf
mov [tmpW],eax
};
dst.c = (tmpW & 0x0100) ? 1 : 0;
dst.z = (tmpW & 0x4000) ? 1 : 0;
dst.n = (tmpW & 0x8000) ? 1 : 0;
break;
case SUBQMOD:
#ifdef DEBUG
error( "DSP - Invalid Opcode (SUBQMOD)" );
#endif
break;
case SAT16S:
#ifdef DEBUG
error( "DSP - Invalid Opcode (SAT16S)" );
#endif
break;
case MOVE:
dst.arb[dst.dest] = dst.arb[dst.src];
break;
case MOVEQ:
dst.arb[dst.dest] = dst.src;
break;
case MOVETA:
dst.srb[dst.dest] = dst.arb[dst.src];
break;
case MOVEFA:
dst.arb[dst.dest] = dst.srb[dst.src];
break;
case MOVEI:
dst.arb[dst.dest] = mem_readword(dst.pc + 2);
dst.arb[dst.dest] |= mem_readword(dst.pc + 4) << 16;
DincPC = 1;
break;
case LOADB:
if( dst.arb[dst.src] >= 0xF1B000 && dst.arb[dst.src] < 0xF1D000 )
{
dst.arb[dst.dest] = mem_readword( dst.arb[dst.src] ) << 16;
dst.arb[dst.dest] |= mem_readword( dst.arb[dst.src] + 2 );
}
else
dst.arb[dst.dest] = mem_readbyte( dst.arb[dst.src] );
break;
case LOADW:
if( dst.arb[dst.src] >= 0xF1B000 && dst.arb[dst.src] < 0xF1D000 )
{
dst.arb[dst.dest] = mem_readword( dst.arb[dst.src] ) << 16;
dst.arb[dst.dest] |= mem_readword( dst.arb[dst.src] + 2 );
}
else
dst.arb[dst.dest] = mem_readword( dst.arb[dst.src] );
break;
case LOAD:
dst.arb[dst.dest] = mem_readword( dst.arb[dst.src] ) << 16;
dst.arb[dst.dest] |= mem_readword( dst.arb[dst.src] + 2 );
break;
case SAT32S:
#ifdef DEBUG
error( "DSP - Invalid Opcode (SAT32S)" );
#endif
break;
case LOAD_14I:
tmpW = dst.arb[0x0E] + (dst.src * 4);
dst.arb[dst.dest] = mem_readword( tmpW ) << 16;
dst.arb[dst.dest] |= mem_readword( tmpW + 2 );
break;
case LOAD_15I:
tmpW = dst.arb[0x0F] + (dst.src * 4);
dst.arb[dst.dest] = mem_readword( tmpW ) << 16;
dst.arb[dst.dest] |= mem_readword( tmpW + 2 );
break;
case STOREB:
if( dst.arb[dst.src] >= 0xF1B000 && dst.arb[dst.src] < 0xF1D000 )
{
mem_writeword( dst.arb[dst.src], (dst.arb[dst.dest] >> 16) );
mem_writeword( dst.arb[dst.src] + 2, (dst.arb[dst.dest] & 0xFFFF) );
}
else
mem_writebyte( dst.arb[dst.src], (dst.arb[dst.dest] & 0xFF) );
break;
case STOREW:
if( dst.arb[dst.src] >= 0xF1B000 && dst.arb[dst.src] < 0xF1D000 )
{
mem_writeword( dst.arb[dst.src], (dst.arb[dst.dest] >> 16) );
mem_writeword( dst.arb[dst.src] + 2, (dst.arb[dst.dest] & 0xFFFF) );
}
else
mem_writeword( dst.arb[dst.src], (dst.arb[dst.dest] & 0xFFFF) );
break;
case STORE:
mem_writeword( dst.arb[dst.src], (dst.arb[dst.dest] >> 16) );
mem_writeword( dst.arb[dst.src] + 2, (dst.arb[dst.dest] & 0xFFFF) );
break;
case MIRROR:
#ifdef DEBUG
error( "DSP - Invalid Opcode (MIRROR)" );
#endif
break;
case STORE_14I:
tmpW = dst.arb[0x0E] + (dst.src * 4);
mem_writeword( tmpW, (dst.arb[dst.dest] >> 16) );
mem_writeword( tmpW + 2, (dst.arb[dst.dest] & 0xFFFF) );
break;
case STORE_15I:
tmpW = dst.arb[0x0F] + (dst.src * 4);
mem_writeword( tmpW, (dst.arb[dst.dest] >> 16) );
mem_writeword( tmpW + 2, (dst.arb[dst.dest] & 0xFFFF) );
break;
case MOVE_PC:
dst.arb[dst.dest] = dst.pc;
break;
case JUMP:
DjmpPC = dst.arb[dst.src];
switch( dst.dest )
{
case 0: // No Conditions
Dbranch = 1;
break;
case 1: // NE - Not Equal
if( !dst.z ) // Zero Flag Unset
Dbranch = 1;
break;
case 2: // EQ - Equal
if( dst.z) // Zero Flag Set
Dbranch = 1;
break;
case 4: // Flag Selected Cleared to Jump
if( dst.dest & 0x10 ) // Negative Flag
if( !dst.n ) Dbranch = 1; else Dbranch = 0;
else // Carry Flag
if( !dst.c ) Dbranch = 1; else Dbranch = 0;
break;
case 8: // Flag Selected Set to Jump
if( dst.dest & 0x10 ) // Negative Flag
{
if( dst.n ) Dbranch = 1; else Dbranch = 0;
}
else // Carry Flag
{
if( dst.c ) Dbranch = 1; else Dbranch = 0;
}
break;
case 0x14:
if( !dst.n ) Dbranch = 1; else Dbranch = 0;
break;
case 0x18:
if( dst.n ) Dbranch = 1; else Dbranch = 0;
break;
default:
#ifdef DEBUG
print( "Unknown JUMP Condition\n" );
#endif
break;
}
break;
case JR:
if( dst.src >= 16 ) // Set Jump Direction
dst.src -= 32;
DjmpPC = (dst.pc + 2) + (dst.src * 2);
switch( dst.dest )
{
case 0x00: // No Conditions
Dbranch = 1;
break;
case 0x01: // NE - Not Equal
if( !dst.z ) // Zero Flag Unset
Dbranch = 1;
break;
case 0x02: // EQ - Equal
if( dst.z) // Zero Flag Set
Dbranch = 1;
break;
case 0x04: // Flag Selected Cleared to Jump
if( !dst.c ) Dbranch = 1; else Dbranch = 0;
break;
case 0x08: // Flag Selected Set to Jump
if( dst.c ) Dbranch = 1; else Dbranch = 0;
break;
case 0x14:
if( !dst.n ) Dbranch = 1; else Dbranch = 0;
break;
case 0x18:
if( dst.n ) Dbranch = 1; else Dbranch = 0;
break;
default:
#ifdef DEBUG
print( "Unknown JR Condition at 0x%08X\n", dst.pc );
#endif
break;
}
break;
case MMULT:
#ifdef DEBUG
error( "DSP - Invalid Opcode (MMULT)" );
#endif
break;
case MTOI:
#ifdef DEBUG
error( "DSP - Invalid Opcode (MTOI)" );
#endif
break;
case NORMI:
#ifdef DEBUG
error( "DSP - Invalid Opcode (NORMI)" );
#endif
break;
case NOP:
break;
case LOAD_14R:
tmpW = dst.arb[0x0E] + dst.arb[dst.src];
dst.arb[dst.dest] = mem_readword( tmpW ) << 16;
dst.arb[dst.dest] |= mem_readword( tmpW + 2 );
break;
case LOAD_15R:
// NOTE: Manual seems to indicate that this opcode
// uses Register 14 as the base offset address.
tmpW = dst.arb[0x0E] + dst.arb[dst.src];
dst.arb[dst.dest] = mem_readword( tmpW ) << 16;
dst.arb[dst.dest] |= mem_readword( tmpW + 2 );
break;
case STORE_14R:
tmpW = dst.arb[0x0E] + dst.arb[dst.src];
mem_writeword( tmpW, (dst.arb[dst.dest] >> 16) );
mem_writeword( tmpW + 2, (dst.arb[dst.dest] & 0xFFFF) );
break;
case STORE_15R:
// NOTE: Manual seems to indicate that this opcode
// uses Register 14 as the base offset address.
tmpW = dst.arb[0x0E] + dst.arb[dst.src];
mem_writeword( tmpW, (dst.arb[dst.dest] >> 16) );
mem_writeword( tmpW + 2, (dst.arb[dst.dest] & 0xFFFF) );
break;
case ADDQMOD:
#ifdef DEBUG
error( "DSP - Invalid Opcode (ADDQMOD)" );
#endif
break;
default:
#ifdef DEBUG
error( "DSP - Invalid Opcode" );
#endif
dst.dspActive = FALSE;
break;
}
switch( Dbranch ) // Increment Program Counter
{
case 2: // Next Instruction is the Branch Address
Dbranch = 0;
dst.pc = DjmpPC;
break;
// A Branch Address was Stored in the Branch Program Counter.
// The Next Instruction is a PC + 4 (Case 0 is Executed).
// The Next Instruction is at the Branch Program Counter
case 1:
Dbranch = 2;
case 0: // Normal Execution
switch( DincPC )
{
case 1: // Opcode Used a 32-Bit Word
dst.pc += 6;
DincPC = 0;
break;
case 0: // Normal Execution
dst.pc += 2;
break;
}
break;
}
}
return( TRUE );
}