// license:BSD-3-Clause // copyright-holders:Olivier Galibert /*************************************************************************** h8_dma.h H8 DMA Controller ***************************************************************************/ #ifndef MAME_CPU_H8_H8_DMA_H #define MAME_CPU_H8_H8_DMA_H #pragma once #include "h8.h" #include "h8_intc.h" struct h8_dma_state { enum { ACTIVE = 0x0001, // DMA is configured SUSPENDED = 0x0002, // DMA currently suspended until trigger happens SUSPEND_AFTER_TRANSFER = 0x0004, // Auto-suspend DMA after each transfer BLOCK = 0x0008, // FAE block mode (cleared on last block) REPEAT = 0x0010, // SAE repeat mode MODE_16 = 0x0020, // Transfer 16-bits values EAT_INTERRUPT = 0x0040, // Discard interrupt when used as trigger TEND_INTERRUPT = 0x0080, // Interrupt on end of transfer SOURCE_DECREMENT = 0x0100, // Decrement source instead of increment (folded into incs/incd) DEST_DECREMENT = 0x0200, // Decrement source instead of increment (folded into incs/incd) SOURCE_IDLE = 0x0400, // Don't increment/decrement source (folded into incs/incd) DEST_IDLE = 0x0800, // Don't increment/decrement destination (folded into incs/incd) MAR_IS_DEST = 0x1000, // MAR is destination in SAE (folded), destibation is the block in fae block FAE = 0x2000, // FAE mode (for interrupt generation) }; u32 m_source, m_dest; s32 m_incs, m_incd; u32 m_count, m_bcount; u16 m_flags; u8 m_id; s8 m_trigger_vector; }; class h8gen_dma_channel_device; enum { // mind the order, all DREQ, TEND need to be sequential H8_INPUT_LINE_DREQ0 = INPUT_LINE_IRQ9 + 1, H8_INPUT_LINE_DREQ1, H8_INPUT_LINE_DREQ2, H8_INPUT_LINE_DREQ3, H8_INPUT_LINE_TEND0, H8_INPUT_LINE_TEND1, H8_INPUT_LINE_TEND2, H8_INPUT_LINE_TEND3, }; class h8h_dma_device; class h8s_dma_device; DECLARE_DEVICE_TYPE(H8H_DMA, h8h_dma_device) DECLARE_DEVICE_TYPE(H8S_DMA, h8s_dma_device) class h8gen_dma_device : public device_t { public: bool trigger_dma(int vector); void count_last(int id); void count_done(int id); void set_input(int inputnum, int state); void start_stop_test(); protected: required_device m_cpu; optional_device_array m_dmach; virtual void device_start() override ATTR_COLD; virtual void device_reset() override ATTR_COLD; virtual u8 active_channels() const = 0; h8gen_dma_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock = 0); }; class h8h_dma_device : public h8gen_dma_device { public: h8h_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); template h8h_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu) : h8h_dma_device(mconfig, tag, owner) { m_cpu.set_tag(std::forward(cpu)); } u8 active_channels() const override; }; class h8s_dma_device : public h8gen_dma_device { public: h8s_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); template h8s_dma_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu) : h8s_dma_device(mconfig, tag, owner) { m_cpu.set_tag(std::forward(cpu)); } u8 dmawer_r(); void dmawer_w(u8 data); u8 dmatcr_r(); void dmatcr_w(u8 data); u16 dmabcr_r(); void dmabcr_w(offs_t offset, u16 data, u16 mem_mask = ~0); void channel_done(int id); int channel_mode(int id, bool block) const; std::tuple get_fae_dtie_dta(int id) const; protected: u8 m_dmawer, m_dmatcr; u16 m_dmabcr; void device_start() override ATTR_COLD; void device_reset() override ATTR_COLD; u8 active_channels() const override; }; class h8gen_dma_channel_device : public device_t { public: enum { NONE = 0, DREQ_LEVEL = -1, DREQ_EDGE = -2, AUTOREQ_CS = -3, AUTOREQ_B = -4, }; enum { FAE_NORMAL, FAE_BLOCK, SAE, SAE_DACK, }; h8_dma_state m_state[2]; h8gen_dma_channel_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); u16 marah_r(); void marah_w(offs_t offset, u16 data, u16 mem_mask = ~0); u16 maral_r(); void maral_w(offs_t offset, u16 data, u16 mem_mask = ~0); u16 ioara_r(); u8 ioara8_r(); void ioara_w(offs_t offset, u16 data, u16 mem_mask = ~0); void ioara8_w(u8 data); u16 etcra_r(); void etcra_w(offs_t offset, u16 data, u16 mem_mask = ~0); u16 marbh_r(); void marbh_w(offs_t offset, u16 data, u16 mem_mask = ~0); u16 marbl_r(); void marbl_w(offs_t offset, u16 data, u16 mem_mask = ~0); u16 ioarb_r(); u8 ioarb8_r(); void ioarb_w(offs_t offset, u16 data, u16 mem_mask = ~0); void ioarb8_w(u8 data); u16 etcrb_r(); void etcrb_w(offs_t offset, u16 data, u16 mem_mask = ~0); void set_id(int id); void count_done(int submodule); void start_stop_test(); bool transfer_test_interrupt(int vector); void set_dreq(int state); void start(int submodule); void abort(int submodule) { dma_done(submodule); } protected: required_device m_cpu; required_device m_intc; int m_irq_base; u32 m_ioar_mask; // ff0000 for h8s, ffff00 for h8h u32 m_mar[2]; u16 m_ioar[2], m_etcr[2]; bool m_dreq; virtual void device_start() override ATTR_COLD; virtual void device_reset() override ATTR_COLD; virtual void dma_done(int subchannel); virtual int channel_mode() const = 0; virtual u16 channel_flags(int submodule) const = 0; virtual s8 trigger_vector(int submodule) const = 0; }; class h8h_dma_channel_device : public h8gen_dma_channel_device { public: h8h_dma_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); template h8h_dma_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu, U &&dma, V &&intc, bool has_adc, bool targets_sci1) : h8h_dma_channel_device(mconfig, tag, owner) { m_cpu.set_tag(std::forward(cpu)); m_dma.set_tag(std::forward(dma)); m_intc.set_tag(std::forward(intc)); m_has_adc = has_adc; m_targets_sci1 = targets_sci1; } u8 dtcra_r(); void dtcra_w(u8 data); u8 dtcrb_r(); void dtcrb_w(u8 data); u8 active_channels() const; protected: required_device m_dma; u8 m_dtcr[2]; bool m_has_adc; bool m_targets_sci1; void device_start() override ATTR_COLD; void device_reset() override ATTR_COLD; void dma_done(int subchannel) override; int channel_mode() const override; u16 channel_flags(int submodule) const override; s8 trigger_vector(int submodule) const override; }; class h8s_dma_channel_device : public h8gen_dma_channel_device { public: h8s_dma_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); template h8s_dma_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu, U &&dma, V &&intc) : h8s_dma_channel_device(mconfig, tag, owner) { m_cpu.set_tag(std::forward(cpu)); m_dma.set_tag(std::forward(dma)); m_intc.set_tag(std::forward(intc)); } u16 dmacr_r(); void dmacr_w(offs_t offset, u16 data, u16 mem_mask = ~0); protected: u16 m_dmacr; required_device m_dma; void device_start() override ATTR_COLD; void device_reset() override ATTR_COLD; void dma_done(int subchannel) override; int channel_mode() const override; u16 channel_flags(int submodule) const override; s8 trigger_vector(int submodule) const override; }; DECLARE_DEVICE_TYPE(H8H_DMA_CHANNEL, h8h_dma_channel_device) DECLARE_DEVICE_TYPE(H8S_DMA_CHANNEL, h8s_dma_channel_device) #endif // MAME_CPU_H8_H8_DMA_H