summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/machine/cammu.h
blob: 5060fc96518a87a34e39c963481e3722625e5467 (plain) (tree)
1
2
3
4
5
6
7
8


                                      

                            
 
            
 



                                                               
 
                                               
                                                                                                

                               
                                                              
 
                                    

       
                                                                                                                                                   
 


                                                                 



                                     
 




                                                           
 














                                                                                                  
                                          







                                                                   











                                                                     
                                               
 















































































                                                                                                                                                                          
 


                                                                                                       
          

                                                                                                                        



                                             






                             
 
                             
         



                            

          







                                                                                                                                 
 





                                                     
 

                                                                                                

                                                       
                                                       

                                                         
 
                                       
                                  
  
 


                                           

                                                                       
                                                          
                                                                                                             
                                                          
                                                                                                             
 
                                                     

                                                      
                                                              
                                                               
                                                                              
                                                                               
                                                                              
                                                                               
                                                                              
                                                                               
                                                                              
                                                                               
                                                                              
                                                                               
                                                                              
                                                                               
 
          
                                                                                                                           


                                             
                                                                                                     


                                                                                                











                              

  
                                               



                                                                                                          
                                                    
 
                                                                

                                                                 
                                                                      

                                                                       
                                                                      
                                                                       






























                                                                     
                                                                               
                                                                                                                                                    
                                                                      
                                                                       
                                                                              

                                                                               
                                                                          
                                                                           
                                                                          
                                                                           
                                                                          
                                                                           
                                                                                            
                                                                                             
                                                                                
                                                                                 
                                                                      
                                                                       
                                                                      

                                                                       



                                                                                           
                                                                                                                               
 













                                     

  
                                               



                                                                                                          
                                                    
 

































                                                                             
                                                                           

                                   

                                       

          
                                                                               
                                                                                                                                                    
 










                                                                      
                                                          

                                                           
                                                                            
                                                                             
                                                                            
                                                                             
                                                                            
                                                                             
                                                                            

                                                                             
                                                                  

                                                                   
                                                                        

                                                                         



                                                                                           

                                                                                                        
 







                             






                                                                                                         

                                                    
 

                                                                                                                       
























                                                                                
                                                          
                                                                                                             
                                                          
                                                                                                             
                                                          
                                                           
                                                              
                                                                                                                                   
                                                          
                                                           
 





                                                                                                                                    

          


                                             
                                                                                                     

                                                                                                
                                                                                                                 

                                                                               

        





















                                                             

  
                          


                                                
 
                              
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay

#ifndef MAME_MACHINE_CAMMU_H
#define MAME_MACHINE_CAMMU_H

#pragma once

#include "cpu/clipper/common.h"

#define MCFG_CAMMU_ID(_id) \
	downcast<cammu_c4_device &>(*device).set_cammu_id(_id);

