From d6b22fa2c0a78087794bf1df2bea62a7e34ca3cb Mon Sep 17 00:00:00 2001 From: Angelo Salese Date: Fri, 21 Jun 2019 20:54:43 +0200 Subject: [PATCH] sh2.cpp: first pass over SH7604 SoC refactoring [Angelo Salese] * Fixed division unit overflow flag clearance; --- src/devices/cpu/sh/sh2.cpp | 207 ++++++- src/devices/cpu/sh/sh2.h | 192 +++++- src/devices/cpu/sh/sh2comn.cpp | 1041 ++++++++++++++++++++------------ src/devices/cpu/sh/sh2comn.h | 9 +- 4 files changed, 1021 insertions(+), 428 deletions(-) diff --git a/src/devices/cpu/sh/sh2.cpp b/src/devices/cpu/sh/sh2.cpp index d3660a52209..d38d8dcc6a8 100644 --- a/src/devices/cpu/sh/sh2.cpp +++ b/src/devices/cpu/sh/sh2.cpp @@ -123,15 +123,94 @@ READ32_MEMBER(sh2_device::sh2_internal_a5) sh2_internal_map - maps SH2 built-ins -------------------------------------------------*/ + void sh2_device::sh7604_map(address_map &map) { map(0x40000000, 0xbfffffff).r(FUNC(sh2_device::sh2_internal_a5)); -/*! - @todo: cps3boot breaks with this enabled. Needs customization ... - */ + +// TODO: cps3boot breaks with this enabled. Needs callback // AM_RANGE(0xc0000000, 0xc0000fff) AM_RAM // cache data array -// AM_RANGE(0xffffff88, 0xffffff8b) AM_READWRITE(dma_dtcr0_r,dma_dtcr0_w) - map(0xe0000000, 0xe00001ff).mirror(0x1ffffe00).rw(FUNC(sh2_device::sh7604_r), FUNC(sh2_device::sh7604_w)); + +// map(0xe0000000, 0xe00001ff).mirror(0x1ffffe00).rw(FUNC(sh2_device::sh7604_r), FUNC(sh2_device::sh7604_w)); + // TODO: internal map takes way too much resources if mirrored with 0x1ffffe00 + // we eventually internalize again via trampoline & sh7604_device + // additionally SH7604 doc mentions that there's a DRAM located at 0xffff8000, + // so this is not a full mirror? (needs confirmation) + // SCI + map(0xfffffe00, 0xfffffe00).rw(FUNC(sh2_device::smr_r), FUNC(sh2_device::smr_w)); + map(0xfffffe01, 0xfffffe01).rw(FUNC(sh2_device::brr_r), FUNC(sh2_device::brr_w)); + map(0xfffffe02, 0xfffffe02).rw(FUNC(sh2_device::scr_r), FUNC(sh2_device::scr_w)); + map(0xfffffe03, 0xfffffe03).rw(FUNC(sh2_device::tdr_r), FUNC(sh2_device::tdr_w)); + map(0xfffffe04, 0xfffffe04).rw(FUNC(sh2_device::ssr_r), FUNC(sh2_device::ssr_w)); + map(0xfffffe05, 0xfffffe05).r(FUNC(sh2_device::rdr_r)); + + // FRC + map(0xfffffe10, 0xfffffe10).rw(FUNC(sh2_device::tier_r), FUNC(sh2_device::tier_w)); + map(0xfffffe11, 0xfffffe11).rw(FUNC(sh2_device::ftcsr_r), FUNC(sh2_device::ftcsr_w)); + map(0xfffffe12, 0xfffffe13).rw(FUNC(sh2_device::frc_r), FUNC(sh2_device::frc_w)); + map(0xfffffe14, 0xfffffe15).rw(FUNC(sh2_device::ocra_b_r), FUNC(sh2_device::ocra_b_w)); + map(0xfffffe16, 0xfffffe16).rw(FUNC(sh2_device::frc_tcr_r), FUNC(sh2_device::frc_tcr_w)); + map(0xfffffe17, 0xfffffe17).rw(FUNC(sh2_device::tocr_r), FUNC(sh2_device::tocr_w)); + map(0xfffffe18, 0xfffffe19).r(FUNC(sh2_device::frc_icr_r)); + + // INTC + map(0xfffffe60, 0xfffffe61).rw(FUNC(sh2_device::iprb_r), FUNC(sh2_device::iprb_w)); + map(0xfffffe62, 0xfffffe63).rw(FUNC(sh2_device::vcra_r), FUNC(sh2_device::vcra_w)); + map(0xfffffe64, 0xfffffe65).rw(FUNC(sh2_device::vcrb_r), FUNC(sh2_device::vcrb_w)); + map(0xfffffe66, 0xfffffe67).rw(FUNC(sh2_device::vcrc_r), FUNC(sh2_device::vcrc_w)); + map(0xfffffe68, 0xfffffe69).rw(FUNC(sh2_device::vcrd_r), FUNC(sh2_device::vcrd_w)); + + map(0xfffffe71, 0xfffffe71).rw(FUNC(sh2_device::drcr_r<0>), FUNC(sh2_device::drcr_w<0>)); + map(0xfffffe72, 0xfffffe72).rw(FUNC(sh2_device::drcr_r<1>), FUNC(sh2_device::drcr_w<1>)); + + // WTC + map(0xfffffe80, 0xfffffe81).rw(FUNC(sh2_device::wtcnt_r), FUNC(sh2_device::wtcnt_w)); + map(0xfffffe82, 0xfffffe83).rw(FUNC(sh2_device::rstcsr_r), FUNC(sh2_device::rstcsr_w)); + + // standby and cache control + map(0xfffffe91, 0xfffffe91).rw(FUNC(sh2_device::sbycr_r), FUNC(sh2_device::sbycr_w)); + map(0xfffffe92, 0xfffffe92).rw(FUNC(sh2_device::ccr_r), FUNC(sh2_device::ccr_w)); + + // INTC second section + map(0xfffffee0, 0xfffffee1).rw(FUNC(sh2_device::intc_icr_r), FUNC(sh2_device::intc_icr_w)); + map(0xfffffee2, 0xfffffee3).rw(FUNC(sh2_device::ipra_r), FUNC(sh2_device::ipra_w)); + map(0xfffffee4, 0xfffffee5).rw(FUNC(sh2_device::vcrwdt_r), FUNC(sh2_device::vcrwdt_w)); + + // DIVU + map(0xffffff00, 0xffffff03).rw(FUNC(sh2_device::dvsr_r), FUNC(sh2_device::dvsr_w)); + map(0xffffff04, 0xffffff07).rw(FUNC(sh2_device::dvdnt_r), FUNC(sh2_device::dvdnt_w)); + map(0xffffff08, 0xffffff0b).rw(FUNC(sh2_device::dvcr_r), FUNC(sh2_device::dvcr_w)); + // INTC third section + map(0xffffff0c, 0xffffff0f).rw(FUNC(sh2_device::vcrdiv_r), FUNC(sh2_device::vcrdiv_w)); + // DIVU continued (64-bit plus mirrors) + map(0xffffff10, 0xffffff13).rw(FUNC(sh2_device::dvdnth_r), FUNC(sh2_device::dvdnth_w)); + map(0xffffff14, 0xffffff17).rw(FUNC(sh2_device::dvdntl_r), FUNC(sh2_device::dvdntl_w)); + map(0xffffff18, 0xffffff1b).r(FUNC(sh2_device::dvdnth_r)); + map(0xffffff1c, 0xffffff1f).r(FUNC(sh2_device::dvdntl_r)); + + // DMAC + map(0xffffff80, 0xffffff83).rw(FUNC(sh2_device::sar_r<0>), FUNC(sh2_device::sar_w<0>)); + map(0xffffff84, 0xffffff87).rw(FUNC(sh2_device::dar_r<0>), FUNC(sh2_device::dar_w<0>)); + map(0xffffff88, 0xffffff8b).rw(FUNC(sh2_device::dmac_tcr_r<0>), FUNC(sh2_device::dmac_tcr_w<0>)); + map(0xffffff8c, 0xffffff8f).rw(FUNC(sh2_device::chcr_r<0>), FUNC(sh2_device::chcr_w<0>)); + + map(0xffffff90, 0xffffff93).rw(FUNC(sh2_device::sar_r<1>), FUNC(sh2_device::sar_w<1>)); + map(0xffffff94, 0xffffff97).rw(FUNC(sh2_device::dar_r<1>), FUNC(sh2_device::dar_w<1>)); + map(0xffffff98, 0xffffff9b).rw(FUNC(sh2_device::dmac_tcr_r<1>), FUNC(sh2_device::dmac_tcr_w<1>)); + map(0xffffff9c, 0xffffff9f).rw(FUNC(sh2_device::chcr_r<1>), FUNC(sh2_device::chcr_w<1>)); + + map(0xffffffa0, 0xffffffa3).rw(FUNC(sh2_device::vcrdma_r<0>), FUNC(sh2_device::vcrdma_w<0>)); + map(0xffffffa8, 0xffffffab).rw(FUNC(sh2_device::vcrdma_r<1>), FUNC(sh2_device::vcrdma_w<1>)); + map(0xffffffb0, 0xffffffb3).rw(FUNC(sh2_device::dmaor_r), FUNC(sh2_device::dmaor_w)); + + // BSC + map(0xffffffe0, 0xffffffe3).rw(FUNC(sh2_device::bcr1_r), FUNC(sh2_device::bcr1_w)); + map(0xffffffe4, 0xffffffe7).rw(FUNC(sh2_device::bcr2_r), FUNC(sh2_device::bcr2_w)); + map(0xffffffe8, 0xffffffeb).rw(FUNC(sh2_device::wcr_r), FUNC(sh2_device::wcr_w)); + map(0xffffffec, 0xffffffef).rw(FUNC(sh2_device::mcr_r), FUNC(sh2_device::mcr_w)); + map(0xfffffff0, 0xfffffff3).rw(FUNC(sh2_device::rtcsr_r), FUNC(sh2_device::rtcsr_w)); + map(0xfffffff4, 0xfffffff7).rw(FUNC(sh2_device::rtcnt_r), FUNC(sh2_device::rtcnt_w)); + map(0xfffffff8, 0xfffffffb).rw(FUNC(sh2_device::rtcor_r), FUNC(sh2_device::rtcor_w)); } void sh2a_device::sh7021_map(address_map &map) @@ -364,14 +443,12 @@ void sh2_device::device_reset() m_sh2_state->pending_irq = m_test_irq = 0; //memset(&m_irq_queue[0], 0, sizeof(m_irq_queue[0])*16); memset(&m_irq_line_state[0], 0, sizeof(m_irq_line_state[0])*17); - m_frc = m_ocra = m_ocrb = m_icr = 0; + m_frc = m_ocra = m_ocrb = m_frc_icr = 0; m_frc_base = 0; m_frt_input = m_sh2_state->internal_irq_level = m_internal_irq_vector = 0; m_dma_timer_active[0] = m_dma_timer_active[1] = 0; m_dma_irq[0] = m_dma_irq[1] = 0; - memset(m_m, 0, 0x200); - m_sh2_state->pc = RL(0); m_sh2_state->r[15] = RL(4); m_sh2_state->sr = SH_I; @@ -467,13 +544,93 @@ void sh2_device::device_start() m_internal = &space(AS_PROGRAM); - save_item(NAME(m_cpu_off)); - //save_item(NAME(m_dvsr)); - //save_item(NAME(m_dvdnth)); - //save_item(NAME(m_dvdntl)); - //save_item(NAME(m_dvcr)); - save_item(NAME(m_test_irq)); + // SCI + save_item(NAME(m_smr)); + save_item(NAME(m_brr)); + save_item(NAME(m_scr)); + save_item(NAME(m_tdr)); + save_item(NAME(m_ssr)); + // FRT / FRC + save_item(NAME(m_tier)); + save_item(NAME(m_ftcsr)); + save_item(NAME(m_frc_tcr)); + save_item(NAME(m_tocr)); + save_item(NAME(m_frc)); + save_item(NAME(m_ocra)); + save_item(NAME(m_ocrb)); + save_item(NAME(m_frc_icr)); + save_item(NAME(m_frc_base)); + save_item(NAME(m_frt_input)); + + // INTC + save_item(NAME(m_irq_level.frc)); + save_item(NAME(m_irq_level.sci)); + save_item(NAME(m_irq_level.divu)); + save_item(NAME(m_irq_level.dmac)); + save_item(NAME(m_irq_level.wdt)); + save_item(NAME(m_irq_vector.fic)); + save_item(NAME(m_irq_vector.foc)); + save_item(NAME(m_irq_vector.fov)); + save_item(NAME(m_irq_vector.divu)); + save_item(NAME(m_irq_vector.dmac[0])); + save_item(NAME(m_irq_vector.dmac[1])); + + save_item(NAME(m_ipra)); + save_item(NAME(m_iprb)); + save_item(NAME(m_vcra)); + save_item(NAME(m_vcrb)); + save_item(NAME(m_vcrc)); + save_item(NAME(m_vcrd)); + save_item(NAME(m_vcrwdt)); + save_item(NAME(m_vcrdiv)); + save_item(NAME(m_intc_icr)); + save_item(NAME(m_vcrdma[0])); + save_item(NAME(m_vcrdma[1])); + + save_item(NAME(m_vecmd)); + save_item(NAME(m_nmie)); + + // DIVU + save_item(NAME(m_divu_ovf)); + save_item(NAME(m_divu_ovfie)); + save_item(NAME(m_dvsr)); + save_item(NAME(m_dvdntl)); + save_item(NAME(m_dvdnth)); + + // WTC + save_item(NAME(m_wtcnt)); + save_item(NAME(m_wtcsr)); + save_item(NAME(m_rstcsr)); + save_item(NAME(m_wtcw[0])); + save_item(NAME(m_wtcw[1])); + + // DMAC + save_item(NAME(m_dmaor)); + save_item(NAME(m_dmac[0].drcr)); + save_item(NAME(m_dmac[1].drcr)); + save_item(NAME(m_dmac[0].sar)); + save_item(NAME(m_dmac[1].sar)); + save_item(NAME(m_dmac[0].dar)); + save_item(NAME(m_dmac[1].dar)); + save_item(NAME(m_dmac[0].tcr)); + save_item(NAME(m_dmac[1].tcr)); + save_item(NAME(m_dmac[0].chcr)); + save_item(NAME(m_dmac[1].chcr)); + + // misc + save_item(NAME(m_sbycr)); + save_item(NAME(m_ccr)); + + // BSC + save_item(NAME(m_bcr1)); + save_item(NAME(m_bcr2)); + save_item(NAME(m_wcr)); + save_item(NAME(m_mcr)); + save_item(NAME(m_rtcsr)); + save_item(NAME(m_rtcor)); + save_item(NAME(m_rtcnt)); + /* for (int i = 0; i < 16; ++i) { @@ -482,22 +639,15 @@ void sh2_device::device_start() } */ - + // internals + save_item(NAME(m_cpu_off)); + save_item(NAME(m_test_irq)); save_item(NAME(m_irq_line_state)); - save_item(NAME(m_m)); save_item(NAME(m_nmi_line_state)); - save_item(NAME(m_frc)); - save_item(NAME(m_ocra)); - save_item(NAME(m_ocrb)); - save_item(NAME(m_icr)); - save_item(NAME(m_frc_base)); - save_item(NAME(m_frt_input)); save_item(NAME(m_internal_irq_vector)); save_item(NAME(m_dma_timer_active)); save_item(NAME(m_dma_irq)); - save_item(NAME(m_wtcnt)); - save_item(NAME(m_wtcsr)); - + state_add( STATE_GENPC, "PC", m_sh2_state->pc).mask(SH12_AM).callimport(); state_add( STATE_GENPCBASE, "CURPC", m_sh2_state->pc ).callimport().noshow(); @@ -509,14 +659,13 @@ void sh2_device::device_start() //m_dvcr = 0; m_test_irq = 0; - memset(m_irq_line_state, 0, sizeof(m_irq_line_state)); - memset(m_m, 0, sizeof(m_m)); + m_nmi_line_state = 0; m_frc = 0; m_ocra = 0; m_ocrb = 0; - m_icr = 0; + m_frc_icr = 0; m_frc_base = 0; m_frt_input = 0; m_internal_irq_vector = 0; @@ -641,7 +790,7 @@ void sh2_device::sh2_exception(const char *message, int irqline) } else { - if(m_m[0x38] & 0x00010000) + if(m_vecmd == true) { vector = standard_irq_callback(irqline); LOG("SH-2 exception #%d (external vector: $%x) after [%s]\n", irqline, vector, message); diff --git a/src/devices/cpu/sh/sh2.h b/src/devices/cpu/sh/sh2.h index 206cecbab6d..e119d6bc098 100644 --- a/src/devices/cpu/sh/sh2.h +++ b/src/devices/cpu/sh/sh2.h @@ -81,10 +81,141 @@ public: } - DECLARE_WRITE32_MEMBER( sh7604_w ); - DECLARE_READ32_MEMBER( sh7604_r ); DECLARE_READ32_MEMBER(sh2_internal_a5); + // SCI + DECLARE_READ8_MEMBER( smr_r ); + DECLARE_WRITE8_MEMBER( smr_w ); + DECLARE_READ8_MEMBER( brr_r ); + DECLARE_WRITE8_MEMBER( brr_w ); + DECLARE_READ8_MEMBER( scr_r ); + DECLARE_WRITE8_MEMBER( scr_w ); + DECLARE_READ8_MEMBER( tdr_r ); + DECLARE_WRITE8_MEMBER( tdr_w ); + DECLARE_READ8_MEMBER( ssr_r ); + DECLARE_WRITE8_MEMBER( ssr_w ); + DECLARE_READ8_MEMBER( rdr_r ); + + // FRT / FRC + DECLARE_READ8_MEMBER( tier_r ); + DECLARE_WRITE8_MEMBER( tier_w ); + DECLARE_READ16_MEMBER( frc_r ); + DECLARE_WRITE16_MEMBER( frc_w ); + DECLARE_READ8_MEMBER( ftcsr_r ); + DECLARE_WRITE8_MEMBER( ftcsr_w ); + DECLARE_READ16_MEMBER( ocra_b_r ); + DECLARE_WRITE16_MEMBER( ocra_b_w ); + DECLARE_READ8_MEMBER( frc_tcr_r ); + DECLARE_WRITE8_MEMBER( frc_tcr_w ); + DECLARE_READ8_MEMBER( tocr_r ); + DECLARE_WRITE8_MEMBER( tocr_w ); + DECLARE_READ16_MEMBER( frc_icr_r ); + + // INTC + DECLARE_READ16_MEMBER( ipra_r ); + DECLARE_WRITE16_MEMBER( ipra_w ); + DECLARE_READ16_MEMBER( iprb_r ); + DECLARE_WRITE16_MEMBER( iprb_w ); + DECLARE_READ16_MEMBER( vcra_r ); + DECLARE_WRITE16_MEMBER( vcra_w ); + DECLARE_READ16_MEMBER( vcrb_r ); + DECLARE_WRITE16_MEMBER( vcrb_w ); + DECLARE_READ16_MEMBER( vcrc_r ); + DECLARE_WRITE16_MEMBER( vcrc_w ); + DECLARE_READ16_MEMBER( vcrd_r ); + DECLARE_WRITE16_MEMBER( vcrd_w ); + DECLARE_READ16_MEMBER( vcrwdt_r ); + DECLARE_WRITE16_MEMBER( vcrwdt_w ); + DECLARE_READ32_MEMBER( vcrdiv_r ); + DECLARE_WRITE32_MEMBER( vcrdiv_w ); + DECLARE_READ16_MEMBER( intc_icr_r ); + DECLARE_WRITE16_MEMBER( intc_icr_w ); + + // DIVU + DECLARE_READ32_MEMBER( dvsr_r ); + DECLARE_WRITE32_MEMBER( dvsr_w ); + DECLARE_READ32_MEMBER( dvdnt_r ); + DECLARE_WRITE32_MEMBER( dvdnt_w ); + DECLARE_READ32_MEMBER( dvdnth_r ); + DECLARE_WRITE32_MEMBER( dvdnth_w ); + DECLARE_READ32_MEMBER( dvdntl_r ); + DECLARE_WRITE32_MEMBER( dvdntl_w ); + + DECLARE_READ32_MEMBER( dvcr_r ); + DECLARE_WRITE32_MEMBER( dvcr_w ); + + // DMAC + template READ32_MEMBER(vcrdma_r) + { + return m_vcrdma[Channel] & 0x7f; + } + + template WRITE32_MEMBER(vcrdma_w) + { + COMBINE_DATA(&m_vcrdma[Channel]); + m_irq_vector.dmac[Channel] = m_vcrdma[Channel] & 0x7f; + sh2_recalc_irq(); + } + + template READ8_MEMBER(drcr_r) { return m_dmac[Channel].drcr & 3; } + template WRITE8_MEMBER(drcr_w) { m_dmac[Channel].drcr = data & 3; sh2_recalc_irq(); } + template READ32_MEMBER(sar_r) { return m_dmac[Channel].sar; } + template WRITE32_MEMBER(sar_w) { COMBINE_DATA(&m_dmac[Channel].sar); } + template READ32_MEMBER(dar_r) { return m_dmac[Channel].dar; } + template WRITE32_MEMBER(dar_w) { COMBINE_DATA(&m_dmac[Channel].dar); } + template READ32_MEMBER(dmac_tcr_r) { return m_dmac[Channel].tcr; } + template WRITE32_MEMBER(dmac_tcr_w) { COMBINE_DATA(&m_dmac[Channel].tcr); m_dmac[Channel].tcr &= 0xffffff; } + template READ32_MEMBER(chcr_r) { return m_dmac[Channel].chcr; } + template WRITE32_MEMBER(chcr_w) + { + uint32_t old; + old = m_dmac[Channel].chcr; + COMBINE_DATA(&m_dmac[Channel].chcr); + m_dmac[Channel].chcr = (data & ~2) | (old & m_dmac[Channel].chcr & 2); + sh2_dmac_check(Channel); + } + READ32_MEMBER( dmaor_r ) { return m_dmaor & 0xf; } + WRITE32_MEMBER( dmaor_w ) + { + if(ACCESSING_BITS_0_7) + { + uint8_t old; + old = m_dmaor & 0xf; + m_dmaor = (data & ~6) | (old & m_dmaor & 6); + sh2_dmac_check(0); + sh2_dmac_check(1); + } + } + + // WTC + DECLARE_READ16_MEMBER( wtcnt_r ); + DECLARE_WRITE16_MEMBER( wtcnt_w ); + DECLARE_READ16_MEMBER( rstcsr_r ); + DECLARE_WRITE16_MEMBER( rstcsr_w ); + + // misc + DECLARE_READ8_MEMBER( sbycr_r ); + DECLARE_WRITE8_MEMBER( sbycr_w ); + DECLARE_READ8_MEMBER( ccr_r ); + DECLARE_WRITE8_MEMBER( ccr_w ); + + // BSC + DECLARE_READ32_MEMBER( bcr1_r ); + DECLARE_WRITE32_MEMBER( bcr1_w ); + DECLARE_READ32_MEMBER( bcr2_r ); + DECLARE_WRITE32_MEMBER( bcr2_w ); + DECLARE_READ32_MEMBER( wcr_r ); + DECLARE_WRITE32_MEMBER( wcr_w ); + DECLARE_READ32_MEMBER( mcr_r ); + DECLARE_WRITE32_MEMBER( mcr_w ); + DECLARE_READ32_MEMBER( rtcsr_r ); + DECLARE_WRITE32_MEMBER( rtcsr_w ); + DECLARE_READ32_MEMBER( rtcor_r ); + DECLARE_WRITE32_MEMBER( rtcor_w ); + DECLARE_READ32_MEMBER( rtcnt_r ); + DECLARE_WRITE32_MEMBER( rtcnt_w ); + + virtual void set_frt_input(int state) override; void sh2_notify_dma_data_available(); void func_fastirq(); @@ -128,11 +259,58 @@ private: int8_t m_irq_line_state[17]; address_space *m_internal; - uint32_t m_m[0x200/4]; + // SCI + uint8_t m_smr, m_brr, m_scr, m_tdr, m_ssr; + // FRT / FRC + uint8_t m_tier, m_ftcsr, m_frc_tcr, m_tocr; + uint16_t m_frc; + uint16_t m_ocra, m_ocrb, m_frc_icr; + // INTC + struct { + uint8_t frc; + uint8_t sci; + uint8_t divu; + uint8_t dmac; + uint8_t wdt; + } m_irq_level; + struct { + uint8_t fic; + uint8_t foc; + uint8_t fov; + uint8_t divu; + uint8_t dmac[2]; + } m_irq_vector; + uint16_t m_ipra, m_iprb; + uint16_t m_vcra, m_vcrb, m_vcrc, m_vcrd, m_vcrwdt, m_vcrdiv, m_intc_icr, m_vcrdma[2]; + bool m_vecmd, m_nmie; + + // DIVU + bool m_divu_ovf, m_divu_ovfie; + uint32_t m_dvsr, m_dvdntl, m_dvdnth; + + // WTC + uint8_t m_wtcnt, m_wtcsr; + uint8_t m_rstcsr; + uint16_t m_wtcw[2]; + + // DMAC + struct { + uint8_t drcr; + uint32_t sar; + uint32_t dar; + uint32_t tcr; + uint32_t chcr; + } m_dmac[2]; + uint8_t m_dmaor; + + // misc + uint8_t m_sbycr, m_ccr; + + // BSC + uint32_t m_bcr1, m_bcr2, m_wcr, m_mcr, m_rtcsr, m_rtcor, m_rtcnt; + int8_t m_nmi_line_state; - uint16_t m_frc; - uint16_t m_ocra, m_ocrb, m_icr; uint64_t m_frc_base; int m_frt_input; @@ -150,8 +328,6 @@ private: uint32_t m_active_dma_src[2]; uint32_t m_active_dma_dst[2]; uint32_t m_active_dma_count[2]; - uint16_t m_wtcnt; - uint8_t m_wtcsr; int m_is_slave; dma_kludge_delegate m_dma_kludge_cb; @@ -181,7 +357,7 @@ private: TIMER_CALLBACK_MEMBER( sh2_dma_current_active_callback ); void sh2_timer_resync(); void sh2_timer_activate(); - void sh2_do_dma(int dma); + void sh2_do_dma(int dmach); virtual void sh2_exception(const char *message, int irqline) override; void sh2_dmac_check(int dma); void sh2_recalc_irq(); 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 -WRITE32_MEMBER( sh2_device::sh7604_w ) +READ8_MEMBER( sh2_device::smr_r ) { - uint32_t old; + return m_smr; +} - old = m_m[offset]; - COMBINE_DATA(m_m+offset); +WRITE8_MEMBER( sh2_device::smr_w ) +{ + m_smr = data; +} - // if(offset != 0x20) - // logerror("sh2_internal_w: Write %08x (%x), %08x @ %08x\n", 0xfffffe00+offset*4, offset, data, mem_mask); +READ8_MEMBER( sh2_device::brr_r ) +{ + return m_brr; +} -// if(offset != 0x20) -// printf("sh2_internal_w: Write %08x (%x), %08x @ %08x (PC %x)\n", 0xfffffe00+offset*4, offset, data, mem_mask, pc()); +WRITE8_MEMBER( sh2_device::brr_w ) +{ + m_brr = data; +} - switch( offset ) +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; +} + +WRITE16_MEMBER( sh2_device::vcrwdt_w ) +{ + COMBINE_DATA(&m_vcrwdt); + // ... + sh2_recalc_irq(); +} + +READ32_MEMBER( sh2_device::vcrdiv_r ) +{ + return m_vcrdiv & 0x7f; +} + +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(); +} + +READ32_MEMBER( sh2_device::dvcr_r ) +{ + return (m_divu_ovfie == true ? 2 : 0) | (m_divu_ovf == true ? 1 : 0); +} + +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_m[0x20] >> 16) & 0xff; - } - - 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) - // ... - } - - if((m_m[0x20] & 0x0000ff00) == 0x0000a500) - { - // clear WOVF - // ... - } - - - - 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(); - } + m_wtcsr = m_wtcw[0] & 0xff; 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; - } - - // 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; } } -READ32_MEMBER( sh2_device::sh7604_r ) +WRITE16_MEMBER( sh2_device::rstcsr_w ) { -// logerror("sh2_internal_r: Read %08x (%x) @ %08x\n", 0xfffffe00+offset*4, offset, mem_mask); - switch( offset ) + COMBINE_DATA(&m_wtcw[1]); + switch (m_wtcw[1] & 0xff00) { - 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; - - case 0x20: - return (((m_wtcsr | 0x18) & 0xff) << 24) | ((m_wtcnt & 0xff) << 16); - - case 0x24: // SBYCR, CCR - return m_m[0x24] & ~0x3000; /* bit 4-5 of CCR are always zero */ - - case 0x38: // ICR, IPRA - return (m_m[0x38] & 0x7fffffff) | (m_nmi_line_state == ASSERT_LINE ? 0 : 0x80000000); - - case 0x78: // BCR1 - return (m_is_slave ? 0x00008000 : 0) | (m_m[0x78] & 0x7fff); - - case 0x41: // dvdntl mirrors - case 0x47: - return m_m[0x45]; - - case 0x46: // dvdnth mirror - return m_m[0x44]; + 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; } - return m_m[offset]; +} + +READ8_MEMBER( sh2_device::sbycr_r ) +{ + return m_sbycr; +} + +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; +} + +READ32_MEMBER( sh2_device::bcr1_r ) +{ + return (m_bcr1 & ~0xe008) | (m_is_slave ? 0x8000 : 0); +} + +WRITE32_MEMBER( sh2_device::bcr1_w ) +{ + COMBINE_DATA(&m_bcr1); +} + +READ32_MEMBER( sh2_device::bcr2_r ) +{ + 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); +} + +READ32_MEMBER( sh2_device::mcr_r ) +{ + return m_mcr & ~0x103; +} + +WRITE32_MEMBER( sh2_device::mcr_w ) +{ + COMBINE_DATA(&m_mcr); +} + +READ32_MEMBER( sh2_device::rtcsr_r ) +{ + return m_rtcsr & 0xf8; +} + +WRITE32_MEMBER( sh2_device::rtcsr_w ) +{ + COMBINE_DATA(&m_rtcsr); +} + +READ32_MEMBER( sh2_device::rtcnt_r ) +{ + return m_rtcnt & 0xff; +} + +WRITE32_MEMBER( sh2_device::rtcnt_w ) +{ + COMBINE_DATA(&m_rtcnt); + m_rtcnt &= 0xff; +} + +READ32_MEMBER( sh2_device::rtcor_r ) +{ + return m_rtcor & 0xff; +} + +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; } } diff --git a/src/devices/cpu/sh/sh2comn.h b/src/devices/cpu/sh/sh2comn.h index fb1e63eac19..53f5e04d2e6 100644 --- a/src/devices/cpu/sh/sh2comn.h +++ b/src/devices/cpu/sh/sh2comn.h @@ -15,10 +15,11 @@ enum { - ICF = 0x00800000, - OCFA = 0x00080000, - OCFB = 0x00040000, - OVF = 0x00020000 + ICF = 0x80, + OCFA = 0x08, + OCFB = 0x04, + OVF = 0x02, + CCLRA = 0x01 }; #define SH12_AM 0xc7ffffff