summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/sh/sh2comn.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/sh/sh2comn.cpp')
-rw-r--r--src/devices/cpu/sh/sh2comn.cpp1023
1 files changed, 645 insertions, 378 deletions
diff --git a/src/devices/cpu/sh/sh2comn.cpp b/src/devices/cpu/sh/sh2comn.cpp
index 8accaaf8ebb..e9503099fc2 100644
--- a/src/devices/cpu/sh/sh2comn.cpp
+++ b/src/devices/cpu/sh/sh2comn.cpp
@@ -22,7 +22,8 @@ static const int div_tab[4] = { 3, 5, 7, 0 };
void sh2_device::sh2_timer_resync()
{
- int divider = div_tab[(m_m[5] >> 8) & 3];
+ // TODO: setting 3 is "External clock: count on rising edge"
+ int divider = div_tab[m_frc_tcr & 3];
uint64_t cur_time = total_cycles();
uint64_t add = (cur_time - m_frc_base) >> divider;
@@ -43,26 +44,26 @@ void sh2_device::sh2_timer_activate()
m_timer->adjust(attotime::never);
frc = m_frc;
- if(!(m_m[4] & OCFA)) {
+ if(!(m_ftcsr & OCFA)) {
uint16_t delta = m_ocra - frc;
if(delta < max_delta)
max_delta = delta;
}
- if(!(m_m[4] & OCFB) && (m_ocra <= m_ocrb || !(m_m[4] & 0x010000))) {
+ if(!(m_ftcsr & OCFB) && (m_ocra <= m_ocrb || !(m_ftcsr & CCLRA))) {
uint16_t delta = m_ocrb - frc;
if(delta < max_delta)
max_delta = delta;
}
- if(!(m_m[4] & OVF) && !(m_m[4] & 0x010000)) {
+ if(!(m_ftcsr & OVF) && !(m_ftcsr & CCLRA)) {
int delta = 0x10000 - frc;
if(delta < max_delta)
max_delta = delta;
}
if(max_delta != 0xfffff) {
- int divider = div_tab[(m_m[5] >> 8) & 3];
+ int divider = div_tab[m_frc_tcr & 3];
if(divider) {
max_delta <<= divider;
m_frc_base = total_cycles();
@@ -82,16 +83,16 @@ TIMER_CALLBACK_MEMBER( sh2_device::sh2_timer_callback )
frc = m_frc;
if(frc == m_ocrb)
- m_m[4] |= OCFB;
+ m_ftcsr |= OCFB;
if(frc == 0x0000)
- m_m[4] |= OVF;
+ m_ftcsr |= OVF;
if(frc == m_ocra)
{
- m_m[4] |= OCFA;
+ m_ftcsr |= OCFA;
- if(m_m[4] & 0x010000)
+ if(m_ftcsr & CCLRA)
m_frc = 0;
}
@@ -128,30 +129,30 @@ void sh2_device::sh2_notify_dma_data_available()
{
//printf("call notify\n");
- for (int dma=0;dma<2;dma++)
+ for (int dmach=0;dmach<2;dmach++)
{
- //printf("m_dma_timer_active[dma] %04x\n",m_dma_timer_active[dma]);
+ //printf("m_dma_timer_active[dmach] %04x\n",m_dma_timer_active[dmach]);
- if (m_dma_timer_active[dma]==2) // 2 = stalled
+ if (m_dma_timer_active[dmach]==2) // 2 = stalled
{
// printf("resuming stalled dma\n");
- m_dma_timer_active[dma]=1;
- m_dma_current_active_timer[dma]->adjust(attotime::zero, dma);
+ m_dma_timer_active[dmach]=1;
+ m_dma_current_active_timer[dmach]->adjust(attotime::zero, dmach);
}
}
}
-void sh2_device::sh2_do_dma(int dma)
+void sh2_device::sh2_do_dma(int dmach)
{
uint32_t dmadata;
uint32_t tempsrc, tempdst;
- if (m_active_dma_count[dma] > 0)
+ if (m_active_dma_count[dmach] > 0)
{
// process current DMA
- switch(m_active_dma_size[dma])
+ switch(m_active_dma_size[dmach])
{
case 0:
{
@@ -159,188 +160,188 @@ void sh2_device::sh2_do_dma(int dma)
// to allow for the callback to check if we can process the DMA at this
// time (we need to know where we're reading / writing to/from)
- if(m_active_dma_incs[dma] == 2)
- tempsrc = m_active_dma_src[dma] - 1;
+ if(m_active_dma_incs[dmach] == 2)
+ tempsrc = m_active_dma_src[dmach] - 1;
else
- tempsrc = m_active_dma_src[dma];
+ tempsrc = m_active_dma_src[dmach];
- if(m_active_dma_incd[dma] == 2)
- tempdst = m_active_dma_dst[dma] - 1;
+ if(m_active_dma_incd[dmach] == 2)
+ tempdst = m_active_dma_dst[dmach] - 1;
else
- tempdst = m_active_dma_dst[dma];
+ tempdst = m_active_dma_dst[dmach];
if (!m_dma_fifo_data_available_cb.isnull())
{
- int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]);
+ int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dmach]);
if (!available)
{
//printf("dma stalled\n");
- m_dma_timer_active[dma]=2;// mark as stalled
+ m_dma_timer_active[dmach]=2;// mark as stalled
return;
}
}
//schedule next DMA callback
- m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma);
+ m_dma_current_active_timer[dmach]->adjust(cycles_to_attotime(2), dmach);
dmadata = m_program->read_byte(tempsrc);
- if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dmach]);
m_program->write_byte(tempdst, dmadata);
- if(m_active_dma_incs[dma] == 2)
- m_active_dma_src[dma] --;
- if(m_active_dma_incd[dma] == 2)
- m_active_dma_dst[dma] --;
+ if(m_active_dma_incs[dmach] == 2)
+ m_active_dma_src[dmach] --;
+ if(m_active_dma_incd[dmach] == 2)
+ m_active_dma_dst[dmach] --;
- if(m_active_dma_incs[dma] == 1)
- m_active_dma_src[dma] ++;
- if(m_active_dma_incd[dma] == 1)
- m_active_dma_dst[dma] ++;
+ if(m_active_dma_incs[dmach] == 1)
+ m_active_dma_src[dmach] ++;
+ if(m_active_dma_incd[dmach] == 1)
+ m_active_dma_dst[dmach] ++;
- m_active_dma_count[dma] --;
+ m_active_dma_count[dmach] --;
}
break;
case 1:
{
- if(m_active_dma_incs[dma] == 2)
- tempsrc = m_active_dma_src[dma] - 2;
+ if(m_active_dma_incs[dmach] == 2)
+ tempsrc = m_active_dma_src[dmach] - 2;
else
- tempsrc = m_active_dma_src[dma];
+ tempsrc = m_active_dma_src[dmach];
- if(m_active_dma_incd[dma] == 2)
- tempdst = m_active_dma_dst[dma] - 2;
+ if(m_active_dma_incd[dmach] == 2)
+ tempdst = m_active_dma_dst[dmach] - 2;
else
- tempdst = m_active_dma_dst[dma];
+ tempdst = m_active_dma_dst[dmach];
if (!m_dma_fifo_data_available_cb.isnull())
{
- int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]);
+ int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dmach]);
if (!available)
{
//printf("dma stalled\n");
- m_dma_timer_active[dma]=2;// mark as stalled
+ m_dma_timer_active[dmach]=2;// mark as stalled
return;
}
}
//schedule next DMA callback
- m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma);
+ m_dma_current_active_timer[dmach]->adjust(cycles_to_attotime(2), dmach);
// check: should this really be using read_word_32 / write_word_32?
dmadata = m_program->read_word(tempsrc);
- if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dmach]);
m_program->write_word(tempdst, dmadata);
- if(m_active_dma_incs[dma] == 2)
- m_active_dma_src[dma] -= 2;
- if(m_active_dma_incd[dma] == 2)
- m_active_dma_dst[dma] -= 2;
+ if(m_active_dma_incs[dmach] == 2)
+ m_active_dma_src[dmach] -= 2;
+ if(m_active_dma_incd[dmach] == 2)
+ m_active_dma_dst[dmach] -= 2;
- if(m_active_dma_incs[dma] == 1)
- m_active_dma_src[dma] += 2;
- if(m_active_dma_incd[dma] == 1)
- m_active_dma_dst[dma] += 2;
+ if(m_active_dma_incs[dmach] == 1)
+ m_active_dma_src[dmach] += 2;
+ if(m_active_dma_incd[dmach] == 1)
+ m_active_dma_dst[dmach] += 2;
- m_active_dma_count[dma] --;
+ m_active_dma_count[dmach] --;
}
break;
case 2:
{
- if(m_active_dma_incs[dma] == 2)
- tempsrc = m_active_dma_src[dma] - 4;
+ if(m_active_dma_incs[dmach] == 2)
+ tempsrc = m_active_dma_src[dmach] - 4;
else
- tempsrc = m_active_dma_src[dma];
+ tempsrc = m_active_dma_src[dmach];
- if(m_active_dma_incd[dma] == 2)
- tempdst = m_active_dma_dst[dma] - 4;
+ if(m_active_dma_incd[dmach] == 2)
+ tempdst = m_active_dma_dst[dmach] - 4;
else
- tempdst = m_active_dma_dst[dma];
+ tempdst = m_active_dma_dst[dmach];
if (!m_dma_fifo_data_available_cb.isnull())
{
- int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]);
+ int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dmach]);
if (!available)
{
//printf("dma stalled\n");
- m_dma_timer_active[dma]=2;// mark as stalled
+ m_dma_timer_active[dmach]=2;// mark as stalled
return;
}
}
//schedule next DMA callback
- m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma);
+ m_dma_current_active_timer[dmach]->adjust(cycles_to_attotime(2), dmach);
dmadata = m_program->read_dword(tempsrc);
- if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dmach]);
m_program->write_dword(tempdst, dmadata);
- if(m_active_dma_incs[dma] == 2)
- m_active_dma_src[dma] -= 4;
- if(m_active_dma_incd[dma] == 2)
- m_active_dma_dst[dma] -= 4;
+ if(m_active_dma_incs[dmach] == 2)
+ m_active_dma_src[dmach] -= 4;
+ if(m_active_dma_incd[dmach] == 2)
+ m_active_dma_dst[dmach] -= 4;
- if(m_active_dma_incs[dma] == 1)
- m_active_dma_src[dma] += 4;
- if(m_active_dma_incd[dma] == 1)
- m_active_dma_dst[dma] += 4;
+ if(m_active_dma_incs[dmach] == 1)
+ m_active_dma_src[dmach] += 4;
+ if(m_active_dma_incd[dmach] == 1)
+ m_active_dma_dst[dmach] += 4;
- m_active_dma_count[dma] --;
+ m_active_dma_count[dmach] --;
}
break;
case 3:
{
// shouldn't this really be 4 calls here instead?
- tempsrc = m_active_dma_src[dma];
+ tempsrc = m_active_dma_src[dmach];
- if(m_active_dma_incd[dma] == 2)
- tempdst = m_active_dma_dst[dma] - 16;
+ if(m_active_dma_incd[dmach] == 2)
+ tempdst = m_active_dma_dst[dmach] - 16;
else
- tempdst = m_active_dma_dst[dma];
+ tempdst = m_active_dma_dst[dmach];
if (!m_dma_fifo_data_available_cb.isnull())
{
- int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dma]);
+ int available = m_dma_fifo_data_available_cb(tempsrc, tempdst, 0, m_active_dma_size[dmach]);
if (!available)
{
//printf("dma stalled\n");
- m_dma_timer_active[dma]=2;// mark as stalled
+ m_dma_timer_active[dmach]=2;// mark as stalled
fatalerror("SH2 dma_callback_fifo_data_available == 0 in unsupported mode\n");
}
}
//schedule next DMA callback
- m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma);
+ m_dma_current_active_timer[dmach]->adjust(cycles_to_attotime(2), dmach);
dmadata = m_program->read_dword(tempsrc);
- if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dmach]);
m_program->write_dword(tempdst, dmadata);
dmadata = m_program->read_dword(tempsrc+4);
- if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dmach]);
m_program->write_dword(tempdst+4, dmadata);
dmadata = m_program->read_dword(tempsrc+8);
- if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dmach]);
m_program->write_dword(tempdst+8, dmadata);
dmadata = m_program->read_dword(tempsrc+12);
- if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dma]);
+ if (!m_dma_kludge_cb.isnull()) dmadata = m_dma_kludge_cb(tempsrc, tempdst, dmadata, m_active_dma_size[dmach]);
m_program->write_dword(tempdst+12, dmadata);
- if(m_active_dma_incd[dma] == 2)
- m_active_dma_dst[dma] -= 16;
+ if(m_active_dma_incd[dmach] == 2)
+ m_active_dma_dst[dmach] -= 16;
- m_active_dma_src[dma] += 16;
- if(m_active_dma_incd[dma] == 1)
- m_active_dma_dst[dma] += 16;
+ m_active_dma_src[dmach] += 16;
+ if(m_active_dma_incd[dmach] == 1)
+ m_active_dma_dst[dmach] += 16;
- m_active_dma_count[dma]-=4;
+ m_active_dma_count[dmach]-=4;
}
break;
}
@@ -350,17 +351,17 @@ void sh2_device::sh2_do_dma(int dma)
// int dma = param & 1;
// fever soccer uses cycle-stealing mode, resume the CPU now DMA has finished
- if (m_active_dma_steal[dma])
+ if (m_active_dma_steal[dmach])
{
resume(SUSPEND_REASON_HALT );
}
- LOG("SH2: DMA %d complete\n", dma);
- m_m[0x62+4*dma] = 0;
- m_m[0x63+4*dma] |= 2;
- m_dma_timer_active[dma] = 0;
- m_dma_irq[dma] |= 1;
+ LOG("SH2: DMA %d complete\n", dmach);
+ m_dmac[dmach].tcr = 0;
+ m_dmac[dmach].chcr |= 2;
+ m_dma_timer_active[dmach] = 0;
+ m_dma_irq[dmach] |= 1;
sh2_recalc_irq();
}
@@ -374,146 +375,489 @@ TIMER_CALLBACK_MEMBER( sh2_device::sh2_dma_current_active_callback )
}
-void sh2_device::sh2_dmac_check(int dma)
+void sh2_device::sh2_dmac_check(int dmach)
{
- if(m_m[0x63+4*dma] & m_m[0x6c] & 1)
+ if(m_dmac[dmach].chcr & m_dmaor & 1)
{
- if(!m_dma_timer_active[dma] && !(m_m[0x63+4*dma] & 2))
+ if(!m_dma_timer_active[dmach] && !(m_dmac[dmach].chcr & 2))
{
- m_active_dma_incd[dma] = (m_m[0x63+4*dma] >> 14) & 3;
- m_active_dma_incs[dma] = (m_m[0x63+4*dma] >> 12) & 3;
- m_active_dma_size[dma] = (m_m[0x63+4*dma] >> 10) & 3;
- m_active_dma_steal[dma] = (m_m[0x63+4*dma] &0x10);
+ m_active_dma_incd[dmach] = (m_dmac[dmach].chcr >> 14) & 3;
+ m_active_dma_incs[dmach] = (m_dmac[dmach].chcr >> 12) & 3;
+ m_active_dma_size[dmach] = (m_dmac[dmach].chcr >> 10) & 3;
+ m_active_dma_steal[dmach] = (m_dmac[dmach].chcr & 0x10);
- if(m_active_dma_incd[dma] == 3 || m_active_dma_incs[dma] == 3)
+ if(m_active_dma_incd[dmach] == 3 || m_active_dma_incs[dmach] == 3)
{
- logerror("SH2: DMA: bad increment values (%d, %d, %d, %04x)\n", m_active_dma_incd[dma], m_active_dma_incs[dma], m_active_dma_size[dma], m_m[0x63+4*dma]);
+ logerror("SH2: DMA: bad increment values (%d, %d, %d, %04x)\n", m_active_dma_incd[dmach], m_active_dma_incs[dmach], m_active_dma_size[dmach], m_dmac[dmach].chcr);
return;
}
- m_active_dma_src[dma] = m_m[0x60+4*dma];
- m_active_dma_dst[dma] = m_m[0x61+4*dma];
- m_active_dma_count[dma] = m_m[0x62+4*dma];
- if(!m_active_dma_count[dma])
- m_active_dma_count[dma] = 0x1000000;
+ m_active_dma_src[dmach] = m_dmac[dmach].sar;
+ m_active_dma_dst[dmach] = m_dmac[dmach].dar;
+ m_active_dma_count[dmach] = m_dmac[dmach].tcr;
+ if(!m_active_dma_count[dmach])
+ m_active_dma_count[dmach] = 0x1000000;
- LOG("SH2: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", dma, m_active_dma_src[dma], m_active_dma_dst[dma], m_active_dma_count[dma], m_m[0x63+4*dma], m_active_dma_incs[dma], m_active_dma_incd[dma], m_active_dma_size[dma]);
+ LOG("SH2: DMA %d start %x, %x, %x, %04x, %d, %d, %d\n", dmach, m_active_dma_src[dmach], m_active_dma_dst[dmach], m_active_dma_count[dmach], m_dmac[dmach].chcr, m_active_dma_incs[dmach], m_active_dma_incd[dmach], m_active_dma_size[dmach]);
- m_dma_timer_active[dma] = 1;
+ m_dma_timer_active[dmach] = 1;
- m_active_dma_src[dma] &= SH12_AM;
- m_active_dma_dst[dma] &= SH12_AM;
+ m_active_dma_src[dmach] &= SH12_AM;
+ m_active_dma_dst[dmach] &= SH12_AM;
- switch(m_active_dma_size[dma])
+ switch(m_active_dma_size[dmach])
{
case 0:
break;
case 1:
- m_active_dma_src[dma] &= ~1;
- m_active_dma_dst[dma] &= ~1;
+ m_active_dma_src[dmach] &= ~1;
+ m_active_dma_dst[dmach] &= ~1;
break;
case 2:
- m_active_dma_src[dma] &= ~3;
- m_active_dma_dst[dma] &= ~3;
+ m_active_dma_src[dmach] &= ~3;
+ m_active_dma_dst[dmach] &= ~3;
break;
case 3:
- m_active_dma_src[dma] &= ~3;
- m_active_dma_dst[dma] &= ~3;
- m_active_dma_count[dma] &= ~3;
+ m_active_dma_src[dmach] &= ~3;
+ m_active_dma_dst[dmach] &= ~3;
+ m_active_dma_count[dmach] &= ~3;
break;
}
// start DMA timer
// fever soccer uses cycle-stealing mode, requiring the CPU to be halted
- if (m_active_dma_steal[dma])
+ if (m_active_dma_steal[dmach])
{
//printf("cycle stealing DMA\n");
suspend(SUSPEND_REASON_HALT, 1 );
}
- m_dma_current_active_timer[dma]->adjust(cycles_to_attotime(2), dma);
+ m_dma_current_active_timer[dmach]->adjust(cycles_to_attotime(2), dmach);
}
}
else
{
- if(m_dma_timer_active[dma])
+ if(m_dma_timer_active[dmach])
{
- logerror("SH2: DMA %d cancelled in-flight\n", dma);
- //m_dma_complete_timer[dma]->adjust(attotime::never);
- m_dma_current_active_timer[dma]->adjust(attotime::never);
+ logerror("SH2: DMA %d cancelled in-flight\n", dmach);
+ //m_dma_complete_timer[dmach]->adjust(attotime::never);
+ m_dma_current_active_timer[dmach]->adjust(attotime::never, dmach);
- m_dma_timer_active[dma] = 0;
+ m_dma_timer_active[dmach] = 0;
}
}
}
+/*
+ * SCI
+ */
+// TODO: identical to H8 counterpart
+
+READ8_MEMBER( sh2_device::smr_r )
+{
+ return m_smr;
+}
+
+WRITE8_MEMBER( sh2_device::smr_w )
+{
+ m_smr = data;
+}
+
+READ8_MEMBER( sh2_device::brr_r )
+{
+ return m_brr;
+}
+
+WRITE8_MEMBER( sh2_device::brr_w )
+{
+ m_brr = data;
+}
+
+READ8_MEMBER( sh2_device::scr_r )
+{
+ return m_scr;
+}
+
+WRITE8_MEMBER( sh2_device::scr_w )
+{
+ m_scr = data;
+}
+
+READ8_MEMBER( sh2_device::tdr_r )
+{
+ return m_tdr;
+}
+
+WRITE8_MEMBER( sh2_device::tdr_w )
+{
+ m_tdr = data;
+ // printf("%c",data & 0xff);
+}
+
+READ8_MEMBER( sh2_device::ssr_r )
+{
+ // 0x84 is needed by EGWord on Saturn to make it to boot for some reason.
+ return m_ssr | 0x84;
+}
+
+WRITE8_MEMBER( sh2_device::ssr_w )
+{
+ m_ssr = data;
+}
+
+READ8_MEMBER( sh2_device::rdr_r )
+{
+ return 0;
+}
+
+/*
+ * FRC
+ */
+
+READ8_MEMBER( sh2_device::tier_r )
+{
+ return m_tier;
+}
+
+WRITE8_MEMBER( sh2_device::tier_w )
+{
+ sh2_timer_resync();
+ m_tier = data;
+ sh2_timer_activate();
+ sh2_recalc_irq();
+}
+
+READ8_MEMBER( sh2_device::ftcsr_r )
+{
+ // TODO: to be tested
+ if (!m_ftcsr_read_cb.isnull())
+ m_ftcsr_read_cb((((m_tier<<24) | (m_ftcsr<<16)) & 0xffff0000) | m_frc);
+
+ return m_ftcsr;
+}
+
+WRITE8_MEMBER( sh2_device::ftcsr_w )
+{
+ uint8_t old;
+ old = m_ftcsr;
+
+ m_ftcsr = data;
+ sh2_timer_resync();
+ m_ftcsr = (m_ftcsr & ~(ICF|OCFA|OCFB|OVF)) | (old & m_ftcsr & (ICF|OCFA|OCFB|OVF));
+ sh2_timer_activate();
+ sh2_recalc_irq();
+}
+
+READ16_MEMBER( sh2_device::frc_r )
+{
+ sh2_timer_resync();
+ return m_frc;
+}
+
+WRITE16_MEMBER( sh2_device::frc_w )
+{
+ sh2_timer_resync();
+ COMBINE_DATA(&m_frc);
+ sh2_timer_activate();
+ sh2_recalc_irq();
+}
+
+READ16_MEMBER( sh2_device::ocra_b_r )
+{
+ return (m_tocr & 0x10) ? m_ocrb : m_ocra;
+}
+
+WRITE16_MEMBER( sh2_device::ocra_b_w )
+{
+ sh2_timer_resync();
+ if(m_tocr & 0x10)
+ m_ocrb = (m_ocrb & (~mem_mask)) | (data & mem_mask);
+ else
+ m_ocra = (m_ocra & (~mem_mask)) | (data & mem_mask);
+ sh2_timer_activate();
+ sh2_recalc_irq();
+}
+
+READ8_MEMBER( sh2_device::frc_tcr_r )
+{
+ return m_frc_tcr & 0x83;
+}
+
+WRITE8_MEMBER( sh2_device::frc_tcr_w )
+{
+ sh2_timer_resync();
+ m_frc_tcr = data & 0x83;
+ sh2_timer_activate();
+ sh2_recalc_irq();
+}
+
+READ8_MEMBER( sh2_device::tocr_r )
+{
+ return (m_tocr & 0x13) | 0xe0;
+}
+
+WRITE8_MEMBER( sh2_device::tocr_w )
+{
+ sh2_timer_resync();
+ // TODO: output levels A/B (bits 1-0)
+ m_tocr = data & 0x13;
+ sh2_timer_activate();
+ sh2_recalc_irq();
+}
+
+READ16_MEMBER( sh2_device::frc_icr_r )
+{
+ return m_frc_icr;
+}
+
+/*
+ * INTC
+ */
+
+READ16_MEMBER( sh2_device::intc_icr_r )
+{
+ // TODO: flip meaning based off NMI edge select bit (NMIE)
+ uint16_t nmilv = m_nmi_line_state == ASSERT_LINE ? 0 : 0x8000;
+ return (nmilv) | (m_intc_icr & 0x0101);
+}
+
+WRITE16_MEMBER( sh2_device::intc_icr_w )
+{
+ COMBINE_DATA(&m_intc_icr);
+ m_nmie = bool(BIT(m_intc_icr, 8));
+ m_vecmd = bool(BIT(m_intc_icr, 0));
+}
+
+READ16_MEMBER( sh2_device::ipra_r )
+{
+ return m_ipra & 0xfff0;
+}
+
+WRITE16_MEMBER( sh2_device::ipra_w )
+{
+ COMBINE_DATA(&m_ipra);
+ m_irq_level.divu = (m_ipra >> 12) & 0xf;
+ m_irq_level.dmac = (m_ipra >> 8) & 0xf;
+ m_irq_level.wdt = (m_ipra >> 4) & 0xf;
+ sh2_recalc_irq();
+}
+
+READ16_MEMBER( sh2_device::iprb_r )
+{
+ return m_iprb & 0xff00;
+}
+
+WRITE16_MEMBER( sh2_device::iprb_w )
+{
+ COMBINE_DATA(&m_iprb);
+ m_irq_level.sci = (m_iprb >> 12) & 0xf;
+ m_irq_level.frc = (m_iprb >> 8) & 0xf;
+ sh2_recalc_irq();
+}
+
+READ16_MEMBER( sh2_device::vcra_r )
+{
+ return m_vcra & 0x7f7f;
+}
+
+WRITE16_MEMBER( sh2_device::vcra_w )
+{
+ COMBINE_DATA(&m_vcra);
+ // ...
+ sh2_recalc_irq();
+}
+
+READ16_MEMBER( sh2_device::vcrb_r )
+{
+ return m_vcrb;
+}
+
+WRITE16_MEMBER( sh2_device::vcrb_w )
+{
+ COMBINE_DATA(&m_vcrb);
+ // ...
+ sh2_recalc_irq();
+}
+
+READ16_MEMBER( sh2_device::vcrc_r )
+{
+ return m_vcrc & 0x7f7f;
+}
+
+WRITE16_MEMBER( sh2_device::vcrc_w )
+{
+ COMBINE_DATA(&m_vcrc);
+ m_irq_vector.fic = (m_vcrc >> 8) & 0x7f;
+ m_irq_vector.foc = (m_vcrc >> 0) & 0x7f;
+ sh2_recalc_irq();
+}
+
+READ16_MEMBER( sh2_device::vcrd_r )
+{
+ return m_vcrd & 0x7f00;
+}
+
+WRITE16_MEMBER( sh2_device::vcrd_w )
+{
+ COMBINE_DATA(&m_vcrd);
+ m_irq_vector.fov = (m_vcrc >> 8) & 0x7f;
+ sh2_recalc_irq();
+}
+
+READ16_MEMBER( sh2_device::vcrwdt_r )
+{
+ return m_vcrwdt & 0x7f7f;
+}
-WRITE32_MEMBER( sh2_device::sh7604_w )
+WRITE16_MEMBER( sh2_device::vcrwdt_w )
{
- uint32_t old;
+ COMBINE_DATA(&m_vcrwdt);
+ // ...
+ sh2_recalc_irq();
+}
- old = m_m[offset];
- COMBINE_DATA(m_m+offset);
+READ32_MEMBER( sh2_device::vcrdiv_r )
+{
+ return m_vcrdiv & 0x7f;
+}
- // if(offset != 0x20)
- // logerror("sh2_internal_w: Write %08x (%x), %08x @ %08x\n", 0xfffffe00+offset*4, offset, data, mem_mask);
+WRITE32_MEMBER( sh2_device::vcrdiv_w )
+{
+ COMBINE_DATA(&m_vcrdiv);
+ // TODO: unemulated, level is seemingly not documented/settable?
+ m_irq_vector.divu = data & 0x7f;
+ sh2_recalc_irq();
+}
-// if(offset != 0x20)
-// printf("sh2_internal_w: Write %08x (%x), %08x @ %08x (PC %x)\n", 0xfffffe00+offset*4, offset, data, mem_mask, pc());
+READ32_MEMBER( sh2_device::dvcr_r )
+{
+ return (m_divu_ovfie == true ? 2 : 0) | (m_divu_ovf == true ? 1 : 0);
+}
- switch( offset )
+WRITE32_MEMBER( sh2_device::dvcr_w )
+{
+ if(ACCESSING_BITS_0_7)
{
- case 0x00:
- //if(mem_mask == 0xff)
- // printf("%c",data & 0xff);
- break;
- case 0x01:
- //printf("%08x %02x %02x\n",mem_mask,offset,data);
- break;
- // Timers
- case 0x04: // TIER, FTCSR, FRC
- if((mem_mask & 0x00ffffff) != 0)
+ if (data & 1)
+ m_divu_ovf = false;
+ if (data & 2)
{
- sh2_timer_resync();
+ m_divu_ovfie = bool(BIT(data, 1));
+ if (m_divu_ovfie == true)
+ LOG("SH2: unemulated DIVU OVF interrupt enable\n");
}
-// printf("SH2.%s: TIER write %04x @ %04x\n", m_device->tag(), data >> 16, mem_mask>>16);
- m_m[4] = (m_m[4] & ~(ICF|OCFA|OCFB|OVF)) | (old & m_m[4] & (ICF|OCFA|OCFB|OVF));
- COMBINE_DATA(&m_frc);
- if((mem_mask & 0x00ffffff) != 0)
- sh2_timer_activate();
sh2_recalc_irq();
- break;
- case 0x05: // OCRx, TCR, TOCR
-// printf("SH2.%s: TCR write %08x @ %08x\n", m_device->tag(), data, mem_mask);
- sh2_timer_resync();
- if(m_m[5] & 0x10)
- m_ocrb = (m_ocrb & (~mem_mask >> 16)) | ((data & mem_mask) >> 16);
- else
- m_ocra = (m_ocra & (~mem_mask >> 16)) | ((data & mem_mask) >> 16);
- sh2_timer_activate();
- break;
+ }
+}
+
+/*
+ * DMAC
+ */
- case 0x06: // ICR
- break;
+READ32_MEMBER( sh2_device::dvsr_r )
+{
+ return m_dvsr;
+}
- // Interrupt vectors
- case 0x18: // IPRB, VCRA
- case 0x19: // VCRB, VCRC
- case 0x1a: // VCRD
+WRITE32_MEMBER( sh2_device::dvsr_w )
+{
+ COMBINE_DATA(&m_dvsr);
+}
+
+READ32_MEMBER( sh2_device::dvdnt_r )
+{
+ return m_dvdntl;
+}
+
+WRITE32_MEMBER( sh2_device::dvdnt_w )
+{
+ COMBINE_DATA(&m_dvdntl);
+ int32_t a = m_dvdntl;
+ int32_t b = m_dvsr;
+ LOG("SH2 div32+mod %d/%d\n", a, b);
+ if (b)
+ {
+ m_dvdntl = a / b;
+ m_dvdnth = a % b;
+ }
+ else
+ {
+ m_divu_ovf = true;
+ m_dvdntl = 0x7fffffff;
+ m_dvdnth = 0x7fffffff;
sh2_recalc_irq();
- break;
+ }
+}
- // DMA
- case 0x1c: // DRCR0, DRCR1
- break;
+READ32_MEMBER( sh2_device::dvdnth_r )
+{
+ return m_dvdnth;
+}
- // Watchdog
- case 0x20: // WTCNT, RSTCSR
- if((m_m[0x20] & 0xff000000) == 0x5a000000)
- m_wtcnt = (m_m[0x20] >> 16) & 0xff;
+READ32_MEMBER( sh2_device::dvdntl_r )
+{
+ return m_dvdntl;
+}
- if((m_m[0x20] & 0xff000000) == 0xa5000000)
+WRITE32_MEMBER( sh2_device::dvdnth_w )
+{
+ COMBINE_DATA(&m_dvdnth);
+}
+
+WRITE32_MEMBER( sh2_device::dvdntl_w )
+{
+ COMBINE_DATA(&m_dvdntl);
+ int64_t a = m_dvdntl | ((uint64_t)(m_dvdnth) << 32);
+ int64_t b = (int32_t)m_dvsr;
+ LOG("SH2 div64+mod %d/%d\n", a, b);
+ if (b)
+ {
+ int64_t q = a / b;
+ if (q != (int32_t)q)
{
+ m_divu_ovf = true;
+ m_dvdntl = 0x7fffffff;
+ m_dvdnth = 0x7fffffff;
+ sh2_recalc_irq();
+ }
+ else
+ {
+ m_dvdntl = q;
+ m_dvdnth = a % b;
+ }
+ }
+ else
+ {
+ m_divu_ovf = true;
+ m_dvdntl = 0x7fffffff;
+ m_dvdnth = 0x7fffffff;
+ sh2_recalc_irq();
+ }
+}
+
+/*
+ * WTC
+ */
+
+READ16_MEMBER( sh2_device::wtcnt_r )
+{
+ return ((m_wtcsr | 0x18) << 8) | (m_wtcnt & 0xff);
+}
+
+READ16_MEMBER( sh2_device::rstcsr_r )
+{
+ return (m_rstcsr & 0xe0) | 0x1f;
+}
+
+WRITE16_MEMBER( sh2_device::wtcnt_w )
+{
+ COMBINE_DATA(&m_wtcw[0]);
+ switch (m_wtcw[0] & 0xff00)
+ {
+ case 0x5a00:
+ m_wtcnt = m_wtcw[0] & 0xff;
+ break;
+ case 0xa500:
/*
WTCSR
x--- ---- Overflow in IT mode
@@ -522,204 +866,127 @@ WRITE32_MEMBER( sh2_device::sh7604_w )
---1 1---
---- -xxx Clock select
*/
+ m_wtcsr = m_wtcw[0] & 0xff;
+ break;
+ }
+}
- m_wtcsr = (m_m[0x20] >> 16) & 0xff;
- }
+WRITE16_MEMBER( sh2_device::rstcsr_w )
+{
+ COMBINE_DATA(&m_wtcw[1]);
+ switch (m_wtcw[1] & 0xff00)
+ {
+ case 0xa500:
+ // clear WOVF flag
+ if ((m_wtcw[1] & 0x80) == 0)
+ m_rstcsr &= 0x7f;
+ break;
+ case 0x5a00:
+ m_rstcsr = (m_rstcsr & 0x80) | (m_wtcw[1] & 0x60);
+ break;
+ }
+}
- if((m_m[0x20] & 0x0000ff00) == 0x00005a00)
- {
- // -x-- ---- RSTE (1: resets wtcnt when overflows 0: no reset)
- // --x- ---- RSTS (0: power-on reset 1: Manual reset)
- // ...
- }
+READ8_MEMBER( sh2_device::sbycr_r )
+{
+ return m_sbycr;
+}
- if((m_m[0x20] & 0x0000ff00) == 0x0000a500)
- {
- // clear WOVF
- // ...
- }
+WRITE8_MEMBER( sh2_device::sbycr_w )
+{
+ m_sbycr = data;
+ if (data & 0x1f)
+ logerror("SH2 module stop selected %02x\n",data);
+}
+READ8_MEMBER( sh2_device::ccr_r )
+{
+ return m_ccr & ~0x30;
+}
+WRITE8_MEMBER( sh2_device::ccr_w )
+{
+ /*
+ xx-- ---- Way 0/1
+ ---x ---- Cache Purge (CP), write only
+ ---- x--- Two-Way Mode (TW)
+ ---- -x-- Data Replacement Disable (OD)
+ ---- --x- Instruction Replacement Disable (ID)
+ ---- ---x Cache Enable (CE)
+ */
+ m_ccr = data;
+}
- break;
-
- // Standby and cache
- case 0x24: // SBYCR, CCR
- /*
- CCR
- xx-- ---- ---- ---- Way 0/1
- ---x ---- ---- ---- Cache Purge (CP)
- ---- x--- ---- ---- Two-Way Mode (TW)
- ---- -x-- ---- ---- Data Replacement Disable (OD)
- ---- --x- ---- ---- Instruction Replacement Disable (ID)
- ---- ---x ---- ---- Cache Enable (CE)
- */
- break;
-
- // Interrupt vectors cont.
- case 0x38: // ICR, IRPA
- break;
- case 0x39: // VCRWDT
- break;
-
- // Division box
- case 0x40: // DVSR
- break;
- case 0x41: // DVDNT
- {
- int32_t a = m_m[0x41];
- int32_t b = m_m[0x40];
- LOG("SH2 div+mod %d/%d\n", a, b);
- if (b)
- {
- m_m[0x45] = a / b;
- m_m[0x44] = a % b;
- }
- else
- {
- m_m[0x42] |= 0x00010000;
- m_m[0x45] = 0x7fffffff;
- m_m[0x44] = 0x7fffffff;
- sh2_recalc_irq();
- }
- break;
- }
- case 0x42: // DVCR
- m_m[0x42] = (m_m[0x42] & ~0x00001000) | (old & m_m[0x42] & 0x00010000);
- sh2_recalc_irq();
- break;
- case 0x43: // VCRDIV
- sh2_recalc_irq();
- break;
- case 0x44: // DVDNTH
- break;
- case 0x45: // DVDNTL
- {
- int64_t a = m_m[0x45] | ((uint64_t)(m_m[0x44]) << 32);
- int64_t b = (int32_t)m_m[0x40];
- LOG("SH2 div+mod %d/%d\n", a, b);
- if (b)
- {
- int64_t q = a / b;
- if (q != (int32_t)q)
- {
- m_m[0x42] |= 0x00010000;
- m_m[0x45] = 0x7fffffff;
- m_m[0x44] = 0x7fffffff;
- sh2_recalc_irq();
- }
- else
- {
- m_m[0x45] = q;
- m_m[0x44] = a % b;
- }
- }
- else
- {
- m_m[0x42] |= 0x00010000;
- m_m[0x45] = 0x7fffffff;
- m_m[0x44] = 0x7fffffff;
- sh2_recalc_irq();
- }
- break;
- }
+READ32_MEMBER( sh2_device::bcr1_r )
+{
+ return (m_bcr1 & ~0xe008) | (m_is_slave ? 0x8000 : 0);
+}
- // DMA controller
- case 0x60: // SAR0
- case 0x61: // DAR0
- break;
- case 0x62: // DTCR0
- m_m[0x62] &= 0xffffff;
- break;
- case 0x63: // CHCR0
- m_m[0x63] = (m_m[0x63] & ~2) | (old & m_m[0x63] & 2);
- sh2_dmac_check(0);
- break;
- case 0x64: // SAR1
- case 0x65: // DAR1
- break;
- case 0x66: // DTCR1
- m_m[0x66] &= 0xffffff;
- break;
- case 0x67: // CHCR1
- m_m[0x67] = (m_m[0x67] & ~2) | (old & m_m[0x67] & 2);
- sh2_dmac_check(1);
- break;
- case 0x68: // VCRDMA0
- case 0x6a: // VCRDMA1
- sh2_recalc_irq();
- break;
- case 0x6c: // DMAOR
- m_m[0x6c] = (m_m[0x6c] & ~6) | (old & m_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;
- }
+WRITE32_MEMBER( sh2_device::bcr1_w )
+{
+ COMBINE_DATA(&m_bcr1);
}
-READ32_MEMBER( sh2_device::sh7604_r )
+READ32_MEMBER( sh2_device::bcr2_r )
{
-// logerror("sh2_internal_r: Read %08x (%x) @ %08x\n", 0xfffffe00+offset*4, offset, mem_mask);
- switch( offset )
- {
- case 0x00:
- break;
- case 0x01:
-// return m_m[1] | 0; // bit31 is TDRE: Trasmit Data Register Empty. Forcing it to be '1' breaks Saturn ...
- return m_m[1] | (0x84 << 24); // ... but this is actually needed to make EGWord on SS to boot?
-
- case 0x04: // TIER, FTCSR, FRC
- if ( mem_mask == 0x00ff0000 )
- {
- if (!m_ftcsr_read_cb.isnull())
- {
- m_ftcsr_read_cb((m_m[4] & 0xffff0000) | m_frc);
- }
- }
- sh2_timer_resync();
- return (m_m[4] & 0xffff0000) | m_frc;
- case 0x05: // OCRx, TCR, TOCR
- if(m_m[5] & 0x10)
- return (m_ocrb << 16) | (m_m[5] & 0xffff);
- else
- return (m_ocra << 16) | (m_m[5] & 0xffff);
- case 0x06: // ICR
- return m_icr << 16;
+ return m_bcr2;
+}
+
+WRITE32_MEMBER( sh2_device::bcr2_w )
+{
+ COMBINE_DATA(&m_bcr2);
+}
+
+READ32_MEMBER( sh2_device::wcr_r )
+{
+ return m_wcr;
+}
+
+WRITE32_MEMBER( sh2_device::wcr_w )
+{
+ COMBINE_DATA(&m_wcr);
+}
- case 0x20:
- return (((m_wtcsr | 0x18) & 0xff) << 24) | ((m_wtcnt & 0xff) << 16);
+READ32_MEMBER( sh2_device::mcr_r )
+{
+ return m_mcr & ~0x103;
+}
+
+WRITE32_MEMBER( sh2_device::mcr_w )
+{
+ COMBINE_DATA(&m_mcr);
+}
- case 0x24: // SBYCR, CCR
- return m_m[0x24] & ~0x3000; /* bit 4-5 of CCR are always zero */
+READ32_MEMBER( sh2_device::rtcsr_r )
+{
+ return m_rtcsr & 0xf8;
+}
+
+WRITE32_MEMBER( sh2_device::rtcsr_w )
+{
+ COMBINE_DATA(&m_rtcsr);
+}
- case 0x38: // ICR, IPRA
- return (m_m[0x38] & 0x7fffffff) | (m_nmi_line_state == ASSERT_LINE ? 0 : 0x80000000);
+READ32_MEMBER( sh2_device::rtcnt_r )
+{
+ return m_rtcnt & 0xff;
+}
- case 0x78: // BCR1
- return (m_is_slave ? 0x00008000 : 0) | (m_m[0x78] & 0x7fff);
+WRITE32_MEMBER( sh2_device::rtcnt_w )
+{
+ COMBINE_DATA(&m_rtcnt);
+ m_rtcnt &= 0xff;
+}
- case 0x41: // dvdntl mirrors
- case 0x47:
- return m_m[0x45];
+READ32_MEMBER( sh2_device::rtcor_r )
+{
+ return m_rtcor & 0xff;
+}
- case 0x46: // dvdnth mirror
- return m_m[0x44];
- }
- return m_m[offset];
+WRITE32_MEMBER( sh2_device::rtcor_w )
+{
+ COMBINE_DATA(&m_rtcor);
+ m_rtcor &= 0xff;
}
void sh2_device::set_frt_input(int state)
@@ -730,7 +997,7 @@ void sh2_device::set_frt_input(int state)
m_frt_input = state;
- if(m_m[5] & 0x8000) {
+ if(m_frc_tcr & 0x80) {
if(state == CLEAR_LINE) {
return;
}
@@ -741,8 +1008,8 @@ void sh2_device::set_frt_input(int state)
}
sh2_timer_resync();
- m_icr = m_frc;
- m_m[4] |= ICF;
+ m_frc_icr = m_frc;
+ m_ftcsr |= ICF;
//logerror("SH2.%s: ICF activated (%x)\n", tag(), m_sh2_state->pc & AM);
sh2_recalc_irq();
}
@@ -753,37 +1020,37 @@ void sh2_device::sh2_recalc_irq()
int level;
// Timer irqs
- if((m_m[4]>>8) & m_m[4] & (ICF|OCFA|OCFB|OVF))
+ if (m_tier & m_ftcsr & (ICF|OCFA|OCFB|OVF))
{
- level = (m_m[0x18] >> 24) & 15;
- if(level > irq)
+ level = (m_irq_level.frc & 15);
+ if (level > irq)
{
- int mask = (m_m[4]>>8) & m_m[4];
+ int mask = m_tier & m_ftcsr;
irq = level;
if(mask & ICF)
- vector = (m_m[0x19] >> 8) & 0x7f;
+ vector = m_irq_vector.fic & 0x7f;
else if(mask & (OCFA|OCFB))
- vector = m_m[0x19] & 0x7f;
+ vector = m_irq_vector.foc & 0x7f;
else
- vector = (m_m[0x1a] >> 24) & 0x7f;
+ vector = m_irq_vector.fov & 0x7f;
}
}
// DMA irqs
- if((m_m[0x63] & 6) == 6 && m_dma_irq[0]) {
- level = (m_m[0x38] >> 8) & 15;
+ if((m_dmac[0].chcr & 6) == 6 && m_dma_irq[0]) {
+ level = m_irq_level.dmac & 15;
if(level > irq) {
irq = level;
m_dma_irq[0] &= ~1;
- vector = (m_m[0x68]) & 0x7f;
+ vector = m_irq_vector.dmac[0] & 0x7f;
}
}
- else if((m_m[0x67] & 6) == 6 && m_dma_irq[1]) {
- level = (m_m[0x38] >> 8) & 15;
+ else if((m_dmac[1].chcr & 6) == 6 && m_dma_irq[1]) {
+ level = m_irq_level.dmac & 15;
if(level > irq) {
irq = level;
m_dma_irq[1] &= ~1;
- vector = (m_m[0x6a]) & 0x7f;
+ vector = m_irq_vector.dmac[1] & 0x7f;
}
}