#define MCFG_CAMMU_EXCEPTION_CB(_exceptioncb) \
	devcb = &downcast<cammu_device &>(*device).set_exception_callback(DEVCB_##_exceptioncb);

#define MCFG_CAMMU_LINK(_tag) \
	downcast<cammu_c3_device &>(*device).add_linked(_tag);

class cammu_device : public device_t
{
public:
	template <class Object> devcb_base &set_exception_callback(Object &&cb) { return m_exception_func.set_callback(std::forward<Object>(cb)); }

	static const u32 CAMMU_PAGE_SIZE = 0x1000;
	static const u32 CAMMU_PAGE_MASK = (CAMMU_PAGE_SIZE - 1);

	enum pdo_mask : u32
	{
		PDO_MASK = 0xfffff000
	};

	enum ptde_mask : u32
	{
		PTDE_F   = 0x00000001, // page fault
		PTDE_PTO = 0xfffff000  // page table origin
	};

	enum pte_mask : u32
	{
		PTE_F     = 0x00000001, // page fault
		PTE_R     = 0x00000002, // referenced flag
		PTE_D     = 0x00000004, // dirty flag
		PTE_PL    = 0x00000078, // protection level
		PTE_S     = 0x00000180, // system reserved
		PTE_ST    = 0x00000e00, // system tag
		PTE_RA    = 0xfffff000, // real address

		PTE_CW    = 0x00000040, // copy on write (c400)
		PTE_NDREF = 0x00000080, // secondary reference (software) / copy on write (fault)?
		PTE_LOCK  = 0x00000100  // page lock (software)
	};

	static const int PTE_ST_SHIFT = 9;

	enum va_mask : u32
	{
		VA_POFS = 0x00000fff, // page offset
		VA_PTI  = 0x003ff000, // page table index
		VA_PTDI = 0xffc00000  // page table directory index
	};

	enum system_tag_t : u8
	{
		ST0 = 0, // private, write-through, main memory space
		ST1 = 1, // shared, write-through, main memory space
		ST2 = 2, // private, copy-back, main memory space
		ST3 = 3, // noncacheable, main memory space
		ST4 = 4, // noncacheable, i/o space
		ST5 = 5, // noncacheable, boot space
		ST6 = 6, // cache purge
		ST7 = 7  // slave i/o
	};

	virtual void map(address_map &map) = 0;

	void set_spaces(std::vector<address_space *> spaces);

	template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> load(const u32 ssw, const u32 address, U &&apply)
	{
		translated_t t = translate_address(ssw, address, access_size(sizeof(T)), READ);

		if (t.space != nullptr)
		{
			switch (sizeof(T))
			{
			case 1: apply(T(t.space->read_byte(t.address))); break;
			case 2: apply(T(t.space->read_word(t.address))); break;
			case 4: apply(T(t.space->read_dword(t.address))); break;
			case 8: apply(T(t.space->read_qword(t.address))); break;
			default: fatalerror("unhandled load size %d\n", access_size(sizeof(T)));
			}

			return true;
		}
		else
			return false;
	}

	template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> store(const u32 ssw, const u32 address, U data)
	{
		translated_t t = translate_address(ssw, address, access_size(sizeof(T)), WRITE);

		if (t.space != nullptr)
		{
			switch (sizeof(T))
			{
			case 1: t.space->write_byte(t.address, T(data)); break;
			case 2: t.space->write_word(t.address, T(data)); break;
			case 4: t.space->write_dword(t.address, T(data)); break;
			case 8: t.space->write_qword(t.address, T(data)); break;
			default: fatalerror("unhandled store size %d\n", access_size(sizeof(T)));
			}

			return true;
		}
		else
			return false;
	}

	template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<T(T)>>::value, bool> modify(const u32 ssw, const u32 address, U &&apply)
	{
		translated_t t = translate_address(ssw, address, access_size(sizeof(T)), RMW);

		if (t.space != nullptr)
		{
			switch (sizeof(T))
			{
			case 4: t.space->write_dword(t.address, apply(T(t.space->read_dword(t.address)))); break;
			default: fatalerror("unhandled modify size %d\n", access_size(sizeof(T)));
			}

			return true;
		}
		else
			return false;
	}

	template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> fetch(const u32 ssw, const u32 address, U &&apply)
	{
		translated_t t = translate_address(ssw, address, access_size(sizeof(T)), EXECUTE);

		if (t.space != nullptr)
		{
			switch (sizeof(T))
			{
			case 2: apply(T(t.space->read_word(t.address))); break;
			case 4: apply(T(t.space->read_dword_unaligned(t.address))); break;
			default: fatalerror("unhandled fetch size %d\n", access_size(sizeof(T)));
			}

			return true;
		}
		else
			return false;
	}

	// address translation for debugger
	bool memory_translate(const u32 ssw, const int spacenum, const int intention, offs_t &address);

protected:
	cammu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

	// device-level overrides
	virtual void device_start() override;
	virtual void device_reset() override;

	enum access_size : u8
	{
		BYTE  = 1,
		WORD  = 2,
		DWORD = 4,
		QWORD = 8
	};

	enum access_type : u8
	{
		READ    = 1,
		WRITE   = 2,
		RMW     = 3,
		EXECUTE = 4
	};

private:
	// address translation
	struct translated_t
	{
		address_space *const space;
		const u32 address;
	};
	translated_t translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode);

	struct pte_t
	{
		const u32 entry;
		const u32 address;
	};
	pte_t get_pte(const u32 va, const bool user);

	// helpers
	virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const = 0;
	virtual bool get_alignment() const = 0;
	virtual u32 get_pdo(const bool user) const = 0;
	virtual system_tag_t get_ust_space() const = 0;

	virtual void set_fault_address(const u32 va) = 0;

	devcb_write16 m_exception_func;
	address_space *m_space[8];
};

