mirror of
https://github.com/holub/mame
synced 2025-05-23 06:08:48 +03:00
728 lines
16 KiB
C
728 lines
16 KiB
C
/*****************************************************************************
|
|
*
|
|
* sh2common.c
|
|
*
|
|
* SH-2 non-specific components
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "debugger.h"
|
|
#include "deprecat.h"
|
|
#include "sh2.h"
|
|
#include "sh2comn.h"
|
|
|
|
extern SH2 *sh2;
|
|
|
|
#define VERBOSE 0
|
|
|
|
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
|
|
|
|
// Atrocious hack that makes the soldivid music correct
|
|
|
|
//static const int div_tab[4] = { 3, 5, 7, 0 };
|
|
static const int div_tab[4] = { 3, 5, 3, 0 };
|
|
|
|
INLINE UINT32 RL(offs_t A)
|
|
{
|
|
if (A >= 0xe0000000)
|
|
return sh2_internal_r(Machine, (A & 0x1fc)>>2, 0xffffffff);
|
|
|
|
if (A >= 0xc0000000)
|
|
return program_read_dword_32be(A);
|
|
|
|
if (A >= 0x40000000)
|
|
return 0xa5a5a5a5;
|
|
|
|
return program_read_dword_32be(A & AM);
|
|
}
|
|
|
|
INLINE void WL(offs_t A, UINT32 V)
|
|
{
|
|
if (A >= 0xe0000000)
|
|
{
|
|
sh2_internal_w(Machine, (A & 0x1fc)>>2, V, 0xffffffff);
|
|
return;
|
|
}
|
|
|
|
if (A >= 0xc0000000)
|
|
{
|
|
program_write_dword_32be(A,V);
|
|
return;
|
|
}
|
|
|
|
if (A >= 0x40000000)
|
|
return;
|
|
|
|
program_write_dword_32be(A & AM,V);
|
|
}
|
|
|
|
static void sh2_timer_resync(void)
|
|
{
|
|
int divider = div_tab[(sh2->m[5] >> 8) & 3];
|
|
UINT64 cur_time = cpunum_gettotalcycles(sh2->cpu_number);
|
|
|
|
if(divider)
|
|
sh2->frc += (cur_time - sh2->frc_base) >> divider;
|
|
sh2->frc_base = cur_time;
|
|
}
|
|
|
|
static void sh2_timer_activate(void)
|
|
{
|
|
int max_delta = 0xfffff;
|
|
UINT16 frc;
|
|
|
|
timer_adjust_oneshot(sh2->timer, attotime_never, 0);
|
|
|
|
frc = sh2->frc;
|
|
if(!(sh2->m[4] & OCFA)) {
|
|
UINT16 delta = sh2->ocra - frc;
|
|
if(delta < max_delta)
|
|
max_delta = delta;
|
|
}
|
|
|
|
if(!(sh2->m[4] & OCFB) && (sh2->ocra <= sh2->ocrb || !(sh2->m[4] & 0x010000))) {
|
|
UINT16 delta = sh2->ocrb - frc;
|
|
if(delta < max_delta)
|
|
max_delta = delta;
|
|
}
|
|
|
|
if(!(sh2->m[4] & OVF) && !(sh2->m[4] & 0x010000)) {
|
|
int delta = 0x10000 - frc;
|
|
if(delta < max_delta)
|
|
max_delta = delta;
|
|
}
|
|
|
|
if(max_delta != 0xfffff) {
|
|
int divider = div_tab[(sh2->m[5] >> 8) & 3];
|
|
if(divider) {
|
|
max_delta <<= divider;
|
|
sh2->frc_base = cpunum_gettotalcycles(sh2->cpu_number);
|
|
timer_adjust_oneshot(sh2->timer, ATTOTIME_IN_CYCLES(max_delta, sh2->cpu_number), sh2->cpu_number);
|
|
} else {
|
|
logerror("SH2.%d: Timer event in %d cycles of external clock", sh2->cpu_number, max_delta);
|
|
}
|
|
}
|
|
}
|
|
|
|
TIMER_CALLBACK( sh2_timer_callback )
|
|
{
|
|
UINT16 frc;
|
|
int cpunum = param;
|
|
|
|
cpuintrf_push_context(cpunum);
|
|
sh2_timer_resync();
|
|
|
|
frc = sh2->frc;
|
|
|
|
if(frc == sh2->ocrb)
|
|
sh2->m[4] |= OCFB;
|
|
|
|
if(frc == 0x0000)
|
|
sh2->m[4] |= OVF;
|
|
|
|
if(frc == sh2->ocra)
|
|
{
|
|
sh2->m[4] |= OCFA;
|
|
|
|
if(sh2->m[4] & 0x010000)
|
|
sh2->frc = 0;
|
|
}
|
|
|
|
sh2_recalc_irq();
|
|
sh2_timer_activate();
|
|
|
|
cpuintrf_pop_context();
|
|
}
|
|
|
|
TIMER_CALLBACK( sh2_dmac_callback )
|
|
{
|
|
int cpunum = param >> 1;
|
|
int dma = param & 1;
|
|
|
|
cpuintrf_push_context(cpunum);
|
|
LOG(("SH2.%d: DMA %d complete\n", cpunum, dma));
|
|
sh2->m[0x63+4*dma] |= 2;
|
|
sh2->dma_timer_active[dma] = 0;
|
|
sh2_recalc_irq();
|
|
cpuintrf_pop_context();
|
|
}
|
|
|
|
static void sh2_dmac_check(int dma)
|
|
{
|
|
if(sh2->m[0x63+4*dma] & sh2->m[0x6c] & 1)
|
|
{
|
|
if(!sh2->dma_timer_active[dma] && !(sh2->m[0x63+4*dma] & 2))
|
|
{
|
|
int incs, incd, size;
|
|
UINT32 src, dst, count;
|
|
incd = (sh2->m[0x63+4*dma] >> 14) & 3;
|
|
incs = (sh2->m[0x63+4*dma] >> 12) & 3;
|
|
size = (sh2->m[0x63+4*dma] >> 10) & 3;
|
|
if(incd == 3 || incs == 3)
|
|
{
|
|
logerror("SH2: DMA: bad increment values (%d, %d, %d, %04x)\n", incd, incs, size, sh2->m[0x63+4*dma]);
|
|
return;
|
|
}
|
|
src = sh2->m[0x60+4*dma];
|
|
dst = sh2->m[0x61+4*dma];
|
|
count = sh2->m[0x62+4*dma];
|
|
if(!count)
|
|
count = 0x1000000;
|
|
|
|
LOG(("SH2: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", dma, src, dst, count, sh2->m[0x63+4*dma], incs, incd, size));
|
|
|
|
sh2->dma_timer_active[dma] = 1;
|
|
timer_adjust_oneshot(sh2->dma_timer[dma], ATTOTIME_IN_CYCLES(2*count+1, sh2->cpu_number), (sh2->cpu_number<<1)|dma);
|
|
|
|
src &= AM;
|
|
dst &= AM;
|
|
|
|
switch(size)
|
|
{
|
|
case 0:
|
|
for(;count > 0; count --)
|
|
{
|
|
if(incs == 2)
|
|
src --;
|
|
if(incd == 2)
|
|
dst --;
|
|
program_write_byte_32be(dst, program_read_byte_32be(src));
|
|
if(incs == 1)
|
|
src ++;
|
|
if(incd == 1)
|
|
dst ++;
|
|
}
|
|
break;
|
|
case 1:
|
|
src &= ~1;
|
|
dst &= ~1;
|
|
for(;count > 0; count --)
|
|
{
|
|
if(incs == 2)
|
|
src -= 2;
|
|
if(incd == 2)
|
|
dst -= 2;
|
|
program_write_word_32be(dst, program_read_word_32be(src));
|
|
if(incs == 1)
|
|
src += 2;
|
|
if(incd == 1)
|
|
dst += 2;
|
|
}
|
|
break;
|
|
case 2:
|
|
src &= ~3;
|
|
dst &= ~3;
|
|
for(;count > 0; count --)
|
|
{
|
|
if(incs == 2)
|
|
src -= 4;
|
|
if(incd == 2)
|
|
dst -= 4;
|
|
program_write_dword_32be(dst, program_read_dword_32be(src));
|
|
if(incs == 1)
|
|
src += 4;
|
|
if(incd == 1)
|
|
dst += 4;
|
|
|
|
}
|
|
break;
|
|
case 3:
|
|
src &= ~3;
|
|
dst &= ~3;
|
|
count &= ~3;
|
|
for(;count > 0; count -= 4)
|
|
{
|
|
if(incd == 2)
|
|
dst -= 16;
|
|
program_write_dword_32be(dst, program_read_dword_32be(src));
|
|
program_write_dword_32be(dst+4, program_read_dword_32be(src+4));
|
|
program_write_dword_32be(dst+8, program_read_dword_32be(src+8));
|
|
program_write_dword_32be(dst+12, program_read_dword_32be(src+12));
|
|
src += 16;
|
|
if(incd == 1)
|
|
dst += 16;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(sh2->dma_timer_active[dma])
|
|
{
|
|
logerror("SH2: DMA %d cancelled in-flight", dma);
|
|
timer_adjust_oneshot(sh2->dma_timer[dma], attotime_never, 0);
|
|
sh2->dma_timer_active[dma] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
WRITE32_HANDLER( sh2_internal_w )
|
|
{
|
|
UINT32 old;
|
|
|
|
#ifdef USE_SH2DRC
|
|
offset &= 0x7f;
|
|
#endif
|
|
|
|
old = sh2->m[offset];
|
|
COMBINE_DATA(sh2->m+offset);
|
|
|
|
// if(offset != 0x20)
|
|
// logerror("sh2_internal_w: Write %08x (%x), %08x @ %08x\n", 0xfffffe00+offset*4, offset, data, mem_mask);
|
|
|
|
// if(offset != 0x20)
|
|
// printf("sh2_internal_w: Write %08x (%x), %08x @ %08x (PC %x)\n", 0xfffffe00+offset*4, offset, data, mem_mask, activecpu_get_pc());
|
|
|
|
switch( offset )
|
|
{
|
|
// Timers
|
|
case 0x04: // TIER, FTCSR, FRC
|
|
if((mem_mask & 0x00ffffff) != 0)
|
|
sh2_timer_resync();
|
|
// printf("SH2.%d: TIER write %04x @ %04x\n", sh2->cpu_number, data >> 16, mem_mask>>16);
|
|
sh2->m[4] = (sh2->m[4] & ~(ICF|OCFA|OCFB|OVF)) | (old & sh2->m[4] & (ICF|OCFA|OCFB|OVF));
|
|
COMBINE_DATA(&sh2->frc);
|
|
if((mem_mask & 0x00ffffff) != 0)
|
|
sh2_timer_activate();
|
|
sh2_recalc_irq();
|
|
break;
|
|
case 0x05: // OCRx, TCR, TOCR
|
|
// printf("SH2.%d: TCR write %08x @ %08x\n", sh2->cpu_number, data, mem_mask);
|
|
sh2_timer_resync();
|
|
if(sh2->m[5] & 0x10)
|
|
sh2->ocrb = (sh2->ocrb & (~mem_mask >> 16)) | ((data & mem_mask) >> 16);
|
|
else
|
|
sh2->ocra = (sh2->ocra & (~mem_mask >> 16)) | ((data & mem_mask) >> 16);
|
|
sh2_timer_activate();
|
|
break;
|
|
|
|
case 0x06: // ICR
|
|
break;
|
|
|
|
// Interrupt vectors
|
|
case 0x18: // IPRB, VCRA
|
|
case 0x19: // VCRB, VCRC
|
|
case 0x1a: // VCRD
|
|
sh2_recalc_irq();
|
|
break;
|
|
|
|
// DMA
|
|
case 0x1c: // DRCR0, DRCR1
|
|
break;
|
|
|
|
// Watchdog
|
|
case 0x20: // WTCNT, RSTCSR
|
|
break;
|
|
|
|
// Standby and cache
|
|
case 0x24: // SBYCR, CCR
|
|
break;
|
|
|
|
// Interrupt vectors cont.
|
|
case 0x38: // ICR, IRPA
|
|
break;
|
|
case 0x39: // VCRWDT
|
|
break;
|
|
|
|
// Division box
|
|
case 0x40: // DVSR
|
|
break;
|
|
case 0x41: // DVDNT
|
|
{
|
|
INT32 a = sh2->m[0x41];
|
|
INT32 b = sh2->m[0x40];
|
|
LOG(("SH2 #%d div+mod %d/%d\n", cpu_getactivecpu(), a, b));
|
|
if (b)
|
|
{
|
|
sh2->m[0x45] = a / b;
|
|
sh2->m[0x44] = a % b;
|
|
}
|
|
else
|
|
{
|
|
sh2->m[0x42] |= 0x00010000;
|
|
sh2->m[0x45] = 0x7fffffff;
|
|
sh2->m[0x44] = 0x7fffffff;
|
|
sh2_recalc_irq();
|
|
}
|
|
break;
|
|
}
|
|
case 0x42: // DVCR
|
|
sh2->m[0x42] = (sh2->m[0x42] & ~0x00001000) | (old & sh2->m[0x42] & 0x00010000);
|
|
sh2_recalc_irq();
|
|
break;
|
|
case 0x43: // VCRDIV
|
|
sh2_recalc_irq();
|
|
break;
|
|
case 0x44: // DVDNTH
|
|
break;
|
|
case 0x45: // DVDNTL
|
|
{
|
|
INT64 a = sh2->m[0x45] | ((UINT64)(sh2->m[0x44]) << 32);
|
|
INT64 b = (INT32)sh2->m[0x40];
|
|
LOG(("SH2 #%d div+mod %lld/%lld\n", cpu_getactivecpu(), a, b));
|
|
if (b)
|
|
{
|
|
INT64 q = a / b;
|
|
if (q != (INT32)q)
|
|
{
|
|
sh2->m[0x42] |= 0x00010000;
|
|
sh2->m[0x45] = 0x7fffffff;
|
|
sh2->m[0x44] = 0x7fffffff;
|
|
sh2_recalc_irq();
|
|
}
|
|
else
|
|
{
|
|
sh2->m[0x45] = q;
|
|
sh2->m[0x44] = a % b;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sh2->m[0x42] |= 0x00010000;
|
|
sh2->m[0x45] = 0x7fffffff;
|
|
sh2->m[0x44] = 0x7fffffff;
|
|
sh2_recalc_irq();
|
|
}
|
|
break;
|
|
}
|
|
|
|
// DMA controller
|
|
case 0x60: // SAR0
|
|
case 0x61: // DAR0
|
|
break;
|
|
case 0x62: // DTCR0
|
|
sh2->m[0x62] &= 0xffffff;
|
|
break;
|
|
case 0x63: // CHCR0
|
|
sh2->m[0x63] = (sh2->m[0x63] & ~2) | (old & sh2->m[0x63] & 2);
|
|
sh2_dmac_check(0);
|
|
break;
|
|
case 0x64: // SAR1
|
|
case 0x65: // DAR1
|
|
break;
|
|
case 0x66: // DTCR1
|
|
sh2->m[0x66] &= 0xffffff;
|
|
break;
|
|
case 0x67: // CHCR1
|
|
sh2->m[0x67] = (sh2->m[0x67] & ~2) | (old & sh2->m[0x67] & 2);
|
|
sh2_dmac_check(1);
|
|
break;
|
|
case 0x68: // VCRDMA0
|
|
case 0x6a: // VCRDMA1
|
|
sh2_recalc_irq();
|
|
break;
|
|
case 0x6c: // DMAOR
|
|
sh2->m[0x6c] = (sh2->m[0x6c] & ~6) | (old & sh2->m[0x6c] & 6);
|
|
sh2_dmac_check(0);
|
|
sh2_dmac_check(1);
|
|
break;
|
|
|
|
// Bus controller
|
|
case 0x78: // BCR1
|
|
case 0x79: // BCR2
|
|
case 0x7a: // WCR
|
|
case 0x7b: // MCR
|
|
case 0x7c: // RTCSR
|
|
case 0x7d: // RTCNT
|
|
case 0x7e: // RTCOR
|
|
break;
|
|
|
|
default:
|
|
logerror("sh2_internal_w: Unmapped write %08x, %08x @ %08x\n", 0xfffffe00+offset*4, data, mem_mask);
|
|
break;
|
|
}
|
|
}
|
|
|
|
READ32_HANDLER( sh2_internal_r )
|
|
{
|
|
#ifdef USE_SH2DRC
|
|
offset &= 0x7f;
|
|
#endif
|
|
// logerror("sh2_internal_r: Read %08x (%x) @ %08x\n", 0xfffffe00+offset*4, offset, mem_mask);
|
|
switch( offset )
|
|
{
|
|
case 0x04: // TIER, FTCSR, FRC
|
|
if ( mem_mask == 0x00ff0000 )
|
|
if ( sh2->ftcsr_read_callback != NULL )
|
|
sh2->ftcsr_read_callback( (sh2->m[4] & 0xffff0000) | sh2->frc );
|
|
sh2_timer_resync();
|
|
return (sh2->m[4] & 0xffff0000) | sh2->frc;
|
|
case 0x05: // OCRx, TCR, TOCR
|
|
if(sh2->m[5] & 0x10)
|
|
return (sh2->ocrb << 16) | (sh2->m[5] & 0xffff);
|
|
else
|
|
return (sh2->ocra << 16) | (sh2->m[5] & 0xffff);
|
|
case 0x06: // ICR
|
|
return sh2->icr << 16;
|
|
|
|
case 0x38: // ICR, IPRA
|
|
return (sh2->m[0x38] & 0x7fffffff) | (sh2->nmi_line_state == ASSERT_LINE ? 0 : 0x80000000);
|
|
|
|
case 0x78: // BCR1
|
|
return sh2->is_slave ? 0x00008000 : 0;
|
|
|
|
case 0x41: // dvdntl mirrors
|
|
case 0x47:
|
|
return sh2->m[0x45];
|
|
|
|
case 0x46: // dvdnth mirror
|
|
return sh2->m[0x44];
|
|
}
|
|
return sh2->m[offset];
|
|
}
|
|
|
|
void sh2_set_frt_input(int cpunum, int state)
|
|
{
|
|
if(state == PULSE_LINE)
|
|
{
|
|
sh2_set_frt_input(cpunum, ASSERT_LINE);
|
|
sh2_set_frt_input(cpunum, CLEAR_LINE);
|
|
return;
|
|
}
|
|
|
|
cpuintrf_push_context(cpunum);
|
|
|
|
if(sh2->frt_input == state) {
|
|
cpuintrf_pop_context();
|
|
return;
|
|
}
|
|
|
|
sh2->frt_input = state;
|
|
|
|
if(sh2->m[5] & 0x8000) {
|
|
if(state == CLEAR_LINE) {
|
|
cpuintrf_pop_context();
|
|
return;
|
|
}
|
|
} else {
|
|
if(state == ASSERT_LINE) {
|
|
cpuintrf_pop_context();
|
|
return;
|
|
}
|
|
}
|
|
|
|
sh2_timer_resync();
|
|
sh2->icr = sh2->frc;
|
|
sh2->m[4] |= ICF;
|
|
logerror("SH2.%d: ICF activated (%x)\n", sh2->cpu_number, sh2->pc & AM);
|
|
sh2_recalc_irq();
|
|
cpuintrf_pop_context();
|
|
}
|
|
|
|
void sh2_set_irq_line(int irqline, int state)
|
|
{
|
|
if (irqline == INPUT_LINE_NMI)
|
|
{
|
|
if (sh2->nmi_line_state == state)
|
|
return;
|
|
sh2->nmi_line_state = state;
|
|
|
|
if( state == CLEAR_LINE )
|
|
{
|
|
LOG(("SH-2 #%d cleared nmi\n", cpu_getactivecpu()));
|
|
}
|
|
else
|
|
{
|
|
LOG(("SH-2 #%d assert nmi\n", cpu_getactivecpu()));
|
|
|
|
sh2_exception("Set IRQ line", 16);
|
|
|
|
#ifdef USE_SH2DRC
|
|
sh2->pending_nmi = 1;
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (sh2->irq_line_state[irqline] == state)
|
|
return;
|
|
sh2->irq_line_state[irqline] = state;
|
|
|
|
if( state == CLEAR_LINE )
|
|
{
|
|
LOG(("SH-2 #%d cleared irq #%d\n", cpu_getactivecpu(), irqline));
|
|
sh2->pending_irq &= ~(1 << irqline);
|
|
}
|
|
else
|
|
{
|
|
LOG(("SH-2 #%d assert irq #%d\n", cpu_getactivecpu(), irqline));
|
|
sh2->pending_irq |= 1 << irqline;
|
|
#ifdef USE_SH2DRC
|
|
sh2->test_irq = 1;
|
|
#else
|
|
if(sh2->delay)
|
|
sh2->test_irq = 1;
|
|
else
|
|
CHECK_PENDING_IRQ("sh2_set_irq_line");
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void sh2_recalc_irq(void)
|
|
{
|
|
int irq = 0, vector = -1;
|
|
int level;
|
|
|
|
// Timer irqs
|
|
if((sh2->m[4]>>8) & sh2->m[4] & (ICF|OCFA|OCFB|OVF))
|
|
{
|
|
level = (sh2->m[0x18] >> 24) & 15;
|
|
if(level > irq)
|
|
{
|
|
int mask = (sh2->m[4]>>8) & sh2->m[4];
|
|
irq = level;
|
|
if(mask & ICF)
|
|
vector = (sh2->m[0x19] >> 8) & 0x7f;
|
|
else if(mask & (OCFA|OCFB))
|
|
vector = sh2->m[0x19] & 0x7f;
|
|
else
|
|
vector = (sh2->m[0x1a] >> 24) & 0x7f;
|
|
}
|
|
}
|
|
|
|
// DMA irqs
|
|
if((sh2->m[0x63] & 6) == 6) {
|
|
level = (sh2->m[0x38] >> 8) & 15;
|
|
if(level > irq) {
|
|
irq = level;
|
|
vector = (sh2->m[0x68] >> 24) & 0x7f;
|
|
}
|
|
}
|
|
|
|
if((sh2->m[0x67] & 6) == 6) {
|
|
level = (sh2->m[0x38] >> 8) & 15;
|
|
if(level > irq) {
|
|
irq = level;
|
|
vector = (sh2->m[0x6a] >> 24) & 0x7f;
|
|
}
|
|
}
|
|
|
|
sh2->internal_irq_level = irq;
|
|
sh2->internal_irq_vector = vector;
|
|
sh2->test_irq = 1;
|
|
}
|
|
|
|
void sh2_exception(const char *message, int irqline)
|
|
{
|
|
int vector;
|
|
|
|
if (irqline != 16)
|
|
{
|
|
if (irqline <= ((sh2->sr >> 4) & 15)) /* If the cpu forbids this interrupt */
|
|
return;
|
|
|
|
// if this is an sh2 internal irq, use its vector
|
|
if (sh2->internal_irq_level == irqline)
|
|
{
|
|
vector = sh2->internal_irq_vector;
|
|
LOG(("SH-2 #%d exception #%d (internal vector: $%x) after [%s]\n", cpu_getactivecpu(), irqline, vector, message));
|
|
}
|
|
else
|
|
{
|
|
if(sh2->m[0x38] & 0x00010000)
|
|
{
|
|
vector = sh2->irq_callback(irqline);
|
|
LOG(("SH-2 #%d exception #%d (external vector: $%x) after [%s]\n", cpu_getactivecpu(), irqline, vector, message));
|
|
}
|
|
else
|
|
{
|
|
sh2->irq_callback(irqline);
|
|
vector = 64 + irqline/2;
|
|
LOG(("SH-2 #%d exception #%d (autovector: $%x) after [%s]\n", cpu_getactivecpu(), irqline, vector, message));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vector = 11;
|
|
LOG(("SH-2 #%d nmi exception (autovector: $%x) after [%s]\n", cpu_getactivecpu(), vector, message));
|
|
}
|
|
|
|
#ifdef USE_SH2DRC
|
|
sh2->evec = RL( sh2->vbr + vector * 4 );
|
|
sh2->evec &= AM;
|
|
sh2->irqsr = sh2->sr;
|
|
|
|
/* set I flags in SR */
|
|
if (irqline > SH2_INT_15)
|
|
sh2->sr = sh2->sr | I;
|
|
else
|
|
sh2->sr = (sh2->sr & ~I) | (irqline << 4);
|
|
|
|
// printf("sh2_exception [%s] irqline %x evec %x save SR %x new SR %x\n", message, irqline, sh2->evec, sh2->irqsr, sh2->sr);
|
|
#else
|
|
sh2->r[15] -= 4;
|
|
WL( sh2->r[15], sh2->sr ); /* push SR onto stack */
|
|
sh2->r[15] -= 4;
|
|
WL( sh2->r[15], sh2->pc ); /* push PC onto stack */
|
|
|
|
/* set I flags in SR */
|
|
if (irqline > SH2_INT_15)
|
|
sh2->sr = sh2->sr | I;
|
|
else
|
|
sh2->sr = (sh2->sr & ~I) | (irqline << 4);
|
|
|
|
/* fetch PC */
|
|
sh2->pc = RL( sh2->vbr + vector * 4 );
|
|
change_pc(sh2->pc & AM);
|
|
#endif
|
|
}
|
|
|
|
void sh2_common_init(int alloc, int index, int clock, const void *config, int (*irqcallback)(int))
|
|
{
|
|
const sh2_cpu_core *conf = config;
|
|
|
|
if (alloc)
|
|
{
|
|
sh2 = (SH2 *)auto_malloc(sizeof(SH2));
|
|
memset(sh2, 0, sizeof(SH2));
|
|
}
|
|
|
|
sh2->timer = timer_alloc(sh2_timer_callback, NULL);
|
|
timer_adjust_oneshot(sh2->timer, attotime_never, 0);
|
|
|
|
sh2->dma_timer[0] = timer_alloc(sh2_dmac_callback, NULL);
|
|
timer_adjust_oneshot(sh2->dma_timer[0], attotime_never, 0);
|
|
|
|
sh2->dma_timer[1] = timer_alloc(sh2_dmac_callback, NULL);
|
|
timer_adjust_oneshot(sh2->dma_timer[1], attotime_never, 0);
|
|
|
|
sh2->m = auto_malloc(0x200);
|
|
|
|
if(conf)
|
|
sh2->is_slave = conf->is_slave;
|
|
else
|
|
sh2->is_slave = 0;
|
|
|
|
sh2->cpu_number = index;
|
|
sh2->irq_callback = irqcallback;
|
|
|
|
state_save_register_item("sh2", index, sh2->pc);
|
|
state_save_register_item("sh2", index, sh2->r[15]);
|
|
state_save_register_item("sh2", index, sh2->sr);
|
|
state_save_register_item("sh2", index, sh2->pr);
|
|
state_save_register_item("sh2", index, sh2->gbr);
|
|
state_save_register_item("sh2", index, sh2->vbr);
|
|
state_save_register_item("sh2", index, sh2->mach);
|
|
state_save_register_item("sh2", index, sh2->macl);
|
|
state_save_register_item("sh2", index, sh2->r[ 0]);
|
|
state_save_register_item("sh2", index, sh2->r[ 1]);
|
|
state_save_register_item("sh2", index, sh2->r[ 2]);
|
|
state_save_register_item("sh2", index, sh2->r[ 3]);
|
|
state_save_register_item("sh2", index, sh2->r[ 4]);
|
|
state_save_register_item("sh2", index, sh2->r[ 5]);
|
|
state_save_register_item("sh2", index, sh2->r[ 6]);
|
|
state_save_register_item("sh2", index, sh2->r[ 7]);
|
|
state_save_register_item("sh2", index, sh2->r[ 8]);
|
|
state_save_register_item("sh2", index, sh2->r[ 9]);
|
|
state_save_register_item("sh2", index, sh2->r[10]);
|
|
state_save_register_item("sh2", index, sh2->r[11]);
|
|
state_save_register_item("sh2", index, sh2->r[12]);
|
|
state_save_register_item("sh2", index, sh2->r[13]);
|
|
state_save_register_item("sh2", index, sh2->r[14]);
|
|
state_save_register_item("sh2", index, sh2->ea);
|
|
}
|
|
|