mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
Almost there, baby
This commit is contained in:
parent
edb88ffe18
commit
53d4895aef
@ -1,8 +1,98 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* SCUDSP CPU core
|
||||
* scudsp.c
|
||||
* Sega SCUDSP emulator version 1.00
|
||||
*
|
||||
* copyright Angelo Salese & Mariusz Wojcieszek, all rights reserved
|
||||
*
|
||||
* - This source code is released as freeware for non-commercial purposes.
|
||||
* - You are free to use and redistribute this code in modified or
|
||||
* unmodified form, provided you list me in the credits.
|
||||
* - If you modify this source code, you must add a notice to each modified
|
||||
* source file that it has been changed. If you're a nice person, you
|
||||
* will clearly mark each change too. :)
|
||||
* - If you wish to use this for commercial purposes, please contact me at
|
||||
* lordkale@libero.it or <insert_marusz_wojcieszek_mail_here>
|
||||
* - This entire notice must remain in the source code.
|
||||
*
|
||||
*
|
||||
* Changelog:
|
||||
* 131010: Angelo Salese
|
||||
* - Converted to CPU structure
|
||||
*
|
||||
* 110807: Angelo Salese
|
||||
* - Allow the Program Counter to be read-backable from SH-2, needed by Virtua Fighter to not
|
||||
* get stuck on "round 1" announcement;
|
||||
*
|
||||
* 110806: Angelo Salese
|
||||
* - Allows reading from non-work ram h areas;
|
||||
* - Fixed DMA add values;
|
||||
* - Fixed a MVI condition shift flag bug, now Sega Saturn produces sound during splash screen;
|
||||
* - Removed left-over IRQ;
|
||||
*
|
||||
* 110722: Angelo Salese
|
||||
* - Added DSP IRQ command, tested with "The King of Boxing"
|
||||
*
|
||||
* 110527: Angelo Salese
|
||||
* - Fixed incorrectly setted execute flag clearance, allows animation of the Sega Saturn
|
||||
* splash screen;
|
||||
*
|
||||
* 051129: Mariusz Wojcieszek
|
||||
* - Fixed parallel instructions which increment CT registers to update CT register only
|
||||
* once, after dsp operation is finished. This fixes instructions like
|
||||
* MOV MC0,X MOV MC0,Y used by vfremix
|
||||
* - Changed ALU 32bit instructions to not sign extend their result when loaded to ALU.
|
||||
* This matches Sega's dspsim behaviour.
|
||||
* - Changed DMA addnumber handling to match Sega's dspsim.
|
||||
*
|
||||
* 050813: Mariusz Wojcieszek
|
||||
* - Fixed add number in DSP DMA
|
||||
*
|
||||
* 050412: Angelo Salese
|
||||
* - Fixed the T0F behaviour in the DMA operation,it was causing an hang in Treasure Hunt
|
||||
* due of that.
|
||||
* - Removed the dsp.log file creation when you are not using the debug build
|
||||
*
|
||||
* 041114: Angelo Salese
|
||||
* - Finished flags in ALU opcodes
|
||||
* - SR opcode: MSB does not change.
|
||||
*
|
||||
* 040328: Mariusz Wojcieszek
|
||||
* - rewritten ALU and MUL operations using signed arithmetics
|
||||
* - improved DMA
|
||||
* - fixed MOV ALH,x
|
||||
*
|
||||
* 031211: Mariusz Wojcieszek
|
||||
* - result of ALU command is stored into ALU register
|
||||
* - X-Bus command: MOV [s],X can be executed in parallel to other X-Bus commands
|
||||
* - Y-Bus command: MOV [s],Y can be executed in parallel to other Y-Bus commands
|
||||
* - Jump and LPS/BTM support:
|
||||
* jump addresses are absolute,
|
||||
* prefetched instructions are executed before jump is taken
|
||||
* - after each instruction, X and Y is multiplied and contents are loaded into MUL register
|
||||
* - fixed RL8
|
||||
* - fixed MVI
|
||||
* - flags computation in MVI and JMP is partly guessed (because of errors in docs)
|
||||
* - added reading DSP mem from SH2 side
|
||||
* - overworked disassembler
|
||||
*
|
||||
* TODO:
|
||||
* - Add control flags
|
||||
* - Croc: has a bug somewhere that never allows it to trip the ENDI opcode.
|
||||
* Snippet of interest is:
|
||||
* 08 00823500 CLR A MOV M0,PL
|
||||
* 09 08040000 OR MOV ALU,A
|
||||
* 0A D208000D JMP NZ,$D
|
||||
* 0B 00000000 NOP
|
||||
* 0C F8000000 ENDI
|
||||
*
|
||||
* 40 00863502 MOV M0,A MOV M2,PL
|
||||
* 41 10003009 ADD MOV ALL,MC0
|
||||
* 42 D3400042 JMP T0,$42
|
||||
* 43 00000000 NOP
|
||||
* 44 D0000007 JMP $7
|
||||
*
|
||||
*
|
||||
* skeleton for now ...
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
@ -17,21 +107,50 @@ const device_type SCUDSP = &device_creator<scudsp_cpu_device>;
|
||||
#define PRF m_flags & 0x04000000
|
||||
#define EPF m_flags & 0x02000000
|
||||
#define T0F m_flags & 0x00800000
|
||||
#define SF m_flags & 0x00400000
|
||||
#define ZF m_flags & 0x00200000
|
||||
#define SF (m_flags & 0x00400000)
|
||||
#define ZF (m_flags & 0x00200000)
|
||||
#define CF m_flags & 0x00100000
|
||||
#define VF m_flags & 0x00080000
|
||||
#define EF m_flags & 0x00040000
|
||||
#define ESF m_flags & 0x00020000
|
||||
#define EXF m_flags & 0x00010000 // execute flag (basically tied to RESET pin)
|
||||
#define LEF m_flags & 0x00008000 // change PC value
|
||||
#define T0F_1 m_flags|=0x00800000
|
||||
#define T0F_0 m_flags&=~0x00800000
|
||||
#define EXF_0 m_flags&=~0x00010000
|
||||
#define EF_1 m_flags|=0x00040000
|
||||
|
||||
#define SET_C(_val) (m_flags = ((m_flags & ~0x00100000) | ((_val) ? 0x00100000 : 0)))
|
||||
#define SET_S(_val) (m_flags = ((m_flags & ~0x00400000) | ((_val) ? 0x00400000 : 0)))
|
||||
#define SET_Z(_val) (m_flags = ((m_flags & ~0x00200000) | ((_val) ? 0x00200000 : 0)))
|
||||
#define SET_V(_val) (m_flags = ((m_flags & ~0x00080000) | ((_val) ? 0x00080000 : 0)))
|
||||
|
||||
|
||||
#define FLAGS_MASK 0x06ff8000
|
||||
|
||||
#define scudsp_readop(A) m_program->read_dword(A << 2)
|
||||
#define scudsp_writeop(A, B) m_program->write_dword(A << 2, B)
|
||||
#define scudsp_readmem(A,MD) m_data->read_dword((A | MD << 6) << 2)
|
||||
#define scudsp_writemem(A,MD,B) m_data->write_dword((A | MD << 6) << 2, B)
|
||||
#define scudsp_readmem(A,MD) m_data->read_dword(((A | MD) << 6) << 2)
|
||||
#define scudsp_writemem(A,MD,B) m_data->write_dword(((A | MD) << 6) << 2, B)
|
||||
|
||||
UINT32 scudsp_cpu_device::scudsp_get_source_mem_reg_value( UINT32 mode )
|
||||
{
|
||||
if ( mode < 0x8 )
|
||||
{
|
||||
return scudsp_get_source_mem_value( mode );
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( mode )
|
||||
{
|
||||
case 0x9:
|
||||
return (UINT32)((m_alu & U64(0x00000000ffffffff)) >> 0);
|
||||
case 0xA:
|
||||
return (UINT32)((m_alu & U64(0x0000ffffffff0000)) >> 16);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT32 scudsp_cpu_device::scudsp_get_source_mem_value(UINT8 mode)
|
||||
{
|
||||
@ -92,47 +211,123 @@ void scudsp_cpu_device::scudsp_set_dest_mem_reg( UINT32 mode, UINT32 value )
|
||||
scudsp_writemem(m_ct3++,3,value);
|
||||
m_ct3 &= 0x3f;
|
||||
break;
|
||||
#if 0
|
||||
case 0x4: /* RX */
|
||||
dsp_reg.rx.ui = value;
|
||||
update_mul = 1;
|
||||
m_rx.ui = value;
|
||||
break;
|
||||
case 0x5: /* PL */
|
||||
dsp_reg.pl.ui = value;
|
||||
dsp_reg.ph.si = (dsp_reg.pl.si < 0) ? -1 : 0;
|
||||
m_pl.ui = value;
|
||||
m_ph.si = (m_pl.si < 0) ? -1 : 0;
|
||||
break;
|
||||
case 0x6: /* RA0 */
|
||||
dsp_reg.ra0 = value;
|
||||
m_ra0 = value;
|
||||
break;
|
||||
case 0x7: /* WA0 */
|
||||
dsp_reg.wa0 = value;
|
||||
m_wa0 = value;
|
||||
break;
|
||||
case 0x8:
|
||||
case 0x9:
|
||||
/* ??? */
|
||||
break;
|
||||
case 0xa: /* LOP */
|
||||
dsp_reg.lop = value;
|
||||
m_lop = value;
|
||||
break;
|
||||
case 0xb: /* TOP */
|
||||
dsp_reg.top = value;
|
||||
m_top = value;
|
||||
break;
|
||||
case 0xc: /* CT0 */
|
||||
dsp_reg.ct0 = value & 0x3f;
|
||||
m_ct0 = value & 0x3f;
|
||||
break;
|
||||
case 0xd: /* CT1 */
|
||||
dsp_reg.ct1 = value & 0x3f;
|
||||
m_ct1 = value & 0x3f;
|
||||
break;
|
||||
case 0xe: /* CT2 */
|
||||
dsp_reg.ct2 = value & 0x3f;
|
||||
m_ct2 = value & 0x3f;
|
||||
break;
|
||||
case 0xf: /* CT3 */
|
||||
dsp_reg.ct3 = value & 0x3f;
|
||||
m_ct3 = value & 0x3f;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void scudsp_cpu_device::scudsp_set_dest_mem_reg_2( UINT32 mode, UINT32 value )
|
||||
{
|
||||
if ( mode < 0xb )
|
||||
{
|
||||
scudsp_set_dest_mem_reg( mode, value );
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( mode )
|
||||
{
|
||||
case 0xc: /* PC */
|
||||
m_delay = m_pc; /* address next after this command will be executed twice */
|
||||
m_top = m_pc;
|
||||
m_pc = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 scudsp_cpu_device::scudsp_compute_condition( UINT32 condition )
|
||||
{
|
||||
UINT32 result = 0;
|
||||
|
||||
switch( condition & 0xf )
|
||||
{
|
||||
case 0x1: /* Z */
|
||||
result = ZF;
|
||||
break;
|
||||
case 0x2: /* S */
|
||||
result = SF;
|
||||
break;
|
||||
case 0x3: /* ZS */
|
||||
result = ZF | SF;
|
||||
break;
|
||||
case 0x4: /* C */
|
||||
result = CF;
|
||||
break;
|
||||
case 0x8: /* T0 */
|
||||
result = T0F;
|
||||
break;
|
||||
}
|
||||
if ( !(condition & 0x20) )
|
||||
{
|
||||
result = !result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void scudsp_cpu_device::scudsp_set_dest_dma_mem( UINT32 memcode, UINT32 value, UINT32 counter )
|
||||
{
|
||||
if ( memcode < 4 )
|
||||
{
|
||||
scudsp_set_dest_mem_reg( memcode, value );
|
||||
}
|
||||
else if ( memcode == 4 )
|
||||
{
|
||||
fatalerror("scudsp_set_dest_dma_mem == 4");
|
||||
/* caused a stack overflow for sure ... */
|
||||
//dsp_reg.internal_prg[ counter & 0x100 ] = value;
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 scudsp_cpu_device::scudsp_get_mem_source_dma( UINT32 memcode, UINT32 counter )
|
||||
{
|
||||
switch( memcode & 0x3 )
|
||||
{
|
||||
case 0x0:
|
||||
return scudsp_readmem(((m_ct0 + counter) & 0x3f),0);
|
||||
case 0x1:
|
||||
return scudsp_readmem(((m_ct1 + counter) & 0x3f),1);
|
||||
case 0x2:
|
||||
return scudsp_readmem(((m_ct2 + counter) & 0x3f),2);
|
||||
case 0x3:
|
||||
return scudsp_readmem(((m_ct3 + counter) & 0x3f),3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
READ32_MEMBER( scudsp_cpu_device::program_control_r )
|
||||
{
|
||||
@ -190,12 +385,300 @@ WRITE32_MEMBER( scudsp_cpu_device::ram_address_w )
|
||||
scudsp_set_dest_mem_reg( (m_ra & 0xc0) >> 6, data );
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* illegal opcodes
|
||||
***********************************/
|
||||
void scudsp_cpu_device::scudsp_illegal()
|
||||
void scudsp_cpu_device::scudsp_operation(UINT32 opcode)
|
||||
{
|
||||
//logerror("scudsp illegal opcode at 0x%04x\n", m_pc);
|
||||
INT64 i1,i2;
|
||||
INT32 i3;
|
||||
int update_ct[4] = {0,0,0,0};
|
||||
int dsp_mem;
|
||||
|
||||
|
||||
/* ALU */
|
||||
switch( (opcode & 0x3c000000) >> 26 )
|
||||
{
|
||||
case 0x0: /* NOP */
|
||||
break;
|
||||
case 0x1: /* AND */
|
||||
i3 = m_acl.si & m_pl.si;
|
||||
m_alu = (UINT64)(UINT32)i3;
|
||||
SET_Z(i3 == 0);
|
||||
SET_C(0);
|
||||
SET_S(i3 < 0);
|
||||
break;
|
||||
case 0x2: /* OR */
|
||||
i3 = m_acl.si | m_pl.si;
|
||||
m_alu = (UINT64)(UINT32)i3;
|
||||
SET_C(0);
|
||||
SET_S(i3 < 0);
|
||||
/* TODO: Croc and some early Psygnosis games wants Z to be 1 when the result of this one is negative.
|
||||
Needs HW tests ... */
|
||||
if(i3 < 0)
|
||||
i3 = 0;
|
||||
SET_Z(i3 == 0);
|
||||
break;
|
||||
case 0x3: /* XOR */
|
||||
i3 = m_acl.si ^ m_pl.si;
|
||||
m_alu = (UINT64)(UINT32)i3;
|
||||
SET_Z(i3 == 0);
|
||||
SET_C(0);
|
||||
SET_S(i3 < 0);
|
||||
break;
|
||||
case 0x4: /* ADD */
|
||||
i3 = m_acl.si + m_pl.si;
|
||||
m_alu = (UINT64)(UINT32)i3;
|
||||
//SET_Z(i3 == 0);
|
||||
SET_Z( (i3 & S64(0xffffffffffff)) == 0 );
|
||||
//SET_S(i3 < 0);
|
||||
SET_S( i3 & S64(0x1000000000000));
|
||||
SET_C(i3 & S64(0x100000000));
|
||||
SET_V(((i3) ^ (m_acl.si)) & ((i3) ^ (m_pl.si)) & 0x80000000);
|
||||
break;
|
||||
case 0x5: /* SUB */
|
||||
i3 = m_acl.si - m_pl.si;
|
||||
m_alu = (UINT64)(UINT32)i3;
|
||||
SET_Z(i3 == 0);
|
||||
SET_C(i3 & S64(0x100000000));
|
||||
SET_S(i3 < 0);
|
||||
SET_V(((m_pl.si) ^ (m_acl.si)) & ((m_pl.si) ^ (i3)) & 0x80000000);
|
||||
break;
|
||||
case 0x6: /* AD2 */
|
||||
i1 = CONCAT_64((INT32)m_ph.si,m_pl.si);
|
||||
i2 = CONCAT_64((INT32)m_ach.si,m_acl.si);
|
||||
m_alu = i1 + i2;
|
||||
SET_Z((m_alu & S64(0xffffffffffff)) == 0);
|
||||
SET_S((m_alu & S64(0x800000000000)) > 0);
|
||||
SET_C((m_alu) & S64(0x1000000000000));
|
||||
SET_V(((m_alu) ^ (i1)) & ((m_alu) ^ (i2)) & S64(0x800000000000));
|
||||
break;
|
||||
case 0x7: /* ??? */
|
||||
/* Unrecognized opcode */
|
||||
break;
|
||||
case 0x8: /* SR */
|
||||
i3 = (m_acl.si >> 1) | (m_acl.si & 0x80000000);/*MSB does not change*/
|
||||
m_alu = (UINT64)(UINT32)i3;
|
||||
SET_Z(i3 == 0);
|
||||
SET_S(i3 < 0);
|
||||
SET_C(m_acl.ui & 0x80000000);
|
||||
break;
|
||||
case 0x9: /* RR */
|
||||
i3 = ((m_acl.ui >> 1) & 0x7fffffff) | ((m_acl.ui << 31) & 0x80000000);
|
||||
m_alu = (UINT64)(UINT32)i3;
|
||||
SET_Z( i3 == 0 );
|
||||
SET_S( i3 < 0 );
|
||||
SET_C( m_acl.ui & 0x1 );
|
||||
break;
|
||||
case 0xa: /* SL */
|
||||
i3 = m_acl.si << 1;
|
||||
m_alu = (UINT64)(UINT32)i3;
|
||||
SET_Z( i3 == 0 );
|
||||
SET_S( i3 < 0 );
|
||||
SET_C( m_acl.ui & 0x80000000 );
|
||||
break;
|
||||
case 0xB: /* RL */
|
||||
i3 = ((m_acl.si << 1) & 0xfffffffe) | ((m_acl.si >> 31) & 0x1);
|
||||
m_alu = (UINT64)(UINT32)i3;
|
||||
SET_Z( i3 == 0 );
|
||||
SET_S( i3 < 0 );
|
||||
SET_C( m_acl.ui & 0x80000000 );
|
||||
break;
|
||||
case 0xc:
|
||||
case 0xd:
|
||||
case 0xe:
|
||||
/* Unrecognized opcode */
|
||||
break;
|
||||
case 0xF: /* RL8 */
|
||||
i3 = ((m_acl.si << 8) & 0xffffff00) | ((m_acl.si >> 24) & 0xff);
|
||||
m_alu = i3;
|
||||
SET_Z( i3 == 0 );
|
||||
SET_S( i3 < 0 );
|
||||
SET_C( m_acl.si & 0x01000000 );
|
||||
break;
|
||||
}
|
||||
|
||||
/* X-Bus */
|
||||
if ( opcode & 0x2000000 )
|
||||
{
|
||||
/* MOV [s],X */
|
||||
dsp_mem = (opcode & 0x700000) >> 20;
|
||||
if ( dsp_mem & 4 )
|
||||
{
|
||||
dsp_mem &= 3;
|
||||
update_ct[dsp_mem] = 1;
|
||||
}
|
||||
m_rx.ui = scudsp_get_source_mem_value( dsp_mem );
|
||||
m_update_mul = 1;
|
||||
}
|
||||
switch( (opcode & 0x1800000) >> 23 )
|
||||
{
|
||||
case 0x0: /* NOP */
|
||||
case 0x1: /* NOP ? */
|
||||
break;
|
||||
case 0x2: /* MOV MUL,P */
|
||||
m_ph.ui = (UINT16)((m_mul & U64(0x0000ffff00000000)) >> 32);
|
||||
m_pl.ui = (UINT32)((m_mul & U64(0x00000000ffffffff)) >> 0);
|
||||
break;
|
||||
case 0x3: /* MOV [s],P */
|
||||
dsp_mem = (opcode & 0x700000) >> 20;
|
||||
if ( dsp_mem & 4 )
|
||||
{
|
||||
dsp_mem &= 3;
|
||||
update_ct[dsp_mem] = 1;
|
||||
}
|
||||
m_pl.ui = scudsp_get_source_mem_value( dsp_mem );
|
||||
m_ph.si = (m_pl.si < 0) ? -1 : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Y-Bus */
|
||||
if ( opcode & 0x80000 )
|
||||
{
|
||||
/* MOV [s],Y */
|
||||
dsp_mem = (opcode & 0x1C000 ) >> 14;
|
||||
if (dsp_mem & 4)
|
||||
{
|
||||
dsp_mem &= 3;
|
||||
update_ct[dsp_mem] = 1;
|
||||
}
|
||||
m_ry.ui = scudsp_get_source_mem_value( dsp_mem );
|
||||
m_update_mul = 1;
|
||||
}
|
||||
switch( (opcode & 0x60000) >> 17 )
|
||||
{
|
||||
case 0x0: /* NOP */
|
||||
break;
|
||||
case 0x1: /* CLR A */
|
||||
m_acl.ui = 0;
|
||||
m_ach.ui = 0;
|
||||
break;
|
||||
case 0x2: /* MOV ALU,A */
|
||||
m_ach.ui = (UINT16)((m_alu & U64(0x0000ffff00000000)) >> 32);
|
||||
m_acl.ui = (UINT32)((m_alu & U64(0x00000000ffffffff)) >> 0);
|
||||
break;
|
||||
case 0x3: /* MOV [s], A */
|
||||
dsp_mem = (opcode & 0x1C000 ) >> 14;
|
||||
if (dsp_mem & 4)
|
||||
{
|
||||
dsp_mem &= 3;
|
||||
update_ct[dsp_mem] = 1;
|
||||
}
|
||||
m_acl.ui = scudsp_get_source_mem_value( dsp_mem );
|
||||
m_ach.si = ((m_acl.si < 0) ? -1 : 0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* update CT registers */
|
||||
if ( update_ct[0] ) { m_ct0++; m_ct0 &= 0x3f; };
|
||||
if ( update_ct[1] ) { m_ct1++; m_ct1 &= 0x3f; };
|
||||
if ( update_ct[2] ) { m_ct2++; m_ct2 &= 0x3f; };
|
||||
if ( update_ct[3] ) { m_ct3++; m_ct3 &= 0x3f; };
|
||||
|
||||
|
||||
/* D1-Bus */
|
||||
switch( (opcode & 0x3000) >> 12 )
|
||||
{
|
||||
case 0x0: /* NOP */
|
||||
break;
|
||||
case 0x1: /* MOV SImm,[d] */
|
||||
scudsp_set_dest_mem_reg( (opcode & 0xf00) >> 8, (INT32)(INT8)(opcode & 0xff) );
|
||||
break;
|
||||
case 0x2:
|
||||
/* ??? */
|
||||
break;
|
||||
case 0x3: /* MOV [s],[d] */
|
||||
scudsp_set_dest_mem_reg( (opcode & 0xf00) >> 8, scudsp_get_source_mem_reg_value( opcode & 0xf ) );
|
||||
break;
|
||||
}
|
||||
|
||||
m_icount -= 1;
|
||||
}
|
||||
|
||||
void scudsp_cpu_device::scudsp_move_immediate( UINT32 opcode )
|
||||
{
|
||||
UINT32 value;
|
||||
|
||||
if ( opcode & 0x2000000 )
|
||||
{
|
||||
if ( scudsp_compute_condition( (opcode & 0x3F80000 ) >> 19 ) )
|
||||
{
|
||||
value = opcode & 0x7ffff;
|
||||
if ( value & 0x40000 ) value |= 0xfff80000;
|
||||
scudsp_set_dest_mem_reg_2( (opcode & 0x3C000000) >> 26, value );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = opcode & 0x1ffffff;
|
||||
if ( value & 0x1000000 ) value |= 0xfe000000;
|
||||
scudsp_set_dest_mem_reg_2( (opcode & 0x3C000000) >> 26, value );
|
||||
}
|
||||
m_icount -= 1;
|
||||
}
|
||||
|
||||
void scudsp_cpu_device::scudsp_dma( UINT32 opcode )
|
||||
{
|
||||
m_icount -= 1;
|
||||
}
|
||||
|
||||
void scudsp_cpu_device::scudsp_jump( UINT32 opcode )
|
||||
{
|
||||
if ( opcode & 0x3f80000 )
|
||||
{
|
||||
if ( scudsp_compute_condition( (opcode & 0x3f80000) >> 19 ) )
|
||||
{
|
||||
m_delay = m_pc;
|
||||
m_pc = opcode & 0xff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_delay = m_pc;
|
||||
m_pc = opcode & 0xff;
|
||||
}
|
||||
|
||||
m_icount -= 1;
|
||||
}
|
||||
|
||||
void scudsp_cpu_device::scudsp_loop(UINT32 opcode)
|
||||
{
|
||||
if ( opcode & 0x8000000 )
|
||||
{
|
||||
/* LPS */
|
||||
if ( m_lop != 0 )
|
||||
{
|
||||
m_lop--;
|
||||
m_delay = m_pc;
|
||||
m_pc--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* BTM */
|
||||
if ( m_lop != 0 )
|
||||
{
|
||||
m_lop--;
|
||||
m_delay = m_pc;
|
||||
m_pc = m_top;
|
||||
}
|
||||
}
|
||||
m_icount -= 1;
|
||||
}
|
||||
|
||||
void scudsp_cpu_device::scudsp_end(UINT32 opcode)
|
||||
{
|
||||
if(opcode & 0x08000000)
|
||||
{
|
||||
/*ENDI*/
|
||||
//TODO: irq signal
|
||||
}
|
||||
|
||||
EXF_0; /* END / ENDI */
|
||||
set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
|
||||
m_icount -= 1;
|
||||
}
|
||||
|
||||
void scudsp_cpu_device::scudsp_illegal(UINT32 opcode)
|
||||
{
|
||||
fatalerror("scudsp illegal opcode at 0x%04x\n", m_pc);
|
||||
m_icount -= 1;
|
||||
}
|
||||
|
||||
@ -206,18 +689,58 @@ void scudsp_cpu_device::execute_run()
|
||||
|
||||
do
|
||||
{
|
||||
debugger_instruction_hook(this, m_pc);
|
||||
m_update_mul = 0;
|
||||
|
||||
opcode = scudsp_readop(m_pc);
|
||||
m_pc++;
|
||||
|
||||
switch( opcode )
|
||||
if ( m_delay )
|
||||
{
|
||||
default:
|
||||
scudsp_illegal();
|
||||
debugger_instruction_hook(this, m_delay);
|
||||
opcode = scudsp_readop(m_delay);
|
||||
m_delay = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger_instruction_hook(this, m_pc);
|
||||
opcode = scudsp_readop(m_pc);
|
||||
m_pc++;
|
||||
}
|
||||
|
||||
switch( (opcode & 0xc0000000) >> 30 )
|
||||
{
|
||||
case 0x00: /* 00 */
|
||||
scudsp_operation(opcode);
|
||||
break;
|
||||
case 0x01: /* 01 */
|
||||
scudsp_illegal(opcode);
|
||||
break;
|
||||
case 0x02: /* 10 */
|
||||
scudsp_move_immediate(opcode);
|
||||
break;
|
||||
case 0x03: /* 11 */
|
||||
switch( (opcode & 0x30000000) >> 28 )
|
||||
{
|
||||
case 0x00:
|
||||
scudsp_dma(opcode);
|
||||
break;
|
||||
case 0x01:
|
||||
scudsp_jump(opcode);
|
||||
break;
|
||||
case 0x02:
|
||||
scudsp_loop(opcode);
|
||||
break;
|
||||
case 0x03:
|
||||
scudsp_end(opcode);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( m_update_mul == 1 )
|
||||
{
|
||||
m_mul = (INT64)m_rx.si * (INT64)m_ry.si;
|
||||
m_update_mul = 0;
|
||||
}
|
||||
|
||||
|
||||
} while( m_icount > 0 );
|
||||
}
|
||||
|
||||
@ -229,16 +752,47 @@ void scudsp_cpu_device::device_start()
|
||||
|
||||
save_item(NAME(m_pc));
|
||||
save_item(NAME(m_ra));
|
||||
|
||||
save_item(NAME(m_ct0));
|
||||
save_item(NAME(m_ct1));
|
||||
save_item(NAME(m_ct2));
|
||||
save_item(NAME(m_ct3));
|
||||
|
||||
save_item(NAME(m_flags));
|
||||
save_item(NAME(m_reset_state));
|
||||
save_item(NAME(m_delay));
|
||||
|
||||
save_item(NAME(m_top));
|
||||
save_item(NAME(m_lop));
|
||||
save_item(NAME(m_rx.ui));
|
||||
|
||||
save_item(NAME(m_mul));
|
||||
|
||||
save_item(NAME(m_ry.ui));
|
||||
|
||||
save_item(NAME(m_alu));
|
||||
save_item(NAME(m_ph.ui));
|
||||
save_item(NAME(m_pl.ui));
|
||||
save_item(NAME(m_ach.ui));
|
||||
save_item(NAME(m_acl.ui));
|
||||
save_item(NAME(m_ra0));
|
||||
save_item(NAME(m_wa0));
|
||||
|
||||
// Register state for debugger
|
||||
state_add( SCUDSP_PC, "PC", m_pc ).formatstr("%02X");
|
||||
state_add( SCUDSP_FLAGS, "SR", m_flags ).formatstr("%08X");
|
||||
state_add( SCUDSP_DELAY, "DELAY", m_delay ).formatstr("%02X").noshow();
|
||||
state_add( SCUDSP_TOP, "TOP", m_top).formatstr("%02X");
|
||||
state_add( SCUDSP_LOP, "LOP", m_lop).formatstr("%03X");
|
||||
state_add( SCUDSP_RX, "RX", m_rx).formatstr("%08X");
|
||||
state_add( SCUDSP_MUL, "MUL", m_mul).formatstr("%012X");
|
||||
state_add( SCUDSP_RY, "RY", m_ry).formatstr("%08X");
|
||||
state_add( SCUDSP_ALU, "ALU", m_alu).formatstr("%012X");
|
||||
state_add( SCUDSP_PH, "PH", m_ph).formatstr("%04X");
|
||||
state_add( SCUDSP_PL, "PL", m_pl).formatstr("%08X");
|
||||
state_add( SCUDSP_ACH, "ACH", m_ach).formatstr("%04X");
|
||||
state_add( SCUDSP_ACL, "ACL", m_acl).formatstr("%08X");
|
||||
state_add( SCUDSP_RA0, "RA0", m_ra0).formatstr("%08X");
|
||||
state_add( SCUDSP_WA0, "WA0", m_wa0).formatstr("%08X");
|
||||
state_add( SCUDSP_RA, "RA", m_ra ).formatstr("%02X");
|
||||
state_add( SCUDSP_CT0, "CT0", m_ct0 ).formatstr("%02X");
|
||||
state_add( SCUDSP_CT1, "CT1", m_ct1 ).formatstr("%02X");
|
||||
@ -260,7 +814,7 @@ void scudsp_cpu_device::execute_set_input(int irqline, int state)
|
||||
switch(irqline)
|
||||
{
|
||||
case SCUDSP_RESET:
|
||||
m_reset_state = state;
|
||||
//m_reset_state = state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* SCUDSP CPU core
|
||||
*
|
||||
* skeleton for now ...
|
||||
* Sega SCUDSP emulator
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
@ -13,13 +11,39 @@
|
||||
|
||||
enum
|
||||
{
|
||||
SCUDSP_RA=1,
|
||||
SCUDSP_CT0, SCUDSP_CT1, SCUDSP_CT2, SCUDSP_CT3,
|
||||
SCUDSP_PC, SCUDSP_FLAGS
|
||||
SCUDSP_PC=1,
|
||||
SCUDSP_FLAGS,
|
||||
SCUDSP_DELAY,
|
||||
SCUDSP_TOP,
|
||||
SCUDSP_LOP,
|
||||
SCUDSP_RX,
|
||||
SCUDSP_MUL,
|
||||
SCUDSP_RY,
|
||||
SCUDSP_ALU,
|
||||
SCUDSP_PH,
|
||||
SCUDSP_PL,
|
||||
SCUDSP_ACH,
|
||||
SCUDSP_ACL,
|
||||
SCUDSP_RA0,
|
||||
SCUDSP_WA0,
|
||||
SCUDSP_RA,
|
||||
SCUDSP_CT0,
|
||||
SCUDSP_CT1,
|
||||
SCUDSP_CT2,
|
||||
SCUDSP_CT3
|
||||
};
|
||||
|
||||
#define SCUDSP_RESET INPUT_LINE_RESET /* Non-Maskable */
|
||||
|
||||
union SCUDSPREG32 {
|
||||
INT32 si;
|
||||
UINT32 ui;
|
||||
};
|
||||
|
||||
union SCUDSPREG16 {
|
||||
INT16 si;
|
||||
UINT16 ui;
|
||||
};
|
||||
|
||||
class scudsp_cpu_device : public cpu_device
|
||||
{
|
||||
@ -69,15 +93,39 @@ private:
|
||||
UINT8 m_pc; /* registers */
|
||||
UINT32 m_flags; /* flags */
|
||||
UINT8 m_ra;
|
||||
UINT8 m_ct0,m_ct1,m_ct2,m_ct3; /*Index for RAM*/ /*6-bits */
|
||||
int m_reset_state;
|
||||
UINT8 m_ct0,m_ct1,m_ct2,m_ct3;
|
||||
UINT8 m_delay; /* Delay */
|
||||
UINT8 m_top; /*Jump Command memory*/
|
||||
UINT16 m_lop; /*Counter Register*/ /*12-bits*/
|
||||
SCUDSPREG32 m_rx; /*X-Bus register*/
|
||||
INT64 m_mul; /*Multiplier register*//*48-bits*/
|
||||
SCUDSPREG32 m_ry; /*Y-Bus register*/
|
||||
INT64 m_alu; /*ALU register*/ /*48-bits*/
|
||||
SCUDSPREG16 m_ph; /*ALU high register*/
|
||||
SCUDSPREG32 m_pl; /*ALU low register*/
|
||||
SCUDSPREG16 m_ach; /*ALU external high register*/
|
||||
SCUDSPREG32 m_acl; /*ALU external low register*/
|
||||
UINT32 m_ra0,m_wa0; /*DSP DMA registers*/
|
||||
address_space *m_program;
|
||||
address_space *m_data;
|
||||
int m_icount;
|
||||
UINT8 m_update_mul;
|
||||
|
||||
UINT32 scudsp_get_source_mem_reg_value( UINT32 mode );
|
||||
UINT32 scudsp_get_source_mem_value(UINT8 mode);
|
||||
void scudsp_set_dest_mem_reg( UINT32 mode, UINT32 value );
|
||||
void scudsp_illegal();
|
||||
void scudsp_set_dest_mem_reg_2( UINT32 mode, UINT32 value );
|
||||
UINT32 scudsp_compute_condition( UINT32 condition );
|
||||
UINT32 scudsp_get_mem_source_dma( UINT32 memcode, UINT32 counter );
|
||||
void scudsp_set_dest_dma_mem( UINT32 memcode, UINT32 value, UINT32 counter );
|
||||
|
||||
void scudsp_illegal(UINT32 opcode);
|
||||
void scudsp_operation(UINT32 opcode);
|
||||
void scudsp_move_immediate(UINT32 opcode);
|
||||
void scudsp_dma(UINT32 opcode);
|
||||
void scudsp_jump(UINT32 opcode);
|
||||
void scudsp_loop(UINT32 opcode);
|
||||
void scudsp_end(UINT32 opcode);
|
||||
};
|
||||
|
||||
|
||||
|
@ -106,12 +106,12 @@ Changelog:
|
||||
#define SET_Z(_val) (state->m_scu_regs[32] = ((state->m_scu_regs[32] & ~0x00200000) | ((_val) ? 0x00200000 : 0)))
|
||||
#define SET_V(_val) (state->m_scu_regs[32] = ((state->m_scu_regs[32] & ~0x00080000) | ((_val) ? 0x00080000 : 0)))
|
||||
|
||||
union SCUDSPREG32 {
|
||||
union SCUDSPREG32_OLD {
|
||||
INT32 si;
|
||||
UINT32 ui;
|
||||
};
|
||||
|
||||
union SCUDSPREG16 {
|
||||
union SCUDSPREG16_OLD {
|
||||
INT16 si;
|
||||
UINT16 ui;
|
||||
};
|
||||
@ -124,14 +124,14 @@ static struct {
|
||||
UINT8 ct0,ct1,ct2,ct3; /*Index for RAM*/ /*6-bits */
|
||||
UINT32 md0[0x40],md1[0x40],md2[0x40],md3[0x40]; /*RAM memory*/
|
||||
UINT8 ra; /*RAM selector*/
|
||||
SCUDSPREG32 rx; /*X-Bus register*/
|
||||
SCUDSPREG32_OLD rx; /*X-Bus register*/
|
||||
INT64 mul; /*Multiplier register*//*48-bits*/
|
||||
SCUDSPREG32 ry; /*Y-Bus register*/
|
||||
SCUDSPREG32_OLD ry; /*Y-Bus register*/
|
||||
INT64 alu; /*ALU register*/ /*48-bits*/
|
||||
SCUDSPREG16 ph; /*ALU high register*/
|
||||
SCUDSPREG32 pl; /*ALU low register*/
|
||||
SCUDSPREG16 ach; /*ALU external high register*/
|
||||
SCUDSPREG32 acl; /*ALU external low register*/
|
||||
SCUDSPREG16_OLD ph; /*ALU high register*/
|
||||
SCUDSPREG32_OLD pl; /*ALU low register*/
|
||||
SCUDSPREG16_OLD ach; /*ALU external high register*/
|
||||
SCUDSPREG32_OLD acl; /*ALU external low register*/
|
||||
UINT32 ra0,wa0; /*DSP DMA registers*/
|
||||
UINT32 internal_prg[0x100];
|
||||
} dsp_reg;
|
||||
|
@ -961,11 +961,11 @@ static ADDRESS_MAP_START( sound_mem, AS_PROGRAM, 16, stv_state )
|
||||
AM_RANGE(0x100000, 0x100fff) AM_DEVREADWRITE_LEGACY("scsp", scsp_r, scsp_w)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START( scudsp_mem, AS_PROGRAM, 32, sat_console_state )
|
||||
static ADDRESS_MAP_START( scudsp_mem, AS_PROGRAM, 32, stv_state )
|
||||
AM_RANGE(0x00, 0xff) AM_RAM
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START( scudsp_data, AS_DATA, 32, sat_console_state )
|
||||
static ADDRESS_MAP_START( scudsp_data, AS_DATA, 32, stv_state )
|
||||
AM_RANGE(0x00, 0xff) AM_RAM
|
||||
ADDRESS_MAP_END
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user