class cammu_c4_device : public cammu_device
{
public:
	void set_cammu_id(const u32 cammu_id) { m_control = cammu_id; }

	DECLARE_READ32_MEMBER(s_pdo_r) { return m_s_pdo; }
	DECLARE_WRITE32_MEMBER(s_pdo_w) { m_s_pdo = ((m_s_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; }
	DECLARE_READ32_MEMBER(u_pdo_r) { return m_u_pdo; }
	DECLARE_WRITE32_MEMBER(u_pdo_w) { m_u_pdo = ((m_u_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; }

	virtual DECLARE_READ32_MEMBER(control_r) = 0;
	virtual DECLARE_WRITE32_MEMBER(control_w) = 0;

	DECLARE_READ32_MEMBER(i_fault_r) { return m_i_fault; }
	DECLARE_WRITE32_MEMBER(i_fault_w) { m_i_fault = data; }
	DECLARE_READ32_MEMBER(fault_address_1_r) { return m_fault_address_1; }
	DECLARE_WRITE32_MEMBER(fault_address_1_w) { m_fault_address_1 = data; }
	DECLARE_READ32_MEMBER(fault_address_2_r) { return m_fault_address_2; }
	DECLARE_WRITE32_MEMBER(fault_address_2_w) { m_fault_address_2 = data; }
	DECLARE_READ32_MEMBER(fault_data_1_lo_r) { return m_fault_data_1_lo; }
	DECLARE_WRITE32_MEMBER(fault_data_1_lo_w) { m_fault_data_1_lo = data; }
	DECLARE_READ32_MEMBER(fault_data_1_hi_r) { return m_fault_data_1_hi; }
	DECLARE_WRITE32_MEMBER(fault_data_1_hi_w) { m_fault_data_1_hi = data; }
	DECLARE_READ32_MEMBER(fault_data_2_lo_r) { return m_fault_data_2_lo; }
	DECLARE_WRITE32_MEMBER(fault_data_2_lo_w) { m_fault_data_2_lo = data; }
	DECLARE_READ32_MEMBER(fault_data_2_hi_r) { return m_fault_data_2_hi; }
	DECLARE_WRITE32_MEMBER(fault_data_2_hi_w) { m_fault_data_2_hi = data; }

protected:
	cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

	virtual void device_start() override;

	virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override;
	virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; }

	virtual void set_fault_address(const u32 va) override { m_fault_address_1 = va; }

	u32 m_s_pdo;
	u32 m_u_pdo;
	u32 m_control;

	u32 m_i_fault;
	u32 m_fault_address_1;
	u32 m_fault_address_2;
	u32 m_fault_data_1_lo;
	u32 m_fault_data_1_hi;
	u32 m_fault_data_2_lo;
	u32 m_fault_data_2_hi;
};

class cammu_c4t_device : public cammu_c4_device
{
public:
	cammu_c4t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	virtual void map(address_map &map) override;

	DECLARE_READ32_MEMBER(ram_line_r) { return m_ram_line; }
	DECLARE_WRITE32_MEMBER(ram_line_w) { m_ram_line = data; }

	DECLARE_READ32_MEMBER(htlb_offset_r) { return m_htlb_offset; }
	DECLARE_WRITE32_MEMBER(htlb_offset_w) { m_htlb_offset = data; }

	DECLARE_READ32_MEMBER(c4_bus_poll_r) { return m_c4_bus_poll; }
	DECLARE_WRITE32_MEMBER(c4_bus_poll_w) { m_c4_bus_poll = data; }

	enum control_mask : u32
	{
		CNTL_RUV   = 0x00000001, // reset user valid
		CNTL_RSV   = 0x00000002, // reset supervisor valid
		CNTL_DBWR  = 0x00000004, // disable bus watch read
		CNTL_ATD   = 0x00000008, // alignment trap disable
		CNTL_UST   = 0x00000030, // unmapped system tag
		CNTL_IOTS  = 0x00000040, // i/o tag select
		CNTL_UVS   = 0x00000080, // user valid status
		CNTL_PB    = 0x00000100, // purge busy
		CNTL_CICT  = 0x00000200, // clear i-side cache tags
		CNTL_CFR   = 0x00000400, // clear trap registers
		CNTL_HTLBD = 0x00000800, // htlb disable
		CNTL_CDCT  = 0x00001000, // clear d-side cache tags
		CNTL_CID   = 0xff000000  // cammu id
	};

	enum control_ust_mask : u32
	{
		UST_NCA = 0x00, // unmapped system tag, noncacheable
		UST_PWT = 0x10, // unmapped system tag, write through
		UST_PCB = 0x20, // unmapped system tag, copy back
		UST_PGE = 0x30  // unmapped system tag, purge mode
	};

	enum control_cid_mask : u32
	{
		CID_C4T = 0x00000000 // unknown
	};

	virtual DECLARE_READ32_MEMBER(control_r) override { return m_control; }
	virtual DECLARE_WRITE32_MEMBER(control_w) override { m_control = ((m_control & (~mem_mask | CNTL_CID)) | (data & (mem_mask & ~CNTL_CID))); }
	DECLARE_READ32_MEMBER(bio_control_r) { return m_bio_control; }
	DECLARE_WRITE32_MEMBER(bio_control_w) { m_bio_control = data; }
	DECLARE_READ32_MEMBER(bio_address_tag_r) { return m_bio_address_tag; }
	DECLARE_WRITE32_MEMBER(bio_address_tag_w) { m_bio_address_tag = data; }

	DECLARE_READ32_MEMBER(cache_data_lo_r) { return m_cache_data_lo; }
	DECLARE_WRITE32_MEMBER(cache_data_lo_w) { m_cache_data_lo = data; }
	DECLARE_READ32_MEMBER(cache_data_hi_r) { return m_cache_data_hi; }
	DECLARE_WRITE32_MEMBER(cache_data_hi_w) { m_cache_data_hi = data; }
	DECLARE_READ32_MEMBER(cache_cpu_tag_r) { return m_cache_cpu_tag; }
	DECLARE_WRITE32_MEMBER(cache_cpu_tag_w) { m_cache_cpu_tag = data; }
	DECLARE_READ32_MEMBER(cache_system_tag_valid_r) { return m_cache_system_tag_valid; }
	DECLARE_WRITE32_MEMBER(cache_system_tag_valid_w) { m_cache_system_tag_valid = data; }
	DECLARE_READ32_MEMBER(cache_system_tag_r) { return m_cache_system_tag; }
	DECLARE_WRITE32_MEMBER(cache_system_tag_w) { m_cache_system_tag = data; }
	DECLARE_READ32_MEMBER(tlb_va_line_r) { return m_tlb_va_line; }
	DECLARE_WRITE32_MEMBER(tlb_va_line_w) { m_tlb_va_line = data; }
	DECLARE_READ32_MEMBER(tlb_ra_line_r) { return m_tlb_ra_line; }
	DECLARE_WRITE32_MEMBER(tlb_ra_line_w) { m_tlb_ra_line = data; }

protected:
	virtual void device_start() override;

	virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; }
	virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & (CNTL_IOTS | CNTL_UST)) >> 4); }

