summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/sh/sh7021.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/sh/sh7021.cpp')
-rw-r--r--src/devices/cpu/sh/sh7021.cpp2243
1 files changed, 2243 insertions, 0 deletions
diff --git a/src/devices/cpu/sh/sh7021.cpp b/src/devices/cpu/sh/sh7021.cpp
new file mode 100644
index 00000000000..6b61621cb5c
--- /dev/null
+++ b/src/devices/cpu/sh/sh7021.cpp
@@ -0,0 +1,2243 @@
+// license:BSD-3-Clause
+// copyright-holders:Ryan Holtz
+/*****************************************************************************
+ *
+ * sh7021.cpp
+ * Portable Hitachi SH-1 (model SH7021) emulator
+ *
+ *****************************************************************************/
+
+#include "emu.h"
+#include "sh7021.h"
+#include "sh_dasm.h"
+
+#define LOG_INTC_RD (1u << 1)
+#define LOG_INTC_WR (1u << 2)
+#define LOG_UBC_RD (1u << 3)
+#define LOG_UBC_WR (1u << 4)
+#define LOG_BSC_RD (1u << 5)
+#define LOG_BSC_WR (1u << 6)
+#define LOG_DMA_RD (1u << 7)
+#define LOG_DMA_WR (1u << 8)
+#define LOG_ITU_RD (1u << 9)
+#define LOG_ITU_WR (1u << 10)
+#define LOG_TPC_RD (1u << 11)
+#define LOG_TPC_WR (1u << 12)
+#define LOG_WDT_RD (1u << 13)
+#define LOG_WDT_WR (1u << 14)
+#define LOG_SCI_RD (1u << 15)
+#define LOG_SCI_WR (1u << 16)
+#define LOG_PFC_RD (1u << 17)
+#define LOG_PFC_WR (1u << 18)
+#define LOG_INTC (LOG_INTC_RD | LOG_INTC_WR)
+#define LOG_UBC (LOG_UBC_RD | LOG_UBC_WR)
+#define LOG_BSC (LOG_BSC_RD | LOG_BSC_WR)
+#define LOG_DMA (LOG_DMA_RD | LOG_DMA_WR)
+#define LOG_ITU (LOG_ITU_RD | LOG_ITU_WR)
+#define LOG_TPC (LOG_TPC_RD | LOG_TPC_WR)
+#define LOG_WDT (LOG_WDT_RD | LOG_WDT_WR)
+#define LOG_SCI (LOG_SCI_RD | LOG_SCI_WR)
+#define LOG_PFC (LOG_PFC_RD | LOG_PFC_WR)
+#define LOG_ALL (LOG_INTC | LOG_UBC | LOG_BSC | LOG_DMA | LOG_ITU | LOG_TPC | LOG_WDT | LOG_SCI | LOG_PFC)
+
+#define VERBOSE (0)
+#include "logmacro.h"
+
+
+DEFINE_DEVICE_TYPE(SH7021, sh7021_device, "sh7021", "Hitachi SH7021")
+
+/*-------------------------------------------------
+ internal_map - maps SH7021 built-ins
+-------------------------------------------------*/
+
+void sh7021_device::internal_map(address_map &map)
+{
+ map(0x00000000, 0x00007fff).rom().region(DEVICE_SELF, 0).mirror(0x00ff8000); // 32KB internal ROM
+
+ map(0x05fffec0, 0x05fffec0).rw(FUNC(sh7021_device::sci_smr_r<0>), FUNC(sh7021_device::sci_smr_w<0>));
+ map(0x05fffec1, 0x05fffec1).rw(FUNC(sh7021_device::sci_brr_r<0>), FUNC(sh7021_device::sci_brr_w<0>));
+ map(0x05fffec2, 0x05fffec2).rw(FUNC(sh7021_device::sci_scr_r<0>), FUNC(sh7021_device::sci_scr_w<0>));
+ map(0x05fffec3, 0x05fffec3).rw(FUNC(sh7021_device::sci_tdr_r<0>), FUNC(sh7021_device::sci_tdr_w<0>));
+ map(0x05fffec4, 0x05fffec4).rw(FUNC(sh7021_device::sci_ssr_r<0>), FUNC(sh7021_device::sci_ssr_w<0>));
+ map(0x05fffec5, 0x05fffec5).r(FUNC(sh7021_device::sci_rdr_r<0>));
+ map(0x05fffec8, 0x05fffec8).rw(FUNC(sh7021_device::sci_smr_r<1>), FUNC(sh7021_device::sci_smr_w<1>));
+ map(0x05fffec9, 0x05fffec9).rw(FUNC(sh7021_device::sci_brr_r<1>), FUNC(sh7021_device::sci_brr_w<1>));
+ map(0x05fffeca, 0x05fffeca).rw(FUNC(sh7021_device::sci_scr_r<1>), FUNC(sh7021_device::sci_scr_w<1>));
+ map(0x05fffecb, 0x05fffecb).rw(FUNC(sh7021_device::sci_tdr_r<1>), FUNC(sh7021_device::sci_tdr_w<1>));
+ map(0x05fffecc, 0x05fffecc).rw(FUNC(sh7021_device::sci_ssr_r<1>), FUNC(sh7021_device::sci_ssr_w<1>));
+ map(0x05fffecd, 0x05fffecd).r(FUNC(sh7021_device::sci_rdr_r<1>));
+
+ map(0x05ffff00, 0x05ffff00).rw(FUNC(sh7021_device::itu_tstr_r), FUNC(sh7021_device::itu_tstr_w));
+ map(0x05ffff01, 0x05ffff01).rw(FUNC(sh7021_device::itu_tsnc_r), FUNC(sh7021_device::itu_tsnc_w));
+ map(0x05ffff02, 0x05ffff02).rw(FUNC(sh7021_device::itu_tmdr_r), FUNC(sh7021_device::itu_tmdr_w));
+ map(0x05ffff03, 0x05ffff03).rw(FUNC(sh7021_device::itu_tfcr_r), FUNC(sh7021_device::itu_tfcr_w));
+ map(0x05ffff31, 0x05ffff31).rw(FUNC(sh7021_device::itu_tocr_r), FUNC(sh7021_device::itu_tocr_w));
+
+ map(0x05ffff04, 0x05ffff04).rw(FUNC(sh7021_device::itu_tcr_r<0>), FUNC(sh7021_device::itu_tcr_w<0>));
+ map(0x05ffff05, 0x05ffff05).rw(FUNC(sh7021_device::itu_tior_r<0>), FUNC(sh7021_device::itu_tior_w<0>));
+ map(0x05ffff06, 0x05ffff06).rw(FUNC(sh7021_device::itu_tier_r<0>), FUNC(sh7021_device::itu_tier_w<0>));
+ map(0x05ffff07, 0x05ffff07).rw(FUNC(sh7021_device::itu_tsr_r<0>), FUNC(sh7021_device::itu_tsr_w<0>));
+ map(0x05ffff08, 0x05ffff09).rw(FUNC(sh7021_device::itu_tcnt_r<0>), FUNC(sh7021_device::itu_tcnt_w<0>));
+ map(0x05ffff0a, 0x05ffff0b).rw(FUNC(sh7021_device::itu_gra_r<0>), FUNC(sh7021_device::itu_gra_w<0>));
+ map(0x05ffff0c, 0x05ffff0d).rw(FUNC(sh7021_device::itu_grb_r<0>), FUNC(sh7021_device::itu_grb_w<0>));
+
+ map(0x05ffff0e, 0x05ffff0e).rw(FUNC(sh7021_device::itu_tcr_r<1>), FUNC(sh7021_device::itu_tcr_w<1>));
+ map(0x05ffff0f, 0x05ffff0f).rw(FUNC(sh7021_device::itu_tior_r<1>), FUNC(sh7021_device::itu_tior_w<1>));
+ map(0x05ffff10, 0x05ffff10).rw(FUNC(sh7021_device::itu_tier_r<1>), FUNC(sh7021_device::itu_tier_w<1>));
+ map(0x05ffff11, 0x05ffff11).rw(FUNC(sh7021_device::itu_tsr_r<1>), FUNC(sh7021_device::itu_tsr_w<1>));
+ map(0x05ffff12, 0x05ffff13).rw(FUNC(sh7021_device::itu_tcnt_r<1>), FUNC(sh7021_device::itu_tcnt_w<1>));
+ map(0x05ffff14, 0x05ffff15).rw(FUNC(sh7021_device::itu_gra_r<1>), FUNC(sh7021_device::itu_gra_w<1>));
+ map(0x05ffff16, 0x05ffff17).rw(FUNC(sh7021_device::itu_grb_r<1>), FUNC(sh7021_device::itu_grb_w<1>));
+
+ map(0x05ffff18, 0x05ffff18).rw(FUNC(sh7021_device::itu_tcr_r<2>), FUNC(sh7021_device::itu_tcr_w<2>));
+ map(0x05ffff19, 0x05ffff19).rw(FUNC(sh7021_device::itu_tior_r<2>), FUNC(sh7021_device::itu_tior_w<2>));
+ map(0x05ffff1a, 0x05ffff1a).rw(FUNC(sh7021_device::itu_tier_r<2>), FUNC(sh7021_device::itu_tier_w<2>));
+ map(0x05ffff1b, 0x05ffff1b).rw(FUNC(sh7021_device::itu_tsr_r<2>), FUNC(sh7021_device::itu_tsr_w<2>));
+ map(0x05ffff1c, 0x05ffff1d).rw(FUNC(sh7021_device::itu_tcnt_r<2>), FUNC(sh7021_device::itu_tcnt_w<2>));
+ map(0x05ffff1e, 0x05ffff1f).rw(FUNC(sh7021_device::itu_gra_r<2>), FUNC(sh7021_device::itu_gra_w<2>));
+ map(0x05ffff20, 0x05ffff21).rw(FUNC(sh7021_device::itu_grb_r<2>), FUNC(sh7021_device::itu_grb_w<2>));
+
+ map(0x05ffff22, 0x05ffff22).rw(FUNC(sh7021_device::itu_tcr_r<3>), FUNC(sh7021_device::itu_tcr_w<3>));
+ map(0x05ffff23, 0x05ffff23).rw(FUNC(sh7021_device::itu_tior_r<3>), FUNC(sh7021_device::itu_tior_w<3>));
+ map(0x05ffff24, 0x05ffff24).rw(FUNC(sh7021_device::itu_tier_r<3>), FUNC(sh7021_device::itu_tier_w<3>));
+ map(0x05ffff25, 0x05ffff25).rw(FUNC(sh7021_device::itu_tsr_r<3>), FUNC(sh7021_device::itu_tsr_w<3>));
+ map(0x05ffff26, 0x05ffff27).rw(FUNC(sh7021_device::itu_tcnt_r<3>), FUNC(sh7021_device::itu_tcnt_w<3>));
+ map(0x05ffff28, 0x05ffff29).rw(FUNC(sh7021_device::itu_gra_r<3>), FUNC(sh7021_device::itu_gra_w<3>));
+ map(0x05ffff2a, 0x05ffff2b).rw(FUNC(sh7021_device::itu_grb_r<3>), FUNC(sh7021_device::itu_grb_w<3>));
+ map(0x05ffff2c, 0x05ffff2d).rw(FUNC(sh7021_device::itu_bra_r<3>), FUNC(sh7021_device::itu_bra_w<3>));
+ map(0x05ffff2e, 0x05ffff2f).rw(FUNC(sh7021_device::itu_brb_r<3>), FUNC(sh7021_device::itu_brb_w<3>));
+
+ map(0x05ffff32, 0x05ffff32).rw(FUNC(sh7021_device::itu_tcr_r<4>), FUNC(sh7021_device::itu_tcr_w<4>));
+ map(0x05ffff33, 0x05ffff33).rw(FUNC(sh7021_device::itu_tior_r<4>), FUNC(sh7021_device::itu_tior_w<4>));
+ map(0x05ffff34, 0x05ffff34).rw(FUNC(sh7021_device::itu_tier_r<4>), FUNC(sh7021_device::itu_tier_w<4>));
+ map(0x05ffff35, 0x05ffff35).rw(FUNC(sh7021_device::itu_tsr_r<4>), FUNC(sh7021_device::itu_tsr_w<4>));
+ map(0x05ffff36, 0x05ffff37).rw(FUNC(sh7021_device::itu_tcnt_r<4>), FUNC(sh7021_device::itu_tcnt_w<4>));
+ map(0x05ffff38, 0x05ffff39).rw(FUNC(sh7021_device::itu_gra_r<4>), FUNC(sh7021_device::itu_gra_w<4>));
+ map(0x05ffff3a, 0x05ffff3b).rw(FUNC(sh7021_device::itu_grb_r<4>), FUNC(sh7021_device::itu_grb_w<4>));
+ map(0x05ffff3c, 0x05ffff3d).rw(FUNC(sh7021_device::itu_bra_r<4>), FUNC(sh7021_device::itu_bra_w<4>));
+ map(0x05ffff3e, 0x05ffff3f).rw(FUNC(sh7021_device::itu_brb_r<4>), FUNC(sh7021_device::itu_brb_w<4>));
+
+ map(0x05ffff40, 0x05ffff43).rw(FUNC(sh7021_device::dma_sar_r<0>), FUNC(sh7021_device::dma_sar_w<0>));
+ map(0x05ffff44, 0x05ffff47).rw(FUNC(sh7021_device::dma_dar_r<0>), FUNC(sh7021_device::dma_dar_w<0>));
+ map(0x05ffff48, 0x05ffff49).rw(FUNC(sh7021_device::dmaor_r), FUNC(sh7021_device::dmaor_w));
+ map(0x05ffff4a, 0x05ffff4b).rw(FUNC(sh7021_device::dma_tcr_r<0>), FUNC(sh7021_device::dma_tcr_w<0>));
+ map(0x05ffff4e, 0x05ffff4f).rw(FUNC(sh7021_device::dma_chcr_r<0>), FUNC(sh7021_device::dma_chcr_w<0>));
+
+ map(0x05ffff50, 0x05ffff53).rw(FUNC(sh7021_device::dma_sar_r<1>), FUNC(sh7021_device::dma_sar_w<1>));
+ map(0x05ffff54, 0x05ffff57).rw(FUNC(sh7021_device::dma_dar_r<1>), FUNC(sh7021_device::dma_dar_w<1>));
+ map(0x05ffff5a, 0x05ffff5b).rw(FUNC(sh7021_device::dma_tcr_r<1>), FUNC(sh7021_device::dma_tcr_w<1>));
+ map(0x05ffff5e, 0x05ffff5f).rw(FUNC(sh7021_device::dma_chcr_r<1>), FUNC(sh7021_device::dma_chcr_w<1>));
+
+ map(0x05ffff60, 0x05ffff63).rw(FUNC(sh7021_device::dma_sar_r<2>), FUNC(sh7021_device::dma_sar_w<2>));
+ map(0x05ffff64, 0x05ffff67).rw(FUNC(sh7021_device::dma_dar_r<2>), FUNC(sh7021_device::dma_dar_w<2>));
+ map(0x05ffff6a, 0x05ffff6b).rw(FUNC(sh7021_device::dma_tcr_r<2>), FUNC(sh7021_device::dma_tcr_w<2>));
+ map(0x05ffff6e, 0x05ffff6f).rw(FUNC(sh7021_device::dma_chcr_r<2>), FUNC(sh7021_device::dma_chcr_w<2>));
+
+ map(0x05ffff70, 0x05ffff73).rw(FUNC(sh7021_device::dma_sar_r<3>), FUNC(sh7021_device::dma_sar_w<3>));
+ map(0x05ffff74, 0x05ffff77).rw(FUNC(sh7021_device::dma_dar_r<3>), FUNC(sh7021_device::dma_dar_w<3>));
+ map(0x05ffff7a, 0x05ffff7b).rw(FUNC(sh7021_device::dma_tcr_r<3>), FUNC(sh7021_device::dma_tcr_w<3>));
+ map(0x05ffff7e, 0x05ffff7f).rw(FUNC(sh7021_device::dma_chcr_r<3>), FUNC(sh7021_device::dma_chcr_w<3>));
+
+ map(0x05ffff84, 0x05ffff85).rw(FUNC(sh7021_device::intc_ipra_r), FUNC(sh7021_device::intc_ipra_w));
+ map(0x05ffff86, 0x05ffff87).rw(FUNC(sh7021_device::intc_iprb_r), FUNC(sh7021_device::intc_iprb_w));
+ map(0x05ffff88, 0x05ffff89).rw(FUNC(sh7021_device::intc_iprc_r), FUNC(sh7021_device::intc_iprc_w));
+ map(0x05ffff8a, 0x05ffff8b).rw(FUNC(sh7021_device::intc_iprd_r), FUNC(sh7021_device::intc_iprd_w));
+ map(0x05ffff8c, 0x05ffff8d).rw(FUNC(sh7021_device::intc_ipre_r), FUNC(sh7021_device::intc_ipre_w));
+ map(0x05ffff8e, 0x05ffff8f).rw(FUNC(sh7021_device::intc_icr_r), FUNC(sh7021_device::intc_icr_w));
+
+ map(0x05ffff90, 0x05ffff91).rw(FUNC(sh7021_device::ubc_barh_r), FUNC(sh7021_device::ubc_barh_w));
+ map(0x05ffff92, 0x05ffff93).rw(FUNC(sh7021_device::ubc_barl_r), FUNC(sh7021_device::ubc_barl_w));
+ map(0x05ffff94, 0x05ffff95).rw(FUNC(sh7021_device::ubc_bamrh_r), FUNC(sh7021_device::ubc_bamrh_w));
+ map(0x05ffff96, 0x05ffff97).rw(FUNC(sh7021_device::ubc_bamrl_r), FUNC(sh7021_device::ubc_bamrl_w));
+ map(0x05ffff98, 0x05ffff99).rw(FUNC(sh7021_device::ubc_bbr_r), FUNC(sh7021_device::ubc_bbr_w));
+
+ map(0x05ffffa0, 0x05ffffa1).rw(FUNC(sh7021_device::bsc_bcr_r), FUNC(sh7021_device::bsc_bcr_w));
+ map(0x05ffffa2, 0x05ffffa3).rw(FUNC(sh7021_device::bsc_wcr1_r), FUNC(sh7021_device::bsc_wcr1_w));
+ map(0x05ffffa4, 0x05ffffa5).rw(FUNC(sh7021_device::bsc_wcr2_r), FUNC(sh7021_device::bsc_wcr2_w));
+ map(0x05ffffa6, 0x05ffffa7).rw(FUNC(sh7021_device::bsc_wcr3_r), FUNC(sh7021_device::bsc_wcr3_w));
+ map(0x05ffffa8, 0x05ffffa9).rw(FUNC(sh7021_device::bsc_dcr_r), FUNC(sh7021_device::bsc_dcr_w));
+ map(0x05ffffaa, 0x05ffffab).rw(FUNC(sh7021_device::bsc_pcr_r), FUNC(sh7021_device::bsc_pcr_w));
+ map(0x05ffffac, 0x05ffffad).rw(FUNC(sh7021_device::bsc_rcr_r), FUNC(sh7021_device::bsc_rcr_w));
+ map(0x05ffffae, 0x05ffffaf).rw(FUNC(sh7021_device::bsc_rtcsr_r), FUNC(sh7021_device::bsc_rtcsr_w));
+ map(0x05ffffb0, 0x05ffffb1).rw(FUNC(sh7021_device::bsc_rtcnt_r), FUNC(sh7021_device::bsc_rtcnt_w));
+ map(0x05ffffb2, 0x05ffffb3).rw(FUNC(sh7021_device::bsc_rtcor_r), FUNC(sh7021_device::bsc_rtcor_w));
+
+ map(0x05ffffb8, 0x05ffffb8).rw(FUNC(sh7021_device::wdt_tcsr_r), FUNC(sh7021_device::wdt_tcsr_w));
+ map(0x05ffffb9, 0x05ffffb9).rw(FUNC(sh7021_device::wdt_tcnt_r), FUNC(sh7021_device::wdt_tcnt_w));
+ map(0x05ffffba, 0x05ffffba).rw(FUNC(sh7021_device::wdt_rstcsr_r), FUNC(sh7021_device::wdt_rstcsr_w));
+
+ map(0x05ffffc0, 0x05ffffc1).rw(FUNC(sh7021_device::pfc_padr_r), FUNC(sh7021_device::pfc_padr_w));
+ map(0x05ffffc2, 0x05ffffc3).rw(FUNC(sh7021_device::pfc_pbdr_r), FUNC(sh7021_device::pfc_pbdr_w));
+ map(0x05ffffc4, 0x05ffffc5).rw(FUNC(sh7021_device::pfc_paior_r), FUNC(sh7021_device::pfc_paior_w));
+ map(0x05ffffc6, 0x05ffffc7).rw(FUNC(sh7021_device::pfc_pbior_r), FUNC(sh7021_device::pfc_pbior_w));
+ map(0x05ffffc8, 0x05ffffc9).rw(FUNC(sh7021_device::pfc_pacr1_r), FUNC(sh7021_device::pfc_pacr1_w));
+ map(0x05ffffca, 0x05ffffcb).rw(FUNC(sh7021_device::pfc_pacr2_r), FUNC(sh7021_device::pfc_pacr2_w));
+ map(0x05ffffcc, 0x05ffffcd).rw(FUNC(sh7021_device::pfc_pbcr1_r), FUNC(sh7021_device::pfc_pbcr1_w));
+ map(0x05ffffce, 0x05ffffcf).rw(FUNC(sh7021_device::pfc_pbcr2_r), FUNC(sh7021_device::pfc_pbcr2_w));
+
+ map(0x05fffff0, 0x05fffff0).rw(FUNC(sh7021_device::tpc_tpmr_r), FUNC(sh7021_device::tpc_tpmr_w));
+ map(0x05fffff1, 0x05fffff1).rw(FUNC(sh7021_device::tpc_tpcr_r), FUNC(sh7021_device::tpc_tpcr_w));
+ map(0x05fffff2, 0x05fffff2).rw(FUNC(sh7021_device::tpc_ndera_r), FUNC(sh7021_device::tpc_ndera_w));
+ map(0x05fffff3, 0x05fffff3).rw(FUNC(sh7021_device::tpc_nderb_r), FUNC(sh7021_device::tpc_nderb_w));
+ map(0x05fffff4, 0x05fffff4).rw(FUNC(sh7021_device::tpc_ndrb_r), FUNC(sh7021_device::tpc_ndrb_w));
+ map(0x05fffff5, 0x05fffff5).rw(FUNC(sh7021_device::tpc_ndra_r), FUNC(sh7021_device::tpc_ndra_w));
+ map(0x05fffff6, 0x05fffff6).rw(FUNC(sh7021_device::tpc_ndrb_alt_r), FUNC(sh7021_device::tpc_ndrb_alt_w));
+ map(0x05fffff7, 0x05fffff7).rw(FUNC(sh7021_device::tpc_ndra_alt_r), FUNC(sh7021_device::tpc_ndra_alt_w));
+
+ map(0x07000000, 0x070003ff).ram().mirror(0x00fffc00); // 1KB internal RAM, actually at 0xf000000
+}
+
+sh7021_device::sh7021_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : sh2_device(mconfig, SH7021, tag, owner, clock, CPU_TYPE_SH2, address_map_constructor(FUNC(sh7021_device::internal_map), this), 28, 0xc7ffffff)
+ , m_pa_out(*this)
+ , m_pb_out(*this)
+ , m_pa_bit_out(*this)
+ , m_pb_bit_out(*this)
+{
+ m_isdrc = false; // FIXME
+}
+
+void sh7021_device::execute_run()
+{
+ int consumed_cycles = 0;
+ do
+ {
+ int icount_before = m_sh2_state->icount;
+ debugger_instruction_hook(m_sh2_state->pc);
+
+ const uint16_t opcode = decrypted_read_word(m_sh2_state->pc >= 0x40000000 ? m_sh2_state->pc : m_sh2_state->pc & m_am);
+
+ if (m_sh2_state->m_delay)
+ {
+ m_sh2_state->pc = m_sh2_state->m_delay;
+ m_sh2_state->m_delay = 0;
+ }
+ else
+ m_sh2_state->pc += 2;
+
+ execute_peripherals(consumed_cycles);
+ execute_one(opcode);
+
+ if (m_test_irq && !m_sh2_state->m_delay)
+ {
+ check_pending_irq("mame_sh2_execute");
+ m_test_irq = 0;
+ }
+ m_sh2_state->icount--;
+ consumed_cycles = icount_before - m_sh2_state->icount;
+ } while (m_sh2_state->icount > 0);
+}
+
+void sh7021_device::device_start()
+{
+ sh2_device::device_start();
+
+ m_itu.timer[0].et = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh7021_device::sh7021_timer_callback<0>), this));
+ m_itu.timer[1].et = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh7021_device::sh7021_timer_callback<1>), this));
+ m_itu.timer[2].et = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh7021_device::sh7021_timer_callback<2>), this));
+ m_itu.timer[3].et = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh7021_device::sh7021_timer_callback<3>), this));
+ m_itu.timer[4].et = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh7021_device::sh7021_timer_callback<4>), this));
+
+ for (uint32_t i = 0; i < 5; ++i)
+ {
+ m_itu.timer[i].et->adjust(attotime::never);
+ }
+
+ m_sci[0].et = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh7021_device::sh7021_sci_callback<0>), this));
+ m_sci[1].et = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sh7021_device::sh7021_sci_callback<1>), this));
+
+ for (uint32_t i = 0; i < 2; ++i)
+ {
+ m_sci[i].et->adjust(attotime::never);
+ }
+
+ // Interrupt Controller (INTC)
+ save_item(NAME(m_iprc));
+ save_item(NAME(m_iprd));
+ save_item(NAME(m_ipre));
+ save_item(NAME(m_icr));
+
+ // User Break Controller (UBC)
+ save_item(STRUCT_MEMBER(m_ubc, barh));
+ save_item(STRUCT_MEMBER(m_ubc, barl));
+ save_item(STRUCT_MEMBER(m_ubc, bamrh));
+ save_item(STRUCT_MEMBER(m_ubc, bamrl));
+ save_item(STRUCT_MEMBER(m_ubc, bbr));
+
+ // Bus State Controller (BSC)
+ save_item(STRUCT_MEMBER(m_bsc, bcr));
+ save_item(STRUCT_MEMBER(m_bsc, wcr1));
+ save_item(STRUCT_MEMBER(m_bsc, wcr2));
+ save_item(STRUCT_MEMBER(m_bsc, wcr3));
+ save_item(STRUCT_MEMBER(m_bsc, dcr));
+ save_item(STRUCT_MEMBER(m_bsc, pcr));
+ save_item(STRUCT_MEMBER(m_bsc, rcr));
+ save_item(STRUCT_MEMBER(m_bsc, rtcsr));
+ save_item(STRUCT_MEMBER(m_bsc, rtcsr_read));
+ save_item(STRUCT_MEMBER(m_bsc, rtcnt));
+ save_item(STRUCT_MEMBER(m_bsc, rtcor));
+
+ // DMA Controller (DMAC)
+ save_item(STRUCT_MEMBER(m_dma, sar));
+ save_item(STRUCT_MEMBER(m_dma, dar));
+ save_item(STRUCT_MEMBER(m_dma, tcr));
+ save_item(STRUCT_MEMBER(m_dma, chcr));
+ save_item(NAME(m_dma_cycles));
+
+ // 16-Bit Integrated-Timer Pulse Unit (ITU)
+ save_item(STRUCT_MEMBER(m_itu, tstr));
+ save_item(STRUCT_MEMBER(m_itu, tsnc));
+ save_item(STRUCT_MEMBER(m_itu, tmdr));
+ save_item(STRUCT_MEMBER(m_itu, tfcr));
+ save_item(STRUCT_MEMBER(m_itu, tocr));
+ save_item(STRUCT_MEMBER(m_itu.timer, tcr));
+ save_item(STRUCT_MEMBER(m_itu.timer, tior));
+ save_item(STRUCT_MEMBER(m_itu.timer, tier));
+ save_item(STRUCT_MEMBER(m_itu.timer, tsr));
+ save_item(STRUCT_MEMBER(m_itu.timer, tcnt));
+ save_item(STRUCT_MEMBER(m_itu.timer, gra));
+ save_item(STRUCT_MEMBER(m_itu.timer, grb));
+ save_item(STRUCT_MEMBER(m_itu.timer, bra));
+ save_item(STRUCT_MEMBER(m_itu.timer, brb));
+
+ // Programmable Timing Pattern Controller (TPC)
+ save_item(STRUCT_MEMBER(m_tpc, tpmr));
+ save_item(STRUCT_MEMBER(m_tpc, tpcr));
+ save_item(STRUCT_MEMBER(m_tpc, ndera));
+ save_item(STRUCT_MEMBER(m_tpc, nderb));
+ save_item(STRUCT_MEMBER(m_tpc, ndra));
+ save_item(STRUCT_MEMBER(m_tpc, ndrb));
+
+ // Watchdog Timer (WDT)
+ save_item(STRUCT_MEMBER(m_wdt, tcsr));
+ save_item(STRUCT_MEMBER(m_wdt, tcnt));
+ save_item(STRUCT_MEMBER(m_wdt, rstcsr));
+
+ // Serial Communication Interface (SCI)
+ save_item(STRUCT_MEMBER(m_sci, smr));
+ save_item(STRUCT_MEMBER(m_sci, brr));
+ save_item(STRUCT_MEMBER(m_sci, scr));
+ save_item(STRUCT_MEMBER(m_sci, tsr));
+ save_item(STRUCT_MEMBER(m_sci, tdr));
+ save_item(STRUCT_MEMBER(m_sci, ssr));
+ save_item(STRUCT_MEMBER(m_sci, ssr_read));
+ save_item(STRUCT_MEMBER(m_sci, rsr));
+ save_item(STRUCT_MEMBER(m_sci, rdr));
+
+ // Pin Function Controller (PFC)
+ save_item(STRUCT_MEMBER(m_pfc, paior));
+ save_item(STRUCT_MEMBER(m_pfc, pacr1));
+ save_item(STRUCT_MEMBER(m_pfc, pacr2));
+ save_item(STRUCT_MEMBER(m_pfc, pbior));
+ save_item(STRUCT_MEMBER(m_pfc, pbcr1));
+ save_item(STRUCT_MEMBER(m_pfc, pbcr2));
+ save_item(STRUCT_MEMBER(m_pfc, padr));
+ save_item(STRUCT_MEMBER(m_pfc, pbdr));
+ save_item(STRUCT_MEMBER(m_pfc, padr_in));
+ save_item(STRUCT_MEMBER(m_pfc, pbdr_in));
+ save_item(STRUCT_MEMBER(m_pfc, cascr));
+ save_item(STRUCT_MEMBER(m_pfc, pafunc));
+ save_item(STRUCT_MEMBER(m_pfc, pbfunc));
+ save_item(STRUCT_MEMBER(m_pfc, pa_gpio_mask));
+ save_item(STRUCT_MEMBER(m_pfc, pb_gpio_mask));
+}
+
+void sh7021_device::device_reset()
+{
+ sh2_device::device_reset();
+
+ // Interrupt Controller (INTC)
+ m_ipra = 0;
+ m_iprb = 0;
+ m_iprc = 0;
+ m_iprd = 0;
+ m_ipre = 0;
+ m_icr = 0;
+
+ // User Break Controller (UBC)
+ m_ubc.barh = 0;
+ m_ubc.barl = 0;
+ m_ubc.bamrh = 0;
+ m_ubc.bamrl = 0;
+ m_ubc.bbr = 0;
+
+ // Bus State Controller (BSC)
+ m_bsc.bcr = 0;
+ m_bsc.wcr1 = 0xffff;
+ m_bsc.wcr2 = 0xffff;
+ m_bsc.wcr3 = 0xf800;
+ m_bsc.dcr = 0;
+ m_bsc.pcr = 0;
+ m_bsc.rcr = 0;
+ m_bsc.rtcsr = 0;
+ m_bsc.rtcsr_read = false;
+ m_bsc.rtcnt = 0;
+ m_bsc.rtcor = 0x00ff;
+
+ // DMA Controller (DMAC)
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ m_dma[i].sar = 0;
+ m_dma[i].dar = 0;
+ m_dma[i].tcr = 0;
+ m_dma[i].chcr = 0;
+ }
+ m_dmaor = 0;
+ m_dma_cycles = 0;
+
+ // 16-Bit Integrated-Timer Pulse Unit (ITU)
+ m_itu.tstr = 0x60;
+ m_itu.tsnc = 0x60;
+ m_itu.tmdr = 0;
+ m_itu.tfcr = 0x40;
+ m_itu.tocr = 0x7f;
+ for (uint32_t i = 0; i < 5; i++)
+ {
+ m_itu.timer[i].tcr = 0;
+ m_itu.timer[i].tior = 0x08;
+ m_itu.timer[i].tier = 0xf8;
+ m_itu.timer[i].tsr = 0xf8;
+ m_itu.timer[i].tcnt = 0;
+ m_itu.timer[i].gra = 0xffff;
+ m_itu.timer[i].grb = 0xffff;
+ m_itu.timer[i].bra = 0xffff;
+ m_itu.timer[i].brb = 0xffff;
+ }
+
+ // Programmable Timing Pattern Controller (TPC)
+ m_tpc.tpmr = 0xf0;
+ m_tpc.tpcr = 0xff;
+ m_tpc.nderb = 0;
+ m_tpc.ndera = 0;
+ m_tpc.ndra = 0;
+ m_tpc.ndrb = 0;
+
+ // Watchdog Timer (WDT)
+ m_wdt.tcsr = 0x18;
+ m_wdt.tcnt = 0;
+ m_wdt.rstcsr = 0x3f;
+
+ // Serial Communication Interface (SCI)
+ for (uint32_t i = 0; i < 2; i++)
+ {
+ m_sci[i].smr = 0;
+ m_sci[i].brr = 0xff;
+ m_sci[i].scr = 0;
+ m_sci[i].tsr = 0;
+ m_sci[i].tdr = 0xff;
+ m_sci[i].ssr = 0x84;
+ m_sci[i].ssr_read = 0;
+ m_sci[i].rsr = 0;
+ m_sci[i].rdr = 0;
+ }
+
+ // Pin Function Controller (PFC)
+ m_pfc.paior = 0;
+ m_pfc.pacr1 = 0x3302;
+ m_pfc.pacr2 = 0xff95;
+ m_pfc.pbior = 0;
+ m_pfc.pbcr1 = 0;
+ m_pfc.pbcr2 = 0;
+ m_pfc.padr = 0;
+ m_pfc.pbdr = 0;
+ m_pfc.padr_in = 0;
+ m_pfc.pbdr_in = 0;
+ m_pfc.cascr = 0x5fff;
+ m_pfc.pa_gpio_mask = 0;
+ m_pfc.pb_gpio_mask = 0xffff;
+
+ static constexpr uint16_t PACR1_W_MASK = 0xfffd;
+ static constexpr uint16_t PACR2_W_MASK = 0x55ff;
+ for (int i = 0; i < 16; i++)
+ {
+ int bit = (i & 7) << 1;
+
+ uint16_t data = (i >= 8 ? (m_pfc.pacr1 & PACR1_W_MASK) : (m_pfc.pacr2 & PACR2_W_MASK));
+ uint8_t func = (data >> bit) & 3;
+ m_pfc.pafunc[i] = (data >> bit) & 3;
+ if (func == 0)
+ m_pfc.pa_gpio_mask |= 1 << i;
+ m_pfc.pbfunc[i] = 0;
+ }
+}
+
+uint8_t sh7021_device::read_byte(offs_t offset)
+{
+ const uint32_t area = (offset >> 24) & 7;
+ if (area == 6)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 11) & 3) + 1; // Consume cycles specified by A6LW
+ else if (area == 0 || area == 2)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 13) & 3) + 1; // Consume cycles specified by A02LW
+
+ return m_program->read_byte(offset & m_am);
+}
+
+uint16_t sh7021_device::read_word(offs_t offset)
+{
+ const uint32_t area = (offset >> 24) & 7;
+ if (area == 6)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 11) & 3) + 1; // Consume cycles specified by A6LW
+ else if (area == 0 || area == 2)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 13) & 3) + 1; // Consume cycles specified by A02LW
+
+ return m_program->read_word(offset & m_am);
+}
+
+uint32_t sh7021_device::read_long(offs_t offset)
+{
+ const uint32_t area = (offset >> 24) & 7;
+ if (area == 6)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 11) & 3) + 1; // Consume cycles specified by A6LW
+ else if (area == 0 || area == 2)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 13) & 3) + 1; // Consume cycles specified by A02LW
+
+ return m_program->read_dword(offset & m_am);
+}
+
+uint16_t sh7021_device::decrypted_read_word(offs_t offset)
+{
+ const uint32_t area = (offset >> 24) & 7;
+ if (area == 6)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 11) & 3) + 1; // Consume cycles specified by A6LW
+ else if (area == 0 || area == 2)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 13) & 3) + 1; // Consume cycles specified by A02LW
+
+ return m_decrypted_program->read_word(offset);
+}
+
+void sh7021_device::write_byte(offs_t offset, uint8_t data)
+{
+ const uint32_t area = (offset >> 24) & 7;
+ if (area == 6)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 11) & 3) + 1; // Consume cycles specified by A6LW
+ else if (area == 0 || area == 2)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 13) & 3) + 1; // Consume cycles specified by A02LW
+
+ m_program->write_byte(offset & m_am, data);
+}
+
+void sh7021_device::write_word(offs_t offset, uint16_t data)
+{
+ const uint32_t area = (offset >> 24) & 7;
+ if (area == 6)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 11) & 3) + 1; // Consume cycles specified by A6LW
+ else if (area == 0 || area == 2)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 13) & 3) + 1; // Consume cycles specified by A02LW
+
+ m_program->write_word(offset & m_am, data);
+}
+
+void sh7021_device::write_long(offs_t offset, uint32_t data)
+{
+ const uint32_t area = (offset >> 24) & 7;
+ if (area == 6)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 11) & 3) + 1; // Consume cycles specified by A6LW
+ else if (area == 0 || area == 2)
+ m_sh2_state->icount -= ((m_bsc.wcr3 >> 13) & 3) + 1; // Consume cycles specified by A02LW
+
+ m_program->write_dword(offset & m_am, data);
+}
+
+void sh7021_device::recalc_irq()
+{
+ int irq = 0;
+ int vector = -1;
+
+ // Serial IRQs
+ for (uint32_t i = 0; i < 2; ++i)
+ {
+ int sci_level = (i == 1 ? ((m_ipre >> 12) & 0xf) : (m_iprd & 0xf));
+ if (sci_level == 0)
+ {
+ continue;
+ }
+
+ if (BIT(m_sci[i].scr, 7) && BIT(m_sci[i].ssr, 7))
+ {
+ // TxI
+ irq = sci_level;
+ vector = 102 + i * 4;
+ LOGMASKED(LOG_DMA_WR, "SCI Tx interrupt %d is ready, level %d vector %d\n", i, irq, vector);
+ }
+ else if (BIT(m_sci[i].scr, 2) && BIT(m_sci[i].ssr, 2))
+ {
+ // TEI
+ irq = sci_level;
+ vector = 103 + i * 4;
+ LOGMASKED(LOG_DMA_WR, "SCI TE interrupt %d is ready, level %d vector %d\n", i, irq, vector);
+ }
+ }
+
+ // Timer IRQs
+ for (uint32_t i = 0; i < 5; ++i)
+ {
+ if ((m_itu.timer[i].tier & m_itu.timer[i].tsr) & 7)
+ {
+ int level;
+
+ switch (i)
+ {
+ case 0:
+ level = (m_iprc >> 4) & 0xf;
+ break;
+ case 1:
+ level = (m_iprc >> 0) & 0xf;
+ break;
+ case 2:
+ level = (m_iprd >> 12) & 0xf;
+ break;
+ case 3:
+ level = (m_iprd >> 8) & 0xf;
+ break;
+ case 4:
+ level = (m_iprd >> 4) & 0xf;
+ break;
+ }
+
+ if (level == 0)
+ {
+ continue;
+ }
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ if (BIT(m_itu.timer[i].tier & m_itu.timer[i].tsr, j))
+ {
+ irq = level;
+ vector = 80 + i * 4 + j;
+ break;
+ }
+ }
+ }
+ }
+
+ if (vector >= 0)
+ {
+ m_sh2_state->internal_irq_level = irq;
+ m_internal_irq_vector = vector;
+ m_test_irq = 1;
+ }
+}
+
+
+// Interrupt Controller (INTC)
+
+uint16_t sh7021_device::intc_ipra_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_INTC_RD, "%s: intc_ipra_r: %04x\n", machine().describe_context(), m_ipra);
+ return m_ipra;
+}
+
+void sh7021_device::intc_ipra_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_INTC_WR, "%s: intc_ipra_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ipra);
+}
+
+uint16_t sh7021_device::intc_iprb_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_INTC_RD, "%s: intc_iprb_r: %04x\n", machine().describe_context(), m_iprb);
+ return m_iprb;
+}
+
+void sh7021_device::intc_iprb_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_INTC_WR, "%s: intc_iprb_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_iprb);
+}
+
+uint16_t sh7021_device::intc_iprc_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_INTC_RD, "%s: intc_iprc_r: %04x\n", machine().describe_context(), m_iprc);
+ return m_iprc;
+}
+
+void sh7021_device::intc_iprc_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_INTC_WR, "%s: intc_iprc_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_iprc);
+}
+
+uint16_t sh7021_device::intc_iprd_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_INTC_RD, "%s: intc_iprd_r: %04x\n", machine().describe_context(), m_iprd);
+ return m_iprd;
+}
+
+void sh7021_device::intc_iprd_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_INTC_WR, "%s: intc_iprd_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_iprd);
+}
+
+uint16_t sh7021_device::intc_ipre_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_INTC_RD, "%s: intc_ipre_r: %04x\n", machine().describe_context(), m_ipre);
+ return m_ipre;
+}
+
+void sh7021_device::intc_ipre_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_INTC_WR, "%s: intc_ipre_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ipre);
+}
+
+uint16_t sh7021_device::intc_icr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_INTC_RD, "%s: intc_icr_r: %04x\n", machine().describe_context(), m_ipre);
+ return m_icr;
+}
+
+void sh7021_device::intc_icr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_INTC_WR, "%s: intc_icr_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_icr);
+}
+
+
+// User Break Controller (UBC)
+
+uint16_t sh7021_device::ubc_barh_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_UBC_RD, "%s: Break Address Register H, ubc_barh_r: %04x\n", machine().describe_context(), m_ubc.barh);
+ return m_ubc.barh;
+}
+
+void sh7021_device::ubc_barh_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_UBC_WR, "%s: Break Address Register H, ubc_barh_w = %04x\n", machine().describe_context(), data);
+ COMBINE_DATA(&m_ubc.barh);
+}
+
+uint16_t sh7021_device::ubc_barl_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_UBC_RD, "%s: Break Address Register L, ubc_barl_r: %04x\n", machine().describe_context(), m_ubc.barl);
+ return m_ubc.barl;
+}
+
+void sh7021_device::ubc_barl_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_UBC_WR, "%s: Break Address Register L, ubc_barl_w = %04x\n", machine().describe_context(), data);
+ COMBINE_DATA(&m_ubc.barl);
+}
+
+uint16_t sh7021_device::ubc_bamrh_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_UBC_RD, "%s: Break Address Mask Register H, ubc_bamrh_r: %04x\n", machine().describe_context(), m_ubc.bamrh);
+ return m_ubc.bamrh;
+}
+
+void sh7021_device::ubc_bamrh_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_UBC_WR, "%s: Break Address Mask Register H, ubc_bmarh_w = %04x\n", machine().describe_context(), data);
+ COMBINE_DATA(&m_ubc.bamrh);
+}
+
+uint16_t sh7021_device::ubc_bamrl_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_UBC_RD, "%s: Break Address Mask Register L, ubc_bamrl_r: %04x\n", machine().describe_context(), m_ubc.bamrl);
+ return m_ubc.bamrl;
+}
+
+void sh7021_device::ubc_bamrl_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_UBC_WR, "%s: Break Address Mask Register L, ubc_bmarl_w = %04x\n", machine().describe_context(), data);
+ COMBINE_DATA(&m_ubc.bamrl);
+}
+
+uint16_t sh7021_device::ubc_bbr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_UBC_RD, "%s: Break Bus Cycle Register, ubc_bbr_r: %04x\n", machine().describe_context(), m_ubc.bbr);
+ return m_ubc.bbr;
+}
+
+void sh7021_device::ubc_bbr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ static const char *const CPU_DMA_NAMES[4] = { "No break", "Break on CPU cycles", "Break on DMA cycles", "Break on both CPU and DMA cycles" };
+ static const char *const INSN_DATA_NAMES[4] = { "No break", "Break on instruction fetch cycles", "Break on data access cycles", "Break on both instruction and data cycles" };
+ static const char *const READ_WRITE_NAMES[4] = { "No break", "Break on read cycles", "Break on write cycles", "Break on both read and write cycles" };
+ static const char *const SIZE_NAMES[4] = { "No break", "Break on byte access", "Break on word access", "Break on long word access" };
+ LOGMASKED(LOG_UBC_WR, "%s: Break Bus Cycle Register, ubc_bbr_w = %04x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_UBC_WR, "%s: CPU/DMA Cycle Select: %s\n", machine().describe_context(), CPU_DMA_NAMES[(data >> 6) & 3]);
+ LOGMASKED(LOG_UBC_WR, "%s: Instruction/Data Fetch Select: %s\n", machine().describe_context(), INSN_DATA_NAMES[(data >> 4) & 3]);
+ LOGMASKED(LOG_UBC_WR, "%s: Read/Write Select: %s\n", machine().describe_context(), READ_WRITE_NAMES[(data >> 2) & 3]);
+ LOGMASKED(LOG_UBC_WR, "%s: Operand Size Select: %s\n", machine().describe_context(), SIZE_NAMES[data & 3]);
+ COMBINE_DATA(&m_ubc.bbr);
+}
+
+
+// Bus State Controller (BSC)
+
+uint16_t sh7021_device::bsc_bcr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_BSC_RD, "%s: Bus Control Register, bsc_bcr_r: %04x\n", machine().describe_context(), m_bsc.bcr);
+ return m_bsc.bcr;
+}
+
+void sh7021_device::bsc_bcr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_BSC_WR, "%s: Bus Control Register bsc_bcr_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_BSC_WR, "%s: DRAM Enable: %d\n", machine().describe_context(), BIT(data, 15));
+ LOGMASKED(LOG_BSC_WR, "%s: Multiplexed I/O Enable: %d\n", machine().describe_context(), BIT(data, 14));
+ LOGMASKED(LOG_BSC_WR, "%s: WARP Enable: %d\n", machine().describe_context(), BIT(data, 13));
+ LOGMASKED(LOG_BSC_WR, "%s: /RD High Duty Cycle: %d% of T1 state\n", machine().describe_context(), BIT(data, 12) ? 35 : 50);
+ LOGMASKED(LOG_BSC_WR, "%s: Byte Access Select: %s\n", machine().describe_context(), BIT(data, 11) ? "/LBS, /WR, /HBS enabled" : "/WRH, /WRL, A0 enabled");
+ COMBINE_DATA(&m_bsc.bcr);
+}
+
+uint16_t sh7021_device::bsc_wcr1_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_BSC_RD, "%s: Wait State Control Register 1, bsc_wcr1_r: %04x\n", machine().describe_context(), m_bsc.wcr1);
+ return m_bsc.wcr1;
+}
+
+void sh7021_device::bsc_wcr1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_BSC_WR, "%s: Wait State Control Register 1, bsc_wcr1_w = %04x\n", machine().describe_context(), data);
+ COMBINE_DATA(&m_bsc.wcr1);
+}
+
+uint16_t sh7021_device::bsc_wcr2_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_BSC_RD, "%s: Wait State Control Register 2, bsc_wcr2_r: %04x\n", machine().describe_context(), m_bsc.wcr2);
+ return m_bsc.wcr2;
+}
+
+void sh7021_device::bsc_wcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_BSC_WR, "%s: Wait State Control Register 2, bsc_wcr2_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_bsc.wcr2);
+}
+
+uint16_t sh7021_device::bsc_wcr3_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_BSC_RD, "%s: Wait State Control Register 3, bsc_wcr3_r: %04x\n", machine().describe_context(), m_bsc.wcr3);
+ return m_bsc.wcr3;
+}
+
+void sh7021_device::bsc_wcr3_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_BSC_WR, "%s: Wait State Control Register 3, bsc_wcr3_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_bsc.wcr3);
+}
+
+uint16_t sh7021_device::bsc_dcr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_BSC_RD, "%s: DRAM Control Register, bsc_dcr_r: %04x\n", machine().describe_context(), m_bsc.dcr);
+ return m_bsc.dcr;
+}
+
+void sh7021_device::bsc_dcr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_BSC_WR, "%s: DRAM Control Register, bsc_dcr_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_BSC_WR, "%s: Dual-WE Mode: %d\n", machine().describe_context(), BIT(data, 15));
+ LOGMASKED(LOG_BSC_WR, "%s: RAS Down Mode: %d\n", machine().describe_context(), BIT(data, 14));
+ LOGMASKED(LOG_BSC_WR, "%s: 2-state Precharge: %d\n", machine().describe_context(), BIT(data, 13));
+ LOGMASKED(LOG_BSC_WR, "%s: Burst Enable: %d\n", machine().describe_context(), BIT(data, 12));
+ LOGMASKED(LOG_BSC_WR, "%s: /CAS High Duty Cycle: %d% of Tc state\n", machine().describe_context(), BIT(data, 11) ? 35 : 50);
+ LOGMASKED(LOG_BSC_WR, "%s: Row/Column Multiplex Enable: %d\n", machine().describe_context(), BIT(data, 10));
+ LOGMASKED(LOG_BSC_WR, "%s: Multiplex Shift Count: %d\n", machine().describe_context(), 8 + ((data >> 8) & 3));
+ COMBINE_DATA(&m_bsc.dcr);
+}
+
+uint16_t sh7021_device::bsc_pcr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_BSC_RD, "%s: Parity Control Register, bsc_pcr_r: %04x\n", machine().describe_context(), m_bsc.pcr);
+ return m_bsc.pcr;
+}
+
+void sh7021_device::bsc_pcr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ static const char *const PARITY_CHECK_NAMES[4] =
+ {
+ "Don't Check, Don't Generate",
+ "Check and Generate in DRAM",
+ "Check and Generate in DRAM and Area 2",
+ "Reserved",
+ };
+
+ LOGMASKED(LOG_BSC_WR, "%s: Parity Control Register, bsc_pcr_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_BSC_WR, "%s: Parity Error Clear: %d\n", machine().describe_context(), BIT(data, 15));
+ LOGMASKED(LOG_BSC_WR, "%s: Force Parity Error: %d\n", machine().describe_context(), BIT(data, 14));
+ LOGMASKED(LOG_BSC_WR, "%s: Parity Polarity: %s\n", machine().describe_context(), BIT(data, 13) ? "odd" : "even");
+ LOGMASKED(LOG_BSC_WR, "%s: Parity Check Enable: %s\n", machine().describe_context(), PARITY_CHECK_NAMES[(data >> 11) & 3]);
+ LOGMASKED(LOG_BSC_WR, "%s: Parity Error Clear: %d\n", machine().describe_context(), BIT(data, 15));
+ COMBINE_DATA(&m_bsc.pcr);
+}
+
+uint16_t sh7021_device::bsc_rcr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_BSC_RD, "%s: Refresh Control Register, bsc_rcr_r: %04x\n", machine().describe_context(), m_bsc.rcr);
+ return m_bsc.rcr;
+}
+
+void sh7021_device::bsc_rcr_w(uint16_t data)
+{
+ if ((data >> 8) != 0x5a)
+ return;
+
+ LOGMASKED(LOG_BSC_WR, "%s: Refresh Control Register, bsc_rcr_w = %02x\n", machine().describe_context(), (uint8_t)data);
+ LOGMASKED(LOG_BSC_WR, "%s: Refresh Control Enable: %d\n", machine().describe_context(), BIT(data, 7));
+ LOGMASKED(LOG_BSC_WR, "%s: Refresh Mode: %s\n", machine().describe_context(), BIT(data, 6) ? "Self-refresh" : "CAS-before-RAS");
+ LOGMASKED(LOG_BSC_WR, "%s: CBR Wait States: %d\n", machine().describe_context(), 1 + ((data >> 4) & 3));
+ m_bsc.rcr = (uint8_t)data;
+}
+
+uint16_t sh7021_device::bsc_rtcsr_r()
+{
+ if (!machine().side_effects_disabled())
+ {
+ LOGMASKED(LOG_BSC_RD, "%s: Refresh Timer Control/Status Register, bsc_rtcsr_r: %04x\n", machine().describe_context(), m_bsc.rtcsr);
+ if (BIT(m_bsc.rtcsr, 7))
+ m_bsc.rtcsr_read = true;
+ }
+ return m_bsc.rtcsr;
+}
+
+void sh7021_device::bsc_rtcsr_w(uint16_t data)
+{
+ if ((data >> 8) != 0xa5)
+ return;
+
+ static const char *const RTCSR_CKS_NAMES[8] =
+ {
+ "Disabled", "/2", "/8", "/32", "/128", "/512", "/2048", "/4096"
+ };
+
+ LOGMASKED(LOG_BSC_WR, "%s: Refresh Timer Control/Status Register, bsc_rcr_w = %02x\n", machine().describe_context(), (uint8_t)data);
+ LOGMASKED(LOG_BSC_WR, "%s: Refresh Control Enable: %d\n", machine().describe_context(), BIT(data, 7));
+ LOGMASKED(LOG_BSC_WR, "%s: Compare Match Interrupt Enable: %d\n", machine().describe_context(), BIT(data, 6));
+ LOGMASKED(LOG_BSC_WR, "%s: Refresh Timer Counter Prescale: %d\n", machine().describe_context(), RTCSR_CKS_NAMES[(data >> 3) & 7]);
+ m_bsc.rtcsr = (m_bsc.rtcsr & 0x80) | (uint8_t)(data & 0x7f);
+ if (m_bsc.rtcsr_read && !BIT(data, 7))
+ {
+ m_bsc.rtcsr_read = false;
+ m_bsc.rtcsr &= 0x7f;
+ }
+}
+
+uint16_t sh7021_device::bsc_rtcnt_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_BSC_RD, "%s: Refresh Timer Count, bsc_rtcnt_r: %04x\n", machine().describe_context(), m_bsc.rtcnt);
+ return m_bsc.rtcnt;
+}
+
+void sh7021_device::bsc_rtcnt_w(uint16_t data)
+{
+ if ((data >> 8) != 0x69)
+ return;
+
+ LOGMASKED(LOG_BSC_WR, "%s: Refresh Timer Count, bsc_rtcnt_w = %02x\n", machine().describe_context(), (uint8_t)data);
+ m_bsc.rtcnt = (uint8_t)data;
+}
+
+uint16_t sh7021_device::bsc_rtcor_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_BSC_RD, "%s: Refresh Time Constant Register, bsc_rtcor_r: %04x\n", machine().describe_context(), m_bsc.rtcor);
+ return m_bsc.rtcor;
+}
+
+void sh7021_device::bsc_rtcor_w(uint16_t data)
+{
+ if ((data >> 8) != 0x96)
+ return;
+
+ LOGMASKED(LOG_BSC_WR, "%s: Refresh Time Constant Register, bsc_rtcor_w = %02x\n", machine().describe_context(), (uint8_t)data);
+ m_bsc.rtcor = (uint8_t)data;
+}
+
+
+// DMA Controller (DMAC)
+
+template uint32_t sh7021_device::dma_sar_r<0>();
+template uint32_t sh7021_device::dma_sar_r<1>();
+template uint32_t sh7021_device::dma_sar_r<2>();
+template uint32_t sh7021_device::dma_sar_r<3>();
+
+template <int Channel>
+uint32_t sh7021_device::dma_sar_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_DMA_RD, "%s: DMA Source Address Register %d, dma_sar_r: %08x\n", machine().describe_context(), Channel, m_dma[Channel].sar);
+ return m_dma[Channel].sar;
+}
+
+template void sh7021_device::dma_sar_w<0>(offs_t offset, uint32_t data, uint32_t mem_mask);
+template void sh7021_device::dma_sar_w<1>(offs_t offset, uint32_t data, uint32_t mem_mask);
+template void sh7021_device::dma_sar_w<2>(offs_t offset, uint32_t data, uint32_t mem_mask);
+template void sh7021_device::dma_sar_w<3>(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+template <int Channel>
+void sh7021_device::dma_sar_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_DMA_WR, "%s: DMA Source Address Register %d, dma_sar_w = %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ COMBINE_DATA(&m_dma[Channel].sar);
+}
+
+template uint32_t sh7021_device::dma_dar_r<0>();
+template uint32_t sh7021_device::dma_dar_r<1>();
+template uint32_t sh7021_device::dma_dar_r<2>();
+template uint32_t sh7021_device::dma_dar_r<3>();
+
+template <int Channel>
+uint32_t sh7021_device::dma_dar_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_DMA_RD, "%s: DMA Destination Address Register %d, dma_sar_r: %08x\n", machine().describe_context(), Channel, m_dma[Channel].dar);
+ return m_dma[Channel].dar;
+}
+
+template void sh7021_device::dma_dar_w<0>(offs_t offset, uint32_t data, uint32_t mem_mask);
+template void sh7021_device::dma_dar_w<1>(offs_t offset, uint32_t data, uint32_t mem_mask);
+template void sh7021_device::dma_dar_w<2>(offs_t offset, uint32_t data, uint32_t mem_mask);
+template void sh7021_device::dma_dar_w<3>(offs_t offset, uint32_t data, uint32_t mem_mask);
+
+template <int Channel>
+void sh7021_device::dma_dar_w(offs_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_DMA_WR, "%s: DMA Destination Address Register %d, dma_dar_w = %08x & %08x\n", machine().describe_context(), Channel, data, mem_mask);
+ COMBINE_DATA(&m_dma[Channel].dar);
+}
+
+template uint16_t sh7021_device::dma_tcr_r<0>();
+template uint16_t sh7021_device::dma_tcr_r<1>();
+template uint16_t sh7021_device::dma_tcr_r<2>();
+template uint16_t sh7021_device::dma_tcr_r<3>();
+
+template <int Channel>
+uint16_t sh7021_device::dma_tcr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_DMA_RD, "%s: DMA Transfer Count Register %d, dma_tcr_r: %04x\n", machine().describe_context(), Channel, m_dma[Channel].tcr);
+ return m_dma[Channel].tcr;
+}
+
+template void sh7021_device::dma_tcr_w<0>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::dma_tcr_w<1>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::dma_tcr_w<2>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::dma_tcr_w<3>(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+template <int Channel>
+void sh7021_device::dma_tcr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_DMA_WR, "%s: DMA Transfer Count Register %d, dma_tcr_w = %04x & %04x\n", machine().describe_context(), Channel, data, mem_mask);
+ COMBINE_DATA(&m_dma[Channel].tcr);
+}
+
+
+template uint16_t sh7021_device::dma_chcr_r<0>();
+template uint16_t sh7021_device::dma_chcr_r<1>();
+template uint16_t sh7021_device::dma_chcr_r<2>();
+template uint16_t sh7021_device::dma_chcr_r<3>();
+
+template <int Channel>
+uint16_t sh7021_device::dma_chcr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_DMA_RD, "%s: DMA Channel Control Register %d, dma_chcr_r: %04x\n", machine().describe_context(), Channel, m_dma[Channel].chcr);
+ return m_dma[Channel].chcr;
+}
+
+template void sh7021_device::dma_chcr_w<0>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::dma_chcr_w<1>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::dma_chcr_w<2>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::dma_chcr_w<3>(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+template <int Channel>
+void sh7021_device::dma_chcr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ static const char *const ADDR_MODE_NAMES[4] =
+ {
+ "Fixed", "Increment", "Decrement", "Reserved"
+ };
+ static const char *const SOURCE_NAMES[16] =
+ {
+ "/DREQ, Dual-Address Mode",
+ "Reserved (1)",
+ "/DREQ, Memory-to-device",
+ "/DREQ, Device-to-memory",
+ "RXI0 (Serial 0 Receive), Dual-Address Mode",
+ "TXI0 (Serial 0 Transmit), Dual-Address Mode",
+ "RXI1 (Serial 1 Receive), Dual-Address Mode",
+ "TXI1 (Serial 1 Transmit), Dual-Address Mode",
+ "IMIA0 (Timer 0 Capture/Compare-Match), Dual-Address Mode",
+ "IMIA1 (Timer 1 Capture/Compare-Match), Dual-Address Mode",
+ "IMIA2 (Timer 2 Capture/Compare-Match), Dual-Address Mode",
+ "IMIA3 (Timer 3 Capture/Compare-Match), Dual-Address Mode",
+ "Auto-Request, Dual-Address Mode",
+ "Reserved (13)",
+ "Reserved (14)",
+ "Reserved (15)"
+ };
+
+ LOGMASKED(LOG_DMA_WR, "%s: DMA Channel Control Register %d, dma_chcr_w = %04x & %04x\n", machine().describe_context(), Channel, data, mem_mask);
+ LOGMASKED(LOG_DMA_WR, "%s: Dest Address Mode: %s\n", machine().describe_context(), ADDR_MODE_NAMES[data >> 14]);
+ LOGMASKED(LOG_DMA_WR, "%s: Source Address Mode: %s\n", machine().describe_context(), ADDR_MODE_NAMES[(data >> 12) & 3]);
+ LOGMASKED(LOG_DMA_WR, "%s: Resource Select: %s\n", machine().describe_context(), SOURCE_NAMES[(data >> 8) & 15]);
+ LOGMASKED(LOG_DMA_WR, "%s: Acknowledge Bit: DACK output in %s cycle\n", machine().describe_context(), BIT(data, 7) ? "write" : "read");
+ LOGMASKED(LOG_DMA_WR, "%s: Acknowledge Level Bit: DACK active %s\n", machine().describe_context(), BIT(data, 6) ? "low" : "high");
+ LOGMASKED(LOG_DMA_WR, "%s: /DREQ Detect Mode: %s\n", machine().describe_context(), BIT(data, 5) ? "Edge" : "Level");
+ LOGMASKED(LOG_DMA_WR, "%s: Transfer Mode: %s\n", machine().describe_context(), BIT(data, 4) ? "Burst Mode" : "Cycle-Steal");
+ LOGMASKED(LOG_DMA_WR, "%s: Transfer Size: %s\n", machine().describe_context(), BIT(data, 3) ? "Word" : "Byte");
+ LOGMASKED(LOG_DMA_WR, "%s: Interrupt Enable: %d\n", machine().describe_context(), BIT(data, 2));
+ LOGMASKED(LOG_DMA_WR, "%s: Transfer End Clear: %d\n", machine().describe_context(), BIT(data, 1));
+ LOGMASKED(LOG_DMA_WR, "%s: Transfer Enable: %d\n", machine().describe_context(), BIT(data, 0));
+ COMBINE_DATA(&m_dma[Channel].chcr);
+ execute_dma(Channel);
+}
+
+uint16_t sh7021_device::dmaor_r()
+{
+ if (!machine().side_effects_disabled())
+ {
+ LOGMASKED(LOG_DMA_RD, "%s: DMA Operation Register, dmaor_r: %04x\n", machine().describe_context(), m_dmaor);
+ LOGMASKED(LOG_DMA_RD, "%s: Address Error Flag: %d\n", machine().describe_context(), BIT(m_dmaor, 2));
+ LOGMASKED(LOG_DMA_RD, "%s: NMI Flag: %d\n", machine().describe_context(), BIT(m_dmaor, 1));
+ LOGMASKED(LOG_DMA_RD, "%s: DMA Master Enable: %d\n", machine().describe_context(), BIT(m_dmaor, 0));
+ }
+ return m_dmaor;
+}
+
+void sh7021_device::dmaor_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ static const char *const PRIORITY_NAMES[4] =
+ {
+ "Fixed Priority (0 -> 3 -> 2 -> 1)",
+ "Fixed Priority (1 -> 3 -> 2 -> 0)",
+ "Round-Robin Priority",
+ "External-Pin Round-Robin Priority"
+ };
+ LOGMASKED(LOG_DMA_WR, "%s: DMA Operation Register, dmaor_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ LOGMASKED(LOG_DMA_WR, "%s: Priority Mode: %s\n", machine().describe_context(), PRIORITY_NAMES[(data >> 8) & 3]);
+ LOGMASKED(LOG_DMA_WR, "%s: Address Error Flag: %d\n", machine().describe_context(), BIT(data, 2));
+ LOGMASKED(LOG_DMA_WR, "%s: NMI Flag: %d\n", machine().describe_context(), BIT(data, 1));
+ LOGMASKED(LOG_DMA_WR, "%s: DMA Master Enable: %d\n", machine().describe_context(), BIT(data, 0));
+ COMBINE_DATA(&m_dmaor);
+}
+
+void sh7021_device::execute_dma(int ch)
+{
+ const short dma_word_size[4] = { 0, +1, -1, 0 };
+ uint8_t rs = (m_dma[ch].chcr >> 8) & 0xf; /**< Resource Select bits */
+
+ // channel enable & master enable
+ if ((m_dma[ch].chcr & 1) == 0 || (m_dmaor & 1) == 0)
+ {
+ return;
+ }
+
+ uint8_t dm = (m_dma[ch].chcr >> 14) & 3; /**< Destination Address Mode bits */
+ uint8_t sm = (m_dma[ch].chcr >> 12) & 3; /**< Source Address Mode bits */
+ bool ts = (m_dma[ch].chcr & 8); /**< Transfer Size bit */
+ int src_word_size = dma_word_size[sm] * (ts ? 2 : 1);
+ int dst_word_size = dma_word_size[dm] * (ts ? 2 : 1);
+ uint32_t src_addr = m_dma[ch].sar;
+ uint32_t dst_addr = m_dma[ch].dar;
+ uint32_t count = m_dma[ch].tcr;
+
+ if (count == 0)
+ {
+ count = 0x10000;
+ }
+
+ if (!ts)
+ {
+ //printf("SH7032: DMA byte mode check\n");
+ //printf("DMA%u: S:%08x D:%08x C:%08x CTRL:%04x\n", ch, m_dma[ch].sar, m_dma[ch].dar, m_dma[ch].tcr, m_dma[ch].chcr);
+ //printf("SRC_INC: %d DST_INC: %d\n", src_word_size, dst_word_size);
+ //printf("MODE: %s\n\n", m_dma[ch].chcr & (1 << 4) ? "BURST" : "STEAL");
+ }
+
+ // Fake a a Transmit End Interrupt
+ if (rs == 5 || rs == 7)
+ {
+ int channel = (rs == 5 ? 0 : 1);
+ uint64_t clock_divider = 1 << ((m_sci[channel].smr & 3) << 1);
+ uint64_t char_length = BIT(m_sci[channel].smr, 6) ? 8 : 7;
+ uint64_t stop_bits = BIT(m_sci[channel].smr, 3) ? 2 : 1;
+ attotime transmit_time = attotime::from_ticks(clock_divider * count * (char_length + stop_bits) * (m_sci[channel].brr + 1), clock());
+ m_sci[channel].et->adjust(transmit_time);
+ LOGMASKED(LOG_DMA_WR, "Setting SCI channel %d to elapse in %d ticks (%d * %d * (%d + %d) * %d)\n", channel, clock_divider * count * (char_length + stop_bits) * (m_sci[channel].brr + 1),
+ clock_divider, count, char_length, stop_bits, m_sci[channel].brr + 1);
+ }
+
+ for (int i = 0; i < count; ++i)
+ {
+ if (ts)
+ m_program->write_word(dst_addr & m_am, m_program->read_word(src_addr & m_am));
+ else
+ m_program->write_byte(dst_addr & m_am, m_program->read_byte(src_addr & m_am));
+
+ src_addr += src_word_size;
+ dst_addr += dst_word_size;
+ }
+
+ m_dma[ch].sar = src_addr;
+ m_dma[ch].dar = dst_addr;
+
+ m_dma[ch].chcr |= 2; // Transfer ended
+
+ // TODO: IRQs
+}
+
+void sh7021_device::execute_peripherals(int peripheral_cycles)
+{
+ m_dma_cycles += peripheral_cycles;
+}
+
+// 16-Bit Integrated-Timer Pulse Unit (ITU)
+
+template TIMER_CALLBACK_MEMBER(sh7021_device::sh7021_timer_callback<0>);
+template TIMER_CALLBACK_MEMBER(sh7021_device::sh7021_timer_callback<1>);
+template TIMER_CALLBACK_MEMBER(sh7021_device::sh7021_timer_callback<2>);
+template TIMER_CALLBACK_MEMBER(sh7021_device::sh7021_timer_callback<3>);
+template TIMER_CALLBACK_MEMBER(sh7021_device::sh7021_timer_callback<4>);
+
+template<int Which>
+TIMER_CALLBACK_MEMBER(sh7021_device::sh7021_timer_callback)
+{
+ // TCNT0 and 1 are up-counters
+ //if (Which < 2)
+ {
+ //if (Which == 0)
+ //LOGMASKED(LOG_ITU_WR, "T%d %04x\n", Which, m_itu.timer[Which].tcnt);
+ m_itu.timer[Which].tcnt++;
+
+ if (m_itu.timer[Which].tcnt == 0)
+ {
+ LOGMASKED(LOG_ITU_WR, "Timer %d has overflowed, flagging OVF\n", Which);
+ m_itu.timer[Which].tsr |= 4; // OVF
+ }
+ }
+
+ if (m_itu.timer[Which].tcnt == m_itu.timer[Which].gra)
+ {
+ LOGMASKED(LOG_ITU_WR, "Timer %d count %04x matches GRA %04x, flagging IMFA\n", Which, m_itu.timer[Which].tcnt, m_itu.timer[Which].gra);
+ m_itu.timer[Which].tsr |= 1; // IMFA
+
+ // CCLR[1:0] = 01
+ if (((m_itu.timer[Which].tcr >> 5) & 3) == 1)
+ {
+ LOGMASKED(LOG_ITU_WR, "Timer %d resetting count to 0\n", Which);
+ m_itu.timer[Which].tcnt = 0;
+ }
+ }
+
+ if (m_itu.timer[Which].tcnt == m_itu.timer[Which].grb)
+ {
+ LOGMASKED(LOG_ITU_WR, "Timer %d count %04x matches GRB %04x, flagging IMFB\n", Which, m_itu.timer[Which].tcnt, m_itu.timer[Which].grb);
+ m_itu.timer[Which].tsr |= 2; // IMFB
+
+ // CCLR[1:0] = 10
+ if (((m_itu.timer[Which].tcr >> 5) & 3) == 2)
+ m_itu.timer[Which].tcnt = 0;
+ }
+
+ recalc_irq();
+ //start_timer(Which);
+}
+
+void sh7021_device::start_timer(int i)
+{
+ if (m_itu.timer[i].tcr & 4)
+ fatalerror("external clock source");
+
+ int prescale = 1 << (m_itu.timer[i].tcr & 3);
+
+// printf("Starting timer %u: TCNT:%x GR:%x TCR:%x TI:%x TICK:%f\n", i, m_itu.timer[i].tcnt, m_itu.timer[i].gra, m_itu.timer[i].tcr & 7, m_itu.timer[i].tier, (double)clock()/psc);
+// printf("%d\n", clock());
+ LOGMASKED(LOG_ITU_WR, "Starting Timer %d, prescale %d, clock %d, current count %04x\n", i, prescale, clock(), m_itu.timer[i].tcnt);
+ attotime period = attotime::from_ticks(prescale, clock());
+ m_itu.timer[i].et->adjust(period, i, period);
+}
+
+uint8_t sh7021_device::itu_tstr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: Timer Start Register, itu_tstr_r: %02x\n", machine().describe_context(), m_itu.tstr);
+ return m_itu.tstr | 0x60;
+}
+
+void sh7021_device::itu_tstr_w(uint8_t data)
+{
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Start Register, itu_tstr_w = %02x\n", machine().describe_context(), data);
+
+ // Starts timers
+ const uint8_t newly_enabled = ~m_itu.tstr & data;
+ const uint8_t newly_disabled = m_itu.tstr & ~data;
+ m_itu.tstr = data;
+
+ for (int i = 0; i < 5; ++i)
+ {
+ if (BIT(newly_disabled, i))
+ {
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Start Register, timer %d disabled\n", machine().describe_context(), i);
+ m_itu.timer[i].et->adjust(attotime::never);
+ }
+ else if (BIT(newly_enabled, i))
+ {
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Start Register, timer %d enabled\n", machine().describe_context(), i);
+ start_timer(i);
+ }
+ }
+}
+
+uint8_t sh7021_device::itu_tsnc_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: Timer Synchro Register, itu_tsnc_r: %02x\n", machine().describe_context(), m_itu.tsnc);
+ return m_itu.tsnc;
+}
+
+void sh7021_device::itu_tsnc_w(uint8_t data)
+{
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Synchro Register, itu_tsnc_w = %02x\n", machine().describe_context(), data);
+ m_itu.tsnc = data;
+}
+
+uint8_t sh7021_device::itu_tmdr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: Timer Mode Register, itu_tmdr_r: %02x\n", machine().describe_context(), m_itu.tmdr);
+ return m_itu.tmdr;
+}
+
+void sh7021_device::itu_tmdr_w(uint8_t data)
+{
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Mode Register, itu_tmdr_w = %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_ITU_WR, "%s: Channel 2 Phase Counting Mode: %d\n", machine().describe_context(), BIT(data, 6));
+ LOGMASKED(LOG_ITU_WR, "%s: Channel 2 Overflow Behavior: %d\n", machine().describe_context(), BIT(data, 5) ? "Set OVF of TSR2 on TCNT2 overflow" : "Set OVF of TSR2 on TCNT2 overflow and underflow");
+ LOGMASKED(LOG_ITU_WR, "%s: Channel 4 PWM Mode: %d\n", machine().describe_context(), BIT(data, 4));
+ LOGMASKED(LOG_ITU_WR, "%s: Channel 3 PWM Mode: %d\n", machine().describe_context(), BIT(data, 3));
+ LOGMASKED(LOG_ITU_WR, "%s: Channel 2 PWM Mode: %d\n", machine().describe_context(), BIT(data, 2));
+ LOGMASKED(LOG_ITU_WR, "%s: Channel 1 PWM Mode: %d\n", machine().describe_context(), BIT(data, 1));
+ LOGMASKED(LOG_ITU_WR, "%s: Channel 0 PWM Mode: %d\n", machine().describe_context(), BIT(data, 0));
+ m_itu.tmdr = data;
+}
+
+uint8_t sh7021_device::itu_tfcr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: Timer Function Control Register, itu_tfcr_r: %02x\n", machine().describe_context(), m_itu.tfcr);
+ return m_itu.tfcr;
+}
+
+void sh7021_device::itu_tfcr_w(uint8_t data)
+{
+ static const char *const COMBO_MODE_NAMES[4] =
+ {
+ "Channel 3 & 4 Normal (0)",
+ "Channel 3 & 4 Normal (1)",
+ "Channel 3 & 4 Together, Complementary PWM",
+ "Channel 3 & 4 Together, Reset-Synced PWM"
+ };
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Function Control Register, itu_tfcr_w = %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_ITU_WR, "%s: Combination Mode: %s\n", machine().describe_context(), COMBO_MODE_NAMES[(data >> 4) & 3]);
+ LOGMASKED(LOG_ITU_WR, "%s: Buffer Mode B4: %s\n", machine().describe_context(), BIT(data, 3) ? "GRB4 and BRB4 buffer mode for Ch.4" : "GRB4 normal for Ch.4");
+ LOGMASKED(LOG_ITU_WR, "%s: Buffer Mode A4: %s\n", machine().describe_context(), BIT(data, 2) ? "GRA4 and BRA4 buffer mode for Ch.4" : "GRA4 normal for Ch.4");
+ LOGMASKED(LOG_ITU_WR, "%s: Buffer Mode B3: %s\n", machine().describe_context(), BIT(data, 1) ? "GRB3 and BRB3 buffer mode for Ch.3" : "GRB3 normal for Ch.3");
+ LOGMASKED(LOG_ITU_WR, "%s: Buffer Mode A3: %s\n", machine().describe_context(), BIT(data, 0) ? "GRA3 and BRA3 buffer mode for Ch.3" : "GRA3 normal for Ch.3");
+ m_itu.tfcr = data;
+}
+
+uint8_t sh7021_device::itu_tocr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: Timer Output Control Register, itu_tfcr_r: %02x\n", machine().describe_context(), m_itu.tocr);
+ return m_itu.tocr | 0x7c;
+}
+
+void sh7021_device::itu_tocr_w(uint8_t data)
+{
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Output Control Register, itu_tocr_w = %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_ITU_WR, "%s: Output Level Select Ch.4: %s\n", machine().describe_context(), BIT(data, 1) ? "Direct" : "Inverted");
+ LOGMASKED(LOG_ITU_WR, "%s: Output Level Select Ch.3: %s\n", machine().describe_context(), BIT(data, 0) ? "Direct" : "Inverted");
+ m_itu.tocr = data;
+}
+
+template uint8_t sh7021_device::itu_tcr_r<0>();
+template uint8_t sh7021_device::itu_tcr_r<1>();
+template uint8_t sh7021_device::itu_tcr_r<2>();
+template uint8_t sh7021_device::itu_tcr_r<3>();
+template uint8_t sh7021_device::itu_tcr_r<4>();
+
+template <int Channel>
+uint8_t sh7021_device::itu_tcr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: Timer Control Register %d, itu_tcr_r: %02x\n", machine().describe_context(), Channel, m_itu.timer[Channel].tcr);
+ return m_itu.timer[Channel].tcr;
+}
+
+template void sh7021_device::itu_tcr_w<0>(uint8_t data);
+template void sh7021_device::itu_tcr_w<1>(uint8_t data);
+template void sh7021_device::itu_tcr_w<2>(uint8_t data);
+template void sh7021_device::itu_tcr_w<3>(uint8_t data);
+template void sh7021_device::itu_tcr_w<4>(uint8_t data);
+
+template <int Channel>
+void sh7021_device::itu_tcr_w(uint8_t data)
+{
+ static const char *const CCLR_NAMES[4] =
+ {
+ "Don't clear TCNT", "Clear TCNT on GRA match or input capture", "Clear TCNT on GRB match or input capture", "Synced clear"
+ };
+ static const char *const CKEG_NAMES[4] =
+ {
+ "Count rising edges", "Count falling edges", "Count both edges (2)", "Count both edges (3)"
+ };
+ static const char *const TPSC_NAMES[8] =
+ {
+ "/1", "/2", "/4", "/8", "External clock A", "External clock B", "External clock C", "External clock D"
+ };
+
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Control Register %d, itu_tcr_w = %02x\n", machine().describe_context(), Channel, data);
+ LOGMASKED(LOG_ITU_WR, "%s: Counter Clear Mode: %s\n", machine().describe_context(), CCLR_NAMES[(data >> 5) & 3]);
+ LOGMASKED(LOG_ITU_WR, "%s: External-Clock Edge Mode: %s\n", machine().describe_context(), CKEG_NAMES[(data >> 3) & 3]);
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Prescaler Mode: %s\n", machine().describe_context(), TPSC_NAMES[data & 7]);
+ m_itu.timer[Channel].tcr = data;
+}
+
+template uint8_t sh7021_device::itu_tior_r<0>();
+template uint8_t sh7021_device::itu_tior_r<1>();
+template uint8_t sh7021_device::itu_tior_r<2>();
+template uint8_t sh7021_device::itu_tior_r<3>();
+template uint8_t sh7021_device::itu_tior_r<4>();
+
+template <int Channel>
+uint8_t sh7021_device::itu_tior_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: Timer I/O Control Register %d, itu_tior_r: %02x\n", machine().describe_context(), Channel, m_itu.timer[Channel].tior);
+ return m_itu.timer[Channel].tior;
+}
+
+template void sh7021_device::itu_tior_w<0>(uint8_t data);
+template void sh7021_device::itu_tior_w<1>(uint8_t data);
+template void sh7021_device::itu_tior_w<2>(uint8_t data);
+template void sh7021_device::itu_tior_w<3>(uint8_t data);
+template void sh7021_device::itu_tior_w<4>(uint8_t data);
+
+template <int Channel>
+void sh7021_device::itu_tior_w(uint8_t data)
+{
+ static const char *const IOB_NAMES[8] =
+ {
+ "Output compare GRB / Compare Match",
+ "Output compare GRB / 0 output at GRB match",
+ "Output compare GRB / 1 output at GRB match",
+ "Output compare GRB / Toggle at GRB match",
+ "Input capture GRB / Capture rising edge",
+ "Input capture GRB / Capture falling edge",
+ "Input capture GRB / Capture both edges (6)",
+ "Input capture GRB / Capture both edges (7)",
+ };
+ static const char *const IOA_NAMES[8] =
+ {
+ "Output compare GRA / Compare Match",
+ "Output compare GRA / 0 output at GRA match",
+ "Output compare GRA / 1 output at GRA match",
+ "Output compare GRA / Toggle at GRA match",
+ "Input capture GRA / Capture rising edge",
+ "Input capture GRA / Capture falling edge",
+ "Input capture GRA / Capture both edges (6)",
+ "Input capture GRA / Capture both edges (7)",
+ };
+
+ LOGMASKED(LOG_ITU_WR, "%s: Timer I/O Control Register %d, itu_tior_w = %02x\n", machine().describe_context(), Channel, data);
+ LOGMASKED(LOG_ITU_WR, "%s: GRB Function: %s\n", machine().describe_context(), IOB_NAMES[(data >> 4) & 7]);
+ LOGMASKED(LOG_ITU_WR, "%s: GRA Function: %s\n", machine().describe_context(), IOA_NAMES[data & 7]);
+ m_itu.timer[Channel].tior = data;
+}
+
+template uint8_t sh7021_device::itu_tier_r<0>();
+template uint8_t sh7021_device::itu_tier_r<1>();
+template uint8_t sh7021_device::itu_tier_r<2>();
+template uint8_t sh7021_device::itu_tier_r<3>();
+template uint8_t sh7021_device::itu_tier_r<4>();
+
+template <int Channel>
+uint8_t sh7021_device::itu_tier_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: Timer Interrupt Enable Register %d, itu_tier_r: %02x\n", machine().describe_context(), Channel, m_itu.timer[Channel].tier);
+ return m_itu.timer[Channel].tier;
+}
+
+template void sh7021_device::itu_tier_w<0>(uint8_t data);
+template void sh7021_device::itu_tier_w<1>(uint8_t data);
+template void sh7021_device::itu_tier_w<2>(uint8_t data);
+template void sh7021_device::itu_tier_w<3>(uint8_t data);
+template void sh7021_device::itu_tier_w<4>(uint8_t data);
+
+template <int Channel>
+void sh7021_device::itu_tier_w(uint8_t data)
+{
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Interrupt Enable Register %d, itu_tier_w = %02x\n", machine().describe_context(), Channel, data);
+ LOGMASKED(LOG_ITU_WR, "%s: Enable Overflow Interrupts: %d\n", machine().describe_context(), BIT(data, 2));
+ LOGMASKED(LOG_ITU_WR, "%s: Enable Capture/Compare B Interrupts: %d\n", machine().describe_context(), BIT(data, 1));
+ LOGMASKED(LOG_ITU_WR, "%s: Enable Capture/Compare A Interrupts: %d\n", machine().describe_context(), BIT(data, 0));
+ m_itu.timer[Channel].tier = data;
+}
+
+template uint8_t sh7021_device::itu_tsr_r<0>();
+template uint8_t sh7021_device::itu_tsr_r<1>();
+template uint8_t sh7021_device::itu_tsr_r<2>();
+template uint8_t sh7021_device::itu_tsr_r<3>();
+template uint8_t sh7021_device::itu_tsr_r<4>();
+
+template <int Channel>
+uint8_t sh7021_device::itu_tsr_r()
+{
+ if (!machine().side_effects_disabled())
+ {
+ LOGMASKED(LOG_ITU_RD, "%s: Timer Status Register %d, itu_tsr_r: %02x\n", machine().describe_context(), Channel, m_itu.timer[Channel].tsr);
+ LOGMASKED(LOG_ITU_RD, "%s: Overflow Flag: %d\n", machine().describe_context(), BIT(m_itu.timer[Channel].tsr, 2));
+ LOGMASKED(LOG_ITU_RD, "%s: Compare/Capture B Flag: %d\n", machine().describe_context(), BIT(m_itu.timer[Channel].tsr, 1));
+ LOGMASKED(LOG_ITU_RD, "%s: Compare/Capture A Flag: %d\n", machine().describe_context(), BIT(m_itu.timer[Channel].tsr, 0));
+ }
+ return m_itu.timer[Channel].tsr;
+}
+
+template void sh7021_device::itu_tsr_w<0>(uint8_t data);
+template void sh7021_device::itu_tsr_w<1>(uint8_t data);
+template void sh7021_device::itu_tsr_w<2>(uint8_t data);
+template void sh7021_device::itu_tsr_w<3>(uint8_t data);
+template void sh7021_device::itu_tsr_w<4>(uint8_t data);
+
+template <int Channel>
+void sh7021_device::itu_tsr_w(uint8_t data)
+{
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Status Register %d, itu_tsr_w = %02x\n", machine().describe_context(), Channel, m_itu.timer[Channel].tsr);
+ if (BIT(m_itu.timer[Channel].tsr, 2) && !BIT(data, 2))
+ LOGMASKED(LOG_ITU_WR, "%s: Overflow Clear\n", machine().describe_context());
+ if (BIT(m_itu.timer[Channel].tsr, 1) && !BIT(data, 1))
+ LOGMASKED(LOG_ITU_WR, "%s: Compare/Capture B Clear\n", machine().describe_context());
+ if (BIT(m_itu.timer[Channel].tsr, 0) && !BIT(data, 0))
+ LOGMASKED(LOG_ITU_WR, "%s: Compare/Capture A Clear\n", machine().describe_context());
+ m_itu.timer[Channel].tsr = data;
+}
+
+template uint16_t sh7021_device::itu_tcnt_r<0>();
+template uint16_t sh7021_device::itu_tcnt_r<1>();
+template uint16_t sh7021_device::itu_tcnt_r<2>();
+template uint16_t sh7021_device::itu_tcnt_r<3>();
+template uint16_t sh7021_device::itu_tcnt_r<4>();
+
+template <int Channel>
+uint16_t sh7021_device::itu_tcnt_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: Timer Counter %d, itu_tcnt_r: %04x\n", machine().describe_context(), Channel, m_itu.timer[Channel].tcnt);
+ return m_itu.timer[Channel].tcnt;
+}
+
+template void sh7021_device::itu_tcnt_w<0>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_tcnt_w<1>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_tcnt_w<2>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_tcnt_w<3>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_tcnt_w<4>(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+template <int Channel>
+void sh7021_device::itu_tcnt_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_ITU_WR, "%s: Timer Counter %d, itu_tcnt_w = %04x & %04x\n", machine().describe_context(), Channel, data, mem_mask);
+ COMBINE_DATA(&m_itu.timer[Channel].tcnt);
+}
+
+template uint16_t sh7021_device::itu_gra_r<0>();
+template uint16_t sh7021_device::itu_gra_r<1>();
+template uint16_t sh7021_device::itu_gra_r<2>();
+template uint16_t sh7021_device::itu_gra_r<3>();
+template uint16_t sh7021_device::itu_gra_r<4>();
+
+template <int Channel>
+uint16_t sh7021_device::itu_gra_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: General Register A %d, itu_gra_r: %04x\n", machine().describe_context(), Channel, m_itu.timer[Channel].gra);
+ return m_itu.timer[Channel].gra;
+}
+
+template void sh7021_device::itu_gra_w<0>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_gra_w<1>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_gra_w<2>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_gra_w<3>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_gra_w<4>(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+template <int Channel>
+void sh7021_device::itu_gra_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_ITU_WR, "%s: General Register A %d, itu_gra_w = %04x\n", machine().describe_context(), Channel, data);
+ COMBINE_DATA(&m_itu.timer[Channel].gra);
+}
+
+template uint16_t sh7021_device::itu_grb_r<0>();
+template uint16_t sh7021_device::itu_grb_r<1>();
+template uint16_t sh7021_device::itu_grb_r<2>();
+template uint16_t sh7021_device::itu_grb_r<3>();
+template uint16_t sh7021_device::itu_grb_r<4>();
+
+template <int Channel>
+uint16_t sh7021_device::itu_grb_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: General Register B %d, itu_grb_r: %04x\n", machine().describe_context(), Channel, m_itu.timer[Channel].grb);
+ return m_itu.timer[Channel].grb;
+}
+
+template void sh7021_device::itu_grb_w<0>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_grb_w<1>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_grb_w<2>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_grb_w<3>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_grb_w<4>(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+template <int Channel>
+void sh7021_device::itu_grb_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_ITU_WR, "%s: General Register B %d, itu_grb_w = %04x\n", machine().describe_context(), Channel, data);
+ COMBINE_DATA(&m_itu.timer[Channel].grb);
+}
+
+template uint16_t sh7021_device::itu_bra_r<3>();
+template uint16_t sh7021_device::itu_bra_r<4>();
+
+template <int Channel>
+uint16_t sh7021_device::itu_bra_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: Buffer Register A %d, itu_bra_r: %04x\n", machine().describe_context(), Channel, m_itu.timer[Channel].bra);
+ return m_itu.timer[Channel].bra;
+}
+
+template void sh7021_device::itu_bra_w<3>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_bra_w<4>(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+template <int Channel>
+void sh7021_device::itu_bra_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_ITU_WR, "%s: Buffer Register A %d, itu_bra_w = %04x\n", machine().describe_context(), Channel, data);
+ COMBINE_DATA(&m_itu.timer[Channel].bra);
+}
+
+template uint16_t sh7021_device::itu_brb_r<3>();
+template uint16_t sh7021_device::itu_brb_r<4>();
+
+template <int Channel>
+uint16_t sh7021_device::itu_brb_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_ITU_RD, "%s: Buffer Register B %d, itu_brb_r: %04x\n", machine().describe_context(), Channel, m_itu.timer[Channel].brb);
+ return m_itu.timer[Channel].brb;
+}
+
+template void sh7021_device::itu_brb_w<3>(offs_t offset, uint16_t data, uint16_t mem_mask);
+template void sh7021_device::itu_brb_w<4>(offs_t offset, uint16_t data, uint16_t mem_mask);
+
+template <int Channel>
+void sh7021_device::itu_brb_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_ITU_WR, "%s: Buffer Register B %d, itu_brb_w = %04x\n", machine().describe_context(), Channel, data);
+ COMBINE_DATA(&m_itu.timer[Channel].brb);
+}
+
+
+// Programmable Timing Pattern Controller (TPC)
+
+uint8_t sh7021_device::tpc_tpmr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_TPC_RD, "%s: TPC Output Mode Register, tpc_tpmr_r: %02x\n", machine().describe_context(), m_tpc.tpmr);
+ return m_tpc.tpmr;
+}
+
+void sh7021_device::tpc_tpmr_w(uint8_t data)
+{
+ LOGMASKED(LOG_TPC_WR, "%s: TPC Output Mode Register, tpc_tpmr_w = %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_TPC_WR, "%s: TPC Output Group 3 Operation: %s\n", machine().describe_context(), BIT(data, 3) ? "Non-Overlap Mode (1/0 from A/B)" : "Normal (Compare-Match A)");
+ LOGMASKED(LOG_TPC_WR, "%s: TPC Output Group 2 Operation: %s\n", machine().describe_context(), BIT(data, 2) ? "Non-Overlap Mode (1/0 from A/B)" : "Normal (Compare-Match A)");
+ LOGMASKED(LOG_TPC_WR, "%s: TPC Output Group 1 Operation: %s\n", machine().describe_context(), BIT(data, 1) ? "Non-Overlap Mode (1/0 from A/B)" : "Normal (Compare-Match A)");
+ LOGMASKED(LOG_TPC_WR, "%s: TPC Output Group 0 Operation: %s\n", machine().describe_context(), BIT(data, 0) ? "Non-Overlap Mode (1/0 from A/B)" : "Normal (Compare-Match A)");
+ m_tpc.tpmr = data;
+}
+
+uint8_t sh7021_device::tpc_tpcr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_TPC_RD, "%s: TPC Output Control Register, tpc_tpcr_r: %02x\n", machine().describe_context(), m_tpc.tpcr);
+ return m_tpc.tpcr;
+}
+
+void sh7021_device::tpc_tpcr_w(uint8_t data)
+{
+ LOGMASKED(LOG_TPC_WR, "%s: TPC Output Control Register, tpc_tpcr_w = %02x\n", machine().describe_context(), data);
+ LOGMASKED(LOG_TPC_WR, "%s: TPC Output Group 3 output triggered by compare-match in ITU channel %d\n", machine().describe_context(), (data >> 6) & 3);
+ LOGMASKED(LOG_TPC_WR, "%s: TPC Output Group 2 output triggered by compare-match in ITU channel %d\n", machine().describe_context(), (data >> 4) & 3);
+ LOGMASKED(LOG_TPC_WR, "%s: TPC Output Group 1 output triggered by compare-match in ITU channel %d\n", machine().describe_context(), (data >> 2) & 3);
+ LOGMASKED(LOG_TPC_WR, "%s: TPC Output Group 0 output triggered by compare-match in ITU channel %d\n", machine().describe_context(), data & 3);
+ m_tpc.tpcr = data;
+}
+
+uint8_t sh7021_device::tpc_ndera_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_TPC_RD, "%s: Next Data Enable Register A, tpc_ndera_r (TP7-0): %02x\n", machine().describe_context(), m_tpc.ndera);
+ return m_tpc.ndera;
+}
+
+void sh7021_device::tpc_ndera_w(uint8_t data)
+{
+ LOGMASKED(LOG_TPC_WR, "%s: Next Data Enable Register A, tpc_ndera_w (TP7-0) = %02x\n", machine().describe_context(), data);
+ m_tpc.ndera = data;
+}
+
+uint8_t sh7021_device::tpc_nderb_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_TPC_RD, "%s: Next Data Enable Register B, tpc_nderb_r (TP15-8): %02x\n", machine().describe_context(), m_tpc.nderb);
+ return m_tpc.nderb;
+}
+
+void sh7021_device::tpc_nderb_w(uint8_t data)
+{
+ LOGMASKED(LOG_TPC_WR, "%s: Next Data Enable Register B, tpc_nderb_w (TP15-8) = %02x\n", machine().describe_context(), data);
+ m_tpc.nderb = data;
+}
+
+uint8_t sh7021_device::tpc_ndra_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_TPC_RD, "%s: Next Data Register A, tpc_ndra_r: %02x\n", machine().describe_context(), 0);//m_tpc.ndra);
+ return 0;//m_tpc.ndra;
+}
+
+void sh7021_device::tpc_ndra_w(uint8_t data)
+{
+ LOGMASKED(LOG_TPC_WR, "%s: Next Data Register A, tpc_ndra_w = %02x\n", machine().describe_context(), data);
+}
+
+uint8_t sh7021_device::tpc_ndra_alt_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_TPC_RD, "%s: Next Data Register A (alt. address), tpc_ndra_alt_r: %02x\n", machine().describe_context(), 0);//m_tpc.ndra);
+ return 0;//m_tpc.ndra;
+}
+
+void sh7021_device::tpc_ndra_alt_w(uint8_t data)
+{
+ LOGMASKED(LOG_TPC_WR, "%s: Next Data Register A (alt. address), tpc_ndra_alt_w = %02x\n", machine().describe_context(), data);
+}
+
+uint8_t sh7021_device::tpc_ndrb_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_TPC_RD, "%s: Next Data Register B, tpc_ndrb_r: %02x\n", machine().describe_context(), 0);//m_tpc.ndrb);
+ return 0;//m_tpc.ndrb;
+}
+
+void sh7021_device::tpc_ndrb_w(uint8_t data)
+{
+ LOGMASKED(LOG_TPC_WR, "%s: Next Data Register B, tpc_ndrb_w = %02x\n", machine().describe_context(), data);
+}
+
+uint8_t sh7021_device::tpc_ndrb_alt_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_TPC_RD, "%s: Next Data Register B (alt. address), tpc_ndrb_alt_r: %02x\n", machine().describe_context(), 0);//m_tpc.ndrb);
+ return 0;//m_tpc.ndrb;
+}
+
+void sh7021_device::tpc_ndrb_alt_w(uint8_t data)
+{
+ LOGMASKED(LOG_TPC_WR, "%s: Next Data Register B (alt. address), tpc_ndrb_alt_w = %02x\n", machine().describe_context(), data);
+}
+
+
+// Watchdog Timer (WDT)
+
+uint8_t sh7021_device::wdt_tcsr_r()
+{
+ return m_wdt.tcsr;
+}
+
+void sh7021_device::wdt_tcsr_w(uint8_t data)
+{
+ m_wdt.tcsr = data;
+}
+
+uint8_t sh7021_device::wdt_tcnt_r()
+{
+ return 0;
+}
+
+void sh7021_device::wdt_tcnt_w(uint8_t data)
+{
+}
+
+uint8_t sh7021_device::wdt_rstcsr_r()
+{
+ return 0;
+}
+
+void sh7021_device::wdt_rstcsr_w(uint8_t data)
+{
+
+}
+
+
+// Serial Communication Interface (SCI)
+
+template TIMER_CALLBACK_MEMBER(sh7021_device::sh7021_sci_callback<0>);
+template TIMER_CALLBACK_MEMBER(sh7021_device::sh7021_sci_callback<1>);
+
+template<int Which>
+TIMER_CALLBACK_MEMBER(sh7021_device::sh7021_sci_callback)
+{
+ LOGMASKED(LOG_DMA_WR, "Setting SCI interrupt on channel %d\n", Which);
+ m_sci[Which].ssr |= (1 << 7) | (1 << 2);
+ recalc_irq();
+}
+
+template uint8_t sh7021_device::sci_smr_r<0>();
+template uint8_t sh7021_device::sci_smr_r<1>();
+
+template <int Channel>
+uint8_t sh7021_device::sci_smr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_SCI_RD, "%s: Serial Mode Register %d, sci_smr_r: %02x\n", machine().describe_context(), Channel, m_sci[Channel].smr);
+ return m_sci[Channel].smr;
+}
+
+template void sh7021_device::sci_smr_w<0>(uint8_t data);
+template void sh7021_device::sci_smr_w<1>(uint8_t data);
+
+template <int Channel>
+void sh7021_device::sci_smr_w(uint8_t data)
+{
+ LOGMASKED(LOG_SCI_WR, "%s: Serial Mode Register %d, sci_smr_w = %02x\n", machine().describe_context(), Channel, data);
+ LOGMASKED(LOG_SCI_WR, "%s: Communication Mode: %s\n", machine().describe_context(), BIT(data, 7) ? "Clocked synchronous" : "Asynchronous");
+ LOGMASKED(LOG_SCI_WR, "%s: Character Length: %d\n", machine().describe_context(), BIT(data, 6) ? 7 : 8);
+ LOGMASKED(LOG_SCI_WR, "%s: Parity Enable: %d\n", machine().describe_context(), BIT(data, 5));
+ LOGMASKED(LOG_SCI_WR, "%s: Parity Mode: %s\n", machine().describe_context(), BIT(data, 4) ? "Odd" : "Even");
+ LOGMASKED(LOG_SCI_WR, "%s: Stop Bits: %d\n", machine().describe_context(), BIT(data, 3) ? 2 : 1);
+ LOGMASKED(LOG_SCI_WR, "%s: Multiprocessor Mode: %d\n", machine().describe_context(), BIT(data, 2));
+ LOGMASKED(LOG_SCI_WR, "%s: Clock Divider: %d\n", machine().describe_context(), 1 << ((data & 3) * 2));
+ m_sci[Channel].smr = data;
+}
+
+template uint8_t sh7021_device::sci_brr_r<0>();
+template uint8_t sh7021_device::sci_brr_r<1>();
+
+template <int Channel>
+uint8_t sh7021_device::sci_brr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_SCI_RD, "%s: Bit Rate Register %d, sci_brr_r: %02x\n", machine().describe_context(), Channel, m_sci[Channel].brr);
+ return m_sci[Channel].brr;
+}
+
+template void sh7021_device::sci_brr_w<0>(uint8_t data);
+template void sh7021_device::sci_brr_w<1>(uint8_t data);
+
+template <int Channel>
+void sh7021_device::sci_brr_w(uint8_t data)
+{
+ LOGMASKED(LOG_SCI_WR, "%s: Bit Rate Register %d, sci_brr_w = %02x\n", machine().describe_context(), Channel, data);
+ m_sci[Channel].brr = data;
+}
+
+template uint8_t sh7021_device::sci_scr_r<0>();
+template uint8_t sh7021_device::sci_scr_r<1>();
+
+template <int Channel>
+uint8_t sh7021_device::sci_scr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_SCI_RD, "%s: Serial Control Register %d, sci_scr_r: %02x\n", machine().describe_context(), Channel, m_sci[Channel].scr);
+ return m_sci[Channel].scr;
+}
+
+template void sh7021_device::sci_scr_w<0>(uint8_t data);
+template void sh7021_device::sci_scr_w<1>(uint8_t data);
+
+template <int Channel>
+void sh7021_device::sci_scr_w(uint8_t data)
+{
+ LOGMASKED(LOG_SCI_WR, "%s: Serial Control Register %d, sci_scr_w = %02x\n", machine().describe_context(), Channel, data);
+ LOGMASKED(LOG_SCI_WR, "%s: Transmit-Empty Interrupt Enable: %d\n", machine().describe_context(), BIT(data, 7));
+ LOGMASKED(LOG_SCI_WR, "%s: Receive-Full Interrupt Enable: %d\n", machine().describe_context(), BIT(data, 6));
+ LOGMASKED(LOG_SCI_WR, "%s: Transmit Enable: %d\n", machine().describe_context(), BIT(data, 5));
+ LOGMASKED(LOG_SCI_WR, "%s: Receive Enable: %d\n", machine().describe_context(), BIT(data, 4));
+ LOGMASKED(LOG_SCI_WR, "%s: Multiprocessor Interrupt Enable: %d\n", machine().describe_context(), BIT(data, 3));
+ LOGMASKED(LOG_SCI_WR, "%s: Transmit-End Interrupt Enable: %d\n", machine().describe_context(), BIT(data, 2));
+ LOGMASKED(LOG_SCI_WR, "%s: Clock Enable Mode: %d%d\n", machine().describe_context(), BIT(data, 1), BIT(data, 0));
+ m_sci[Channel].scr = data;
+}
+
+template uint8_t sh7021_device::sci_tdr_r<0>();
+template uint8_t sh7021_device::sci_tdr_r<1>();
+
+template <int Channel>
+uint8_t sh7021_device::sci_tdr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_SCI_RD, "%s: Transmit Data Register %d, sci_tdr_r: %02x\n", machine().describe_context(), Channel, m_sci[Channel].tdr);
+ return m_sci[Channel].tdr;
+}
+
+template void sh7021_device::sci_tdr_w<0>(uint8_t data);
+template void sh7021_device::sci_tdr_w<1>(uint8_t data);
+
+template <int Channel>
+void sh7021_device::sci_tdr_w(uint8_t data)
+{
+ LOGMASKED(LOG_SCI_WR, "%s: Transmit Data Register %d, sci_tdr_w = %02x\n", machine().describe_context(), Channel, data);
+ m_sci[Channel].tdr = data;
+}
+
+template uint8_t sh7021_device::sci_ssr_r<0>();
+template uint8_t sh7021_device::sci_ssr_r<1>();
+
+template <int Channel>
+uint8_t sh7021_device::sci_ssr_r()
+{
+ if (!machine().side_effects_disabled())
+ {
+ LOGMASKED(LOG_SCI_RD, "%s: Serial Status Register %d, sci_ssr_r: %02x\n", machine().describe_context(), Channel, m_sci[Channel].ssr);
+ LOGMASKED(LOG_SCI_RD, "%s: Transmit Empty Flag: %d\n", machine().describe_context(), Channel, BIT(m_sci[Channel].ssr, 7));
+ LOGMASKED(LOG_SCI_RD, "%s: Receiver Full Flag: %d\n", machine().describe_context(), Channel, BIT(m_sci[Channel].ssr, 6));
+ LOGMASKED(LOG_SCI_RD, "%s: Overrun Error Flag: %d\n", machine().describe_context(), Channel, BIT(m_sci[Channel].ssr, 5));
+ LOGMASKED(LOG_SCI_RD, "%s: Framing Error Flag: %d\n", machine().describe_context(), Channel, BIT(m_sci[Channel].ssr, 4));
+ LOGMASKED(LOG_SCI_RD, "%s: Parity Error Flag: %d\n", machine().describe_context(), Channel, BIT(m_sci[Channel].ssr, 3));
+ LOGMASKED(LOG_SCI_RD, "%s: Transmit End Flag: %d\n", machine().describe_context(), Channel, BIT(m_sci[Channel].ssr, 2));
+ LOGMASKED(LOG_SCI_RD, "%s: Multiprocessor Bit Flag: %d\n", machine().describe_context(), Channel, BIT(m_sci[Channel].ssr, 1));
+ LOGMASKED(LOG_SCI_RD, "%s: Multiprocessor Bit Transfer Flag: %d\n", machine().describe_context(), Channel, BIT(m_sci[Channel].ssr, 0));
+
+ m_sci[Channel].ssr_read |= m_sci[Channel].ssr & 0xf8;
+ }
+
+ return (m_sci[Channel].ssr & 0xf9) | 0x04;
+}
+
+template void sh7021_device::sci_ssr_w<0>(uint8_t data);
+template void sh7021_device::sci_ssr_w<1>(uint8_t data);
+
+template <int Channel>
+void sh7021_device::sci_ssr_w(uint8_t data)
+{
+ LOGMASKED(LOG_SCI_WR, "%s: Serial Status Register %d, sci_ssr_w = %02x\n", machine().describe_context(), Channel, data);
+ if (!BIT(data, 7) && BIT(m_sci[Channel].ssr, 7) && BIT(m_sci[Channel].ssr_read, 7))
+ {
+ // Clear TDR-Empty Flag and Transmit End Flag
+ m_sci[Channel].ssr_read &= ~(1 << 7);
+ m_sci[Channel].ssr &= ~(1 << 7);
+ m_sci[Channel].ssr &= ~(1 << 2);
+ }
+
+ if (!BIT(data, 6) && BIT(m_sci[Channel].ssr, 6) && BIT(m_sci[Channel].ssr_read, 6))
+ {
+ // Clear RDR-Full Flag
+ m_sci[Channel].ssr_read &= ~(1 << 6);
+ m_sci[Channel].ssr &= ~(1 << 6);
+ }
+
+ if (!BIT(data, 5) && BIT(m_sci[Channel].ssr, 5) && BIT(m_sci[Channel].ssr_read, 5))
+ {
+ // Clear Overrun Error Flag
+ m_sci[Channel].ssr_read &= ~(1 << 5);
+ m_sci[Channel].ssr &= ~(1 << 5);
+ }
+
+ if (!BIT(data, 4) && BIT(m_sci[Channel].ssr, 4) && BIT(m_sci[Channel].ssr_read, 4))
+ {
+ // Clear Framing Error Flag
+ m_sci[Channel].ssr_read &= ~(1 << 4);
+ m_sci[Channel].ssr &= ~(1 << 4);
+ }
+
+ if (!BIT(data, 3) && BIT(m_sci[Channel].ssr, 3) && BIT(m_sci[Channel].ssr_read, 3))
+ {
+ // Clear Parity Error Flag
+ m_sci[Channel].ssr_read &= ~(1 << 3);
+ m_sci[Channel].ssr &= ~(1 << 3);
+ }
+
+ m_sci[Channel].ssr &= 0xfe;
+ m_sci[Channel].ssr |= data & 1;
+}
+
+template uint8_t sh7021_device::sci_rdr_r<0>();
+template uint8_t sh7021_device::sci_rdr_r<1>();
+
+template <int Channel>
+uint8_t sh7021_device::sci_rdr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_SCI_RD, "%s: Receive Data Register %d, sci_rdr_r: %02x\n", machine().describe_context(), Channel, m_sci[Channel].rdr);
+ return m_sci[Channel].rdr;
+}
+
+
+// Pin Function Controller (PFC)
+
+void sh7021_device::write_padr(uint16_t data)
+{
+ LOGMASKED(LOG_PFC_WR, "%s: Port A Input write: write_padr: %04x\n", machine().describe_context(), data);
+ m_pfc.padr_in = data;
+}
+
+void sh7021_device::write_pbdr(uint16_t data)
+{
+ LOGMASKED(LOG_PFC_WR, "%s: Port B Input write: write_pbdr: %04x\n", machine().describe_context(), data);
+ m_pfc.pbdr_in = data;
+}
+
+template void sh7021_device::write_padr_bit< 0>(int state);
+template void sh7021_device::write_padr_bit< 1>(int state);
+template void sh7021_device::write_padr_bit< 2>(int state);
+template void sh7021_device::write_padr_bit< 3>(int state);
+template void sh7021_device::write_padr_bit< 4>(int state);
+template void sh7021_device::write_padr_bit< 5>(int state);
+template void sh7021_device::write_padr_bit< 6>(int state);
+template void sh7021_device::write_padr_bit< 7>(int state);
+template void sh7021_device::write_padr_bit< 8>(int state);
+template void sh7021_device::write_padr_bit< 9>(int state);
+template void sh7021_device::write_padr_bit<10>(int state);
+template void sh7021_device::write_padr_bit<11>(int state);
+template void sh7021_device::write_padr_bit<12>(int state);
+template void sh7021_device::write_padr_bit<13>(int state);
+template void sh7021_device::write_padr_bit<14>(int state);
+template void sh7021_device::write_padr_bit<15>(int state);
+
+template <int Line>
+void sh7021_device::write_padr_bit(int state)
+{
+ LOGMASKED(LOG_PFC_WR, "%s: Port A Bit %d Input write: write_padr_bit: %d\n", machine().describe_context(), Line, state);
+ m_pfc.padr_in = (m_pfc.padr_in & ~(1 << Line)) | (state << Line);
+}
+
+template void sh7021_device::write_pbdr_bit< 0>(int state);
+template void sh7021_device::write_pbdr_bit< 1>(int state);
+template void sh7021_device::write_pbdr_bit< 2>(int state);
+template void sh7021_device::write_pbdr_bit< 3>(int state);
+template void sh7021_device::write_pbdr_bit< 4>(int state);
+template void sh7021_device::write_pbdr_bit< 5>(int state);
+template void sh7021_device::write_pbdr_bit< 6>(int state);
+template void sh7021_device::write_pbdr_bit< 7>(int state);
+template void sh7021_device::write_pbdr_bit< 8>(int state);
+template void sh7021_device::write_pbdr_bit< 9>(int state);
+template void sh7021_device::write_pbdr_bit<10>(int state);
+template void sh7021_device::write_pbdr_bit<11>(int state);
+template void sh7021_device::write_pbdr_bit<12>(int state);
+template void sh7021_device::write_pbdr_bit<13>(int state);
+template void sh7021_device::write_pbdr_bit<14>(int state);
+template void sh7021_device::write_pbdr_bit<15>(int state);
+
+template <int Line>
+void sh7021_device::write_pbdr_bit(int state)
+{
+ LOGMASKED(LOG_PFC_WR, "%s: Port B Bit %d Input write: write_pbdr_bit: %d\n", machine().describe_context(), Line, state);
+ m_pfc.pbdr_in = (m_pfc.pbdr_in & ~(1 << Line)) | (state << Line);
+}
+
+uint16_t sh7021_device::pfc_paior_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PFC_RD, "%s: Port A I/O (Direction) Register, pfc_paior_r: %04x\n", machine().describe_context(), m_pfc.paior);
+ return m_pfc.paior;
+}
+
+void sh7021_device::pfc_paior_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_PFC_WR, "%s: Port A I/O (Direction) Register, pfc_paior_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_pfc.paior);
+}
+
+uint16_t sh7021_device::pfc_pacr1_r()
+{
+ static constexpr uint16_t PACR1_R_MASK = 0x0002;
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PFC_RD, "%s: Port A Control Register 1, pfc_pacr1_r: %04x\n", machine().describe_context(), m_pfc.pacr1);
+ return m_pfc.pacr1 | PACR1_R_MASK;
+}
+
+void sh7021_device::pfc_pacr1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ static constexpr uint16_t PACR1_W_MASK = 0xfffd;
+ LOGMASKED(LOG_PFC_WR, "%s: Port A Control Register 1, pfc_pacr1_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_pfc.pacr1);
+ const uint16_t pacr1_masked = m_pfc.pacr1 & PACR1_W_MASK;
+ for (int i = 0; i < 8; i++)
+ {
+ int bit = i << 1;
+ m_pfc.pafunc[8 + i] = (pacr1_masked >> bit) & 3;
+ }
+}
+
+uint16_t sh7021_device::pfc_pacr2_r()
+{
+ static constexpr uint16_t PACR2_R_MASK = 0xaa00;
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PFC_RD, "%s: Port A Control Register 2, pfc_pacr2_r: %04x\n", machine().describe_context(), m_pfc.pacr2);
+ return m_pfc.pacr2 | PACR2_R_MASK;
+}
+
+void sh7021_device::pfc_pacr2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ static constexpr uint16_t PACR2_W_MASK = 0x55ff;
+ LOGMASKED(LOG_PFC_WR, "%s: Port A Control Register 2, pfc_pacr2_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_pfc.pacr2);
+ const uint16_t pacr2_masked = m_pfc.pacr2 & PACR2_W_MASK;
+ for (int i = 0; i < 8; i++)
+ {
+ int bit = i << 1;
+ m_pfc.pafunc[i] = (pacr2_masked >> bit) & 3;
+ }
+}
+
+uint16_t sh7021_device::pfc_pbior_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PFC_RD, "%s: Port B I/O (Direction) Register, pfc_pbior_r: %04x\n", machine().describe_context(), m_pfc.pbior);
+ return m_pfc.pbior;
+}
+
+void sh7021_device::pfc_pbior_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_PFC_WR, "%s: Port B I/O (Direction) Register, pfc_pbior_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_pfc.pbior);
+}
+
+uint16_t sh7021_device::pfc_pbcr1_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PFC_RD, "%s: Port B Control Register 1, pfc_pbcr1_r: %04x\n", machine().describe_context(), m_pfc.pbcr1);
+ return m_pfc.pbcr1;
+}
+
+void sh7021_device::pfc_pbcr1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_PFC_WR, "%s: Port B Control Register 1, pfc_pbcr1_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_pfc.pbcr1);
+ for (int i = 0; i < 8; i++)
+ {
+ int bit = i << 1;
+ m_pfc.pbfunc[8 + i] = (m_pfc.pbcr1 >> bit) & 3;
+ }
+}
+
+uint16_t sh7021_device::pfc_pbcr2_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PFC_RD, "%s: Port B Control Register 2, pfc_pbcr2_r: %04x\n", machine().describe_context(), m_pfc.pbcr2);
+ return m_pfc.pbcr2;
+}
+
+void sh7021_device::pfc_pbcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_PFC_WR, "%s: Port B Control Register 2, pfc_pbcr2_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_pfc.pbcr2);
+ for (int i = 0; i < 8; i++)
+ {
+ int bit = i << 1;
+ m_pfc.pbfunc[i] = (m_pfc.pbcr2 >> bit) & 3;
+ }
+}
+
+uint16_t sh7021_device::pfc_padr_r()
+{
+ const uint16_t data = ((m_pfc.padr_in & ~m_pfc.paior) | (m_pfc.padr & m_pfc.paior)) & m_pfc.pa_gpio_mask;
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PFC_RD, "%s: Port A Data Register, pfc_padr_r: %04x ((%04x & ~%04x) | (%04x & %04x)) & %04x\n", machine().describe_context(), data, m_pfc.padr_in, m_pfc.paior, m_pfc.padr, m_pfc.paior, m_pfc.pa_gpio_mask);
+ return data;
+}
+
+void sh7021_device::pfc_padr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_PFC_WR, "%s: Port A Data Register, pfc_padr_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ const uint16_t old = m_pfc.padr;
+ COMBINE_DATA(&m_pfc.padr);
+ const uint16_t changed = m_pfc.padr ^ old;
+
+ uint16_t output_mask = m_pfc.paior & m_pfc.pa_gpio_mask;
+ for (int i = 0; i < 16; i++)
+ {
+ if (BIT(output_mask, i) && BIT(changed, i))
+ {
+ m_pa_bit_out[i](BIT(m_pfc.padr, i));
+ }
+ }
+
+ if (output_mask)
+ {
+ m_pa_out(m_pfc.padr & output_mask, output_mask);
+ }
+}
+
+uint16_t sh7021_device::pfc_pbdr_r()
+{
+ const uint16_t data = ((m_pfc.pbdr_in & ~m_pfc.pbior) | (m_pfc.padr & m_pfc.pbior)) & m_pfc.pa_gpio_mask;
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PFC_RD, "%s: Port B Data Register, pfc_pbdr_r: %04x\n", machine().describe_context(), data);
+ return data;
+}
+
+void sh7021_device::pfc_pbdr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_PFC_WR, "%s: Port B Data Register, pfc_pbdr_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ const uint16_t old = m_pfc.pbdr;
+ COMBINE_DATA(&m_pfc.pbdr);
+ const uint16_t changed = m_pfc.pbdr ^ old;
+
+ uint16_t output_mask = m_pfc.pbior;
+ for (int i = 0; i < 16; i++)
+ {
+ if (m_pfc.pbfunc[i] != 0)
+ {
+ output_mask &= ~(1 << i);
+ }
+ else if (BIT(changed, i))
+ {
+ m_pb_bit_out[i](BIT(m_pfc.pbdr, i));
+ }
+ }
+
+ if (output_mask)
+ {
+ m_pb_out(m_pfc.pbdr & output_mask, output_mask);
+ }
+}
+
+uint16_t sh7021_device::pfc_cascr_r()
+{
+ if (!machine().side_effects_disabled())
+ LOGMASKED(LOG_PFC_RD, "%s: Column Address Strobe Pin Control Register, pfc_cascr_r: %04x\n", machine().describe_context(), m_pfc.cascr);
+ return m_pfc.cascr;
+}
+
+void sh7021_device::pfc_cascr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_PFC_WR, "%s: Column Address Strobe Pin Control Register, pfc_cascr_w = %04x & %04x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_pfc.cascr);
+}