private:
	u32 m_ram_line;
	u32 m_htlb_offset;
	u32 m_c4_bus_poll;
	u32 m_bio_control;
	u32 m_bio_address_tag;

	u32 m_cache_data_lo;
	u32 m_cache_data_hi;
	u32 m_cache_cpu_tag;
	u32 m_cache_system_tag_valid;
	u32 m_cache_system_tag;
	u32 m_tlb_va_line;
	u32 m_tlb_ra_line;
};

class cammu_c4i_device : public cammu_c4_device
{
public:
	cammu_c4i_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	virtual void map(address_map &map) override;

	enum control_mask : u32
	{
		CNTL_LRAS = 0x00000001, // tlb line replacement
		CNTL_BWWD = 0x00000002, // buswatch write disable
		CNTL_BWRD = 0x00000004, // buswatch read disable
		CNTL_FSR  = 0x00000010, // fake system response
		CNTL_ATD  = 0x00000100, // alignment trap disable
		CNTL_UMM  = 0x00003000, // unmapped mode address space select
		CNTL_POLL = 0x00030000, // poll bus signals
		CNTL_BM   = 0x00040000, // burst mode address space select
		CNTL_PZBS = 0x00080000, // page 0 boot select
		CNTL_CRR  = 0x00700000, // cache memory refresh rate
		CNTL_CID  = 0xff000000  // cammu identification
	};

	enum control_umm_mask : u32
	{
		UMM_MM    = 0x00000000, // mm space, noncacheable
		UMM_MMRIO = 0x00001000, // mm or i/o space, noncacheable
		UMM_IO    = 0x00002000  // i/o space noncacheable
	};

	enum control_crr_mask : u32
	{
		CRR_GT131  = 0x00000000, // clock rate over 131 MHz
		CRR_GT66   = 0x00100000, // clock rate over 66 MHz
		CRR_GT33   = 0x00200000, // clock rate over 33 MHz
		CRR_GT8    = 0x00300000, // clock rate over 8 MHz
		CRR_GT2    = 0x00400000, // clock rate over 2 MHz
		CRR_GT1    = 0x00500000, // clock rate over 1 MHz
		CRR_GTHALF = 0x00600000, // clock rate over 0.5 MHz
		CRR_OFF    = 0x00700000, // refresh off
	};

	// c4i cammu identification (rev 2 and rev 3 known to have existed)
	enum control_cid_mask : u32
	{
		CID_C4IR0 = 0x00000000,
		CID_C4IR2 = 0x02000000
	};

	virtual DECLARE_READ32_MEMBER(control_r) override { return m_control; }
	virtual DECLARE_WRITE32_MEMBER(control_w) override { m_control = ((m_control & (~mem_mask | CNTL_CID)) | (data & (mem_mask & ~CNTL_CID))); }

	enum reset_mask : u32
	{
		RESET_CDCT  = 0x00000001, // clear data cache tags
		RESET_RDUV  = 0x00000100, // reset all d-side uv flags
		RESET_RDSV  = 0x00001000, // reset all d-side sv flags
		RESET_CICT  = 0x00010000, // clear ins. cache tags
		RESET_RIUV  = 0x01000000, // reset all i-side uv flags
		RESET_RISV  = 0x10000000, // reset all i-side sv flags
		RESET_FLUSH = 0x40000000, // flush out burst io buffer
		RESET_CFR   = 0x80000000  // clear fault registers
	};
	DECLARE_READ32_MEMBER(reset_r) { return m_reset; }
	DECLARE_WRITE32_MEMBER(reset_w) { m_reset = data; }

	DECLARE_READ32_MEMBER(clr_s_data_tlb_r) { return m_clr_s_data_tlb; }
	DECLARE_WRITE32_MEMBER(clr_s_data_tlb_w) { m_clr_s_data_tlb = data; }
	DECLARE_READ32_MEMBER(clr_u_data_tlb_r) { return m_clr_u_data_tlb; }
	DECLARE_WRITE32_MEMBER(clr_u_data_tlb_w) { m_clr_u_data_tlb = data; }
	DECLARE_READ32_MEMBER(clr_s_insn_tlb_r) { return m_clr_s_insn_tlb; }
	DECLARE_WRITE32_MEMBER(clr_s_insn_tlb_w) { m_clr_s_insn_tlb = data; }
	DECLARE_READ32_MEMBER(clr_u_insn_tlb_r) { return m_clr_u_insn_tlb; }
	DECLARE_WRITE32_MEMBER(clr_u_insn_tlb_w) { m_clr_u_insn_tlb = data; }

	DECLARE_READ32_MEMBER(test_data_r) { return m_test_data; }
	DECLARE_WRITE32_MEMBER(test_data_w) { m_test_data = data; }

	DECLARE_READ32_MEMBER(test_address_r) { return m_test_address; }
	DECLARE_WRITE32_MEMBER(test_address_w) { m_test_address = data; }

protected:
	virtual void device_start() override;

	virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; }
	// FIXME: don't really know how unmapped mode works on c4i
	virtual system_tag_t get_ust_space() const override { return (m_control & UMM_IO) ? ST4 : ST3; }

private:
	u32 m_reset;
	u32 m_clr_s_data_tlb;
	u32 m_clr_u_data_tlb;
	u32 m_clr_s_insn_tlb;
	u32 m_clr_u_insn_tlb;
	u32 m_test_data;
	u32 m_test_address;
};

class cammu_c3_device : public cammu_device
{
public:
	cammu_c3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	virtual void map(address_map &map) override;
	virtual void map_global(address_map &map);

	void add_linked(const char *const tag) { m_linked.push_back(downcast<cammu_c3_device *>(siblingdevice(tag))); }

	enum control_mask : u32
	{
		CNTL_EP   = 0x00000001, // enable prefetch
		CNTL_EWCW = 0x00000002, // enable watch cpu writes
		CNTL_EWIW = 0x00000004, // enable watch i/o writes
		CNTL_EWIR = 0x00000008, // enable watch i/o reads
		CNTL_UST  = 0x00000030, // unmapped system tag
		CNTL_CV   = 0x00000100, // clear valid
		CNTL_ATE  = 0x00000200, // alignment trap enable
		CNTL_CID  = 0xff000000  // cammu id
	};

	enum ust_mask : u32
	{
		UST_0 = 0x00000000, // private, write-through, main memory space
		UST_1 = 0x00000010, // shared, write-through, main memory space
		UST_2 = 0x00000020, // private, copy-back, main memory space
		UST_3 = 0x00000030  // noncacheable, main memory space
	};

	enum control_cid_mask : u32
	{
		CID_C3 = 0x00000000 // unknown
	};

	DECLARE_READ32_MEMBER(s_pdo_r) { return m_s_pdo; }
	DECLARE_WRITE32_MEMBER(s_pdo_w) { m_s_pdo = ((m_s_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; }
	DECLARE_READ32_MEMBER(u_pdo_r) { return m_u_pdo; }
	DECLARE_WRITE32_MEMBER(u_pdo_w) { m_u_pdo = ((m_u_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; }
	DECLARE_READ32_MEMBER(fault_r) { return m_fault; }
	DECLARE_WRITE32_MEMBER(fault_w) { m_fault = data; }
	DECLARE_READ32_MEMBER(control_r) { return m_control; }
	DECLARE_WRITE32_MEMBER(control_w) { m_control = ((m_control & (~mem_mask | CNTL_CID)) | (data & (mem_mask & ~CNTL_CID))); }
	DECLARE_READ32_MEMBER(reset_r) { return m_reset; }
	DECLARE_WRITE32_MEMBER(reset_w) { m_reset = data; }

	// global methods - relay to each linked device
	DECLARE_WRITE32_MEMBER(g_s_pdo_w)   { for (cammu_c3_device *dev : m_linked) dev->s_pdo_w(space, offset, data, mem_mask); }
	DECLARE_WRITE32_MEMBER(g_u_pdo_w)   { for (cammu_c3_device *dev : m_linked) dev->u_pdo_w(space, offset, data, mem_mask); }
	DECLARE_WRITE32_MEMBER(g_fault_w)   { for (cammu_c3_device *dev : m_linked) dev->fault_w(space, offset, data, mem_mask); }
	DECLARE_WRITE32_MEMBER(g_control_w) { for (cammu_c3_device *dev : m_linked) dev->control_w(space, offset, data, mem_mask); }
	DECLARE_WRITE32_MEMBER(g_reset_w)   { for (cammu_c3_device *dev : m_linked) dev->reset_w(space, offset, data, mem_mask); }

protected:
	virtual void device_reset() override;
	virtual void device_start() override;

	virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override;
	virtual bool get_alignment() const override { return m_control & CNTL_ATE; }
	virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; }
	virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & CNTL_UST) >> 4); }

	virtual void set_fault_address(const u32 va) override { m_fault = va; }

private:
	enum c3_access_t : u8
	{
		N   = 0, // no access
		R   = 1, // read permitted
		W   = 2, // write permitted
		RW  = 3, // read and write permitted
		E   = 4, // execute permitted
		RE  = 5, // read and execute permitted
		RWE = 7  // read, write and execute permitted
	};

	static const u8 i_cammu_column[];
	static const u8 d_cammu_column[];
	static const c3_access_t cammu_matrix[][16];

	u32 m_s_pdo;
	u32 m_u_pdo;
	u32 m_fault;
	u32 m_control;
	u32 m_reset;

	std::vector<cammu_c3_device *> m_linked;
};

// device type definitions
DECLARE_DEVICE_TYPE(CAMMU_C4T, cammu_c4t_device)
DECLARE_DEVICE_TYPE(CAMMU_C4I, cammu_c4i_device)
DECLARE_DEVICE_TYPE(CAMMU_C3,  cammu_c3_device)

#endif // MAME_MACHINE_CAMMU_H