summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/drivers/4dpi.cpp
blob: b0b06f8487aa287ae666924c1236f61fec621306 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
                       
                                      
  







                                                                     
           
                                                                                         
                                                                            


                                                                     
                                                                                                                                           


                                                                 
                     
                             
                            

          
                                        




                                                   
   

                

                 
                           
                                  








                              


                                 


                              

                         
                            

                               

                  
                          
 
                             
 

                             
 
                                         

       
                                                                                      






                                                   
                                       
                                               
                                                 
                                     
                                            
         
         
 


                                            
                          
 



                                                                   
 

                                              
                                                    
                                              

                                                             
                                              
 





                                               
                                       
          
                                
 
                                            
                                   
 



                                                                                        
                     
 
                                     
         










                                                                        
                                                                                      






                                                                          















                                                                    
                             
         




                                                                              

          
                               
         







                                                                   

          










                                                                      

                     



                       
                                 
 









                                    


                       
                       
 



                                        




                                                   
  
 















































                                                                                                           
                                   


                           
                                        
 


                                            



                                                                                                       

                                                                              


                                                                                                 
                                                                              
 
                                                                          
                                                                                       
 
                                                                                                                                              
                                                                                       
 

                                                                                                                                                
 

                                                     



                                                         



                                                                

                                                                  

                                                              

                                                                 
 
                                         
                                                    
                                                                  

                                                       

                               
                                   



                                                        
 



                                                                  

                                                          
 
                                                     
 
                                           
                                                      
 

                                                   





                                                                                          
                                                  
 


                                                                                  




                                                                                 


                                                                                                                             
 

                                           

                                                                                                                             

                                                                                                                    
                                                                                                
 


                                                                                                   



                                         








                                                                                  

                                                                    
                                                



                                                                                  
                                                    
 














                                                                                                       
                                                                                    











                                                                                         

                                                                                                                                             
 
                                                                                                                                               
 
                                          

                        










                                                                                                                     
                              

                                

                                                           
                               
 



                                                                                                                                                          
 
                                                                                                                                                                                    
                                                                                                    

                                                                                                                                                                                        
                                                                                               
                                                                                                 
 


                                                                                                                   
 

                                                                                                         
 

                                                                                                                                                                                                                         
 
                                                                                                                                                                                    
 




                                                                                                                                           


                                                                                                                                 
 
                                                                                                                         
 
                                                            


                                                                                                       

 






































































































                                                                                                                                           
                                                       
 




                                                                                    
                                                      

 
                                                 
 

                                                           











                                                        















                                                         



                                                           

                                                                            
                                                                       





                                                          
 
                                          


                                           

                                                                                                                 




                                                                                        
                                        
                 
                                                                                               
 
                                                    

                                                                                                          








                                                                           
                               
                                                                            


                                     

                                                                                          
 




                                                                  

                                                                                          














                                                                                                                              
                                                                                     








                                                                                            
                                                                        

                                                                        
                          
                                                                                     


                                                                                   



                                                             



                                                             

                   



                                                                                 
 


                                                                                 
 
                   
                               



                                  
                         
                                                                 



                                                                
                   
                                                                                        

                                                                                               
                                          
 
 





















































































































                                                                                                                              
                               
 

                                                                                 
 

                     






                                           
                                                  



                         





                                                                                 
                                                            


                                     








                                                              
                                 
                  
                                  

                                   


                                                    
                                





                                                                  



















                                                                                        
                                      


                  

                                                                                 
                    
                                                                              
 

                                                                     
         

 
                          
 
                          

                                
                                      



                    
               





















                                                                                                                                                          

       


















                                                                                                                                             
                                                                                                                                



                                                                                                                                                                  
// license:BSD-3-Clause
// copyright-holders:Patrick Mackinlay
/*
 * SGI Personal IRIS family driver
 *
 *   Year  Model  Board  Type  CPU    Clock    I/D Cache    Code Name
 *   1988  4D/20  IP6    IP6   R2000  12.5MHz  16KiB/8KiB   Eclipse
 *   1989  4D/25  IP10   IP6   R3000  20MHz    64KiB/32KiB  Eclipse
 *   1991  4D/30  IP14   IP12  R3000  30MHz    64KiB/64KiB  Magnum
 *   1991  4D/35  IP12   IP12  R3000  36MHz    64KiB/64KiB  Magnum
 *
 * Sources:
 *   - http://bitsavers.org/pdf/sgi/personal_iris/VME-Eclipse_CPU_VIP10_Specification.pdf
 *   - http://www.bitsavers.org/pdf/sgi/personal_iris/SGI_IP-6_Schematic.pdf
 *   - http://www.futuretech.blinkenlights.nl/pitechrep.html
 *   - https://hardware.majix.org/computers/sgi.pi/index.shtml
 *   - http://archive.irix.cc/sgistuff/hardware/systems/personal.html
 *   - http://archive.irix.cc/developerforum95/Silicon_Graphics_Developer_Forum_95_The_CD_Volume_2/documents/hw_handbook_html/handbook.html
 *   - https://github.com/NetBSD/src/tree/trunk/sys/arch/sgimips/
 *
 * TODO:
 *   - audio, printer
 *   - devicify ioc1 and ctl1
 *   - 4d30/35 skeleton only
 *
 * Status:
 *   - parity and cache diagnostics fail
 *   - irix 4.0.5 working
 *   - ide test failures
 *     - lca2 (unimplemented fpga program/readback)
 *     - nvram4 (security mode?)
 *     - fpu (cvt.?.? invalid operation exceptions)
 */

#include "emu.h"

// cpu and memory
#include "cpu/mips/mips1.h"
#include "cpu/dsp56000/dsp56000.h"
#include "machine/ram.h"
#include "machine/eepromser.h"

// other devices
#include "machine/wd33c9x.h"
#include "machine/am79c90.h"
#include "machine/mc68681.h"
#include "machine/pit8253.h"
#include "machine/dp8573.h"
#include "machine/z80scc.h"
#include "machine/edlc.h"
#include "machine/input_merger.h"

// buses and connectors
#include "machine/nscsi_bus.h"
#include "bus/nscsi/hd.h"
#include "bus/nscsi/cd.h"
#include "bus/rs232/rs232.h"
#include "bus/sgikbd/sgikbd.h"
#include "bus/rs232/hlemouse.h"

// video and audio
#include "video/sgi_gr1.h"

#define LOG_GENERAL (1U << 0)

#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"

class pi4d2x_state : public driver_device
{
public:
	pi4d2x_state(machine_config const &mconfig, device_type type, char const *tag)
		: driver_device(mconfig, type, tag)
		, m_cpu(*this, "maincpu")
		, m_ram(*this, "ram")
		, m_eeprom(*this, "eeprom")
		, m_rtc(*this, "rtc")
		, m_pit(*this, "pit")
		, m_scsi(*this, "scsi:0:wd33c93")
		, m_enet(*this, "enet")
		, m_duart(*this, "duart%u", 0U)
		, m_serial(*this, "serial%u", 1U)
		, m_gfx(*this, "gfx")
		, m_leds(*this, "led%u", 0U)
	{
	}

	void pi4d20(machine_config &config);
	void pi4d25(machine_config &config);

	void initialize();

private:
	required_device<mips1_device_base> m_cpu;
	required_device<ram_device> m_ram;
	required_device<eeprom_serial_93c56_16bit_device> m_eeprom;

	required_device<dp8573_device> m_rtc;
	required_device<pit8254_device> m_pit;
	required_device<wd33c9x_base_device> m_scsi;
	required_device<am7990_device> m_enet;
	required_device_array<scn2681_device, 2> m_duart;
	required_device_array<rs232_port_device, 2> m_serial;
	required_device<sgi_gr1_device> m_gfx;

	enum leds : unsigned
	{
		LED_HBT = 0, // heartbeat (1Hz)
		LED_CPU = 1, // cpu activity
		LED_GFX = 2, // graphics
		LED_FPU = 3, // fpu present
		LED_CON = 4, // console
	};
	output_finder<5> m_leds;

	void common(machine_config &config);
	void map(address_map &map);

	template <unsigned N> void lio_interrupt(int state) { lio_interrupt(N, state); }
	void lio_interrupt(unsigned number, int state);
	void scsi_drq(int state);

	u8 sysid_r();

	u32 buserror_r(offs_t offset)
	{
		m_cpu->berr_w(1);
		return 0;
	}
	void buserror_w(offs_t offset, u32 data, u32 mem_mask)
	{
		m_cpu->set_input_line(INPUT_LINE_IRQ5, 1);
	}

	enum sysid_mask : u8
	{
		SYSID_SERDATA = 0x01, // serial memory data output state
		SYSID_FPPRES  = 0x02, // floating point processor present (active low)
		SYSID_SERCLK  = 0x04, // serial memory clock
		SYSID_VMEFBT  = 0x04, // vme fast bus timeout
		SYSID_GDMAERR = 0x08, // error in graphics dma
		SYSID_GDMAEN  = 0x10, // graphics dma busy
		SYSID_GDMARDY = 0x20, // asserted at end of graphics dma
		SYSID_GDMARST = 0x40, // asserted in reset of graphics dma
		SYSID_VMERMW  = 0x80, // asserted in vme read-modify-write
	};

	enum lio_int_number : unsigned
	{
		LIO_D0     = 0, // duart 0 interrupt
		LIO_D1     = 1, // duart 1 interrupt
		LIO_VR     = 2, // vertical retrace interrupt
		LIO_CENTR  = 3, // parallel port interrupt
		LIO_SCSI   = 4, // scsi interrupt
		LIO_ENET   = 5, // ethernet interrupt
		LIO_GE     = 6, // ge interrupt
		LIO_FIFO   = 7, // fifo full interrupt
		LIO_AC     = 8, // vme ac fail interrupt
		LIO_VRSTAT = 9, // vert retrace status: no interrupt
	};

	enum memcfg_mask : u8
	{
		MEMCFG_MEMSIZE  = 0x0f, // (n+1)/16 memory populated
		MEMCFG_4MRAM    = 0x10, // 4M DRAMs
		MEMCFG_TIMERDIS = 0x20, // disable timer (active low)
		MEMCFG_FMEM     = 0x40, // reduce cas pulse on reads
		MEMCFG_REFDIS   = 0x80, // disable memory refresh (active low)
	};

	enum cpuctrl_mask : u16
	{
		CPUCTRL_SERDATA = 0x0100, // serial memory data out
		CPUCTRL_SIN     = 0x0200, // system init (reset)
		CPUCTRL_RPAR    = 0x0400, // enable parity checking
		CPUCTRL_SLA     = 0x0800, // enable slave accesses
		CPUCTRL_ARB     = 0x1000, // enable vme arbiter
		CPUCTRL_BAD     = 0x2000, // write bad parity
		CPUCTRL_DOG     = 0x4000, // enable watchdog timer
		CPUCTRL_FPER    = 0x8000, // fast peripheral cycle
	};

	enum cpuauxctl_mask : u8
	{
		CPUAUXCTRL_LED = 0x0f, // diagnostic leds (active low)
		CPUAUXCTRL_PE  = 0x10, // console led (active low)
		CPUAUXCTRL_CS  = 0x20, // eeprom chip select
		CPUAUXCTRL_CLK = 0x40, // serial clock
		CPUAUXCTRL_GR  = 0x80, // graphics reset (active low)
	};

	u8 m_memcfg;
	u8 m_sysid;
	u8 m_vme_isr;
	u8 m_vme_imr;
	u16 m_cpuctrl;
	u8 m_cpuauxctl;
	u32 m_erradr;
	u32 m_refadr;
	attotime m_refresh_timer;

	enum parerr_mask : u8
	{
		PARERR_GDMA  = 0x01,
		PARERR_DMA   = 0x02,
		PARERR_CPU   = 0x04,
		PARERR_VME   = 0x08,
		PARERR_BYTE  = 0xf0,
	};
	u8 m_parerr;

	u16 m_lio_isr;
	u8 m_lio_imr;
	bool m_lio_int;
	int m_lio_fifo;

	u16 m_dmalo;
	u8 m_mapindex;
	std::unique_ptr<u16 []> m_dmahi;
	offs_t m_dmaaddr;

	u32 m_gdma_dabr;   // descriptor array base
	u32 m_gdma_bufadr; // buffer address
	u16 m_gdma_burst;  // burst/delay
	u16 m_gdma_buflen; // buffer length
};

class pi4d3x_state : public driver_device
{
public:
	pi4d3x_state(machine_config const &mconfig, device_type type, char const *tag)
		: driver_device(mconfig, type, tag)
		, m_cpu(*this, "maincpu")
		, m_ram(*this, "ram")
		, m_eprom(*this, "boot")
		, m_eeprom(*this, "eeprom")
		, m_rtc(*this, "rtc")
		, m_pit(*this, "pit")
		, m_scsi(*this, "scsi:0:wd33c93a")
		, m_enet(*this, "enet")
		, m_duart(*this, "duart%u", 0U)
		, m_serial(*this, "serial%u", 1U)
		, m_dsp(*this, "dsp")
	{
	}

	void pi4d30(machine_config &config);
	void pi4d35(machine_config &config);

	void initialize();

private:
	required_device<mips1_device_base> m_cpu;
	required_device<ram_device> m_ram;
	required_region_ptr<u16> m_eprom;
	required_device<eeprom_serial_93c56_16bit_device> m_eeprom;

	required_device<dp8573_device> m_rtc;
	required_device<pit8254_device> m_pit;
	required_device<wd33c9x_base_device> m_scsi;
	required_device<seeq8003_device> m_enet;
	required_device_array<z80scc_device, 3> m_duart;
	required_device_array<rs232_port_device, 4> m_serial;
	required_device<dsp56001_device> m_dsp;

	void common(machine_config &config);
	void map(address_map &map);

	template <unsigned LIO, unsigned N> void lio_interrupt(int state) { lio_interrupt(LIO, N, state); }
	void lio_interrupt(unsigned const lio, unsigned const number, int state);

	u8 m_lio_isr[2];
	u8 m_lio_imr[2];
	bool m_lio_int[2];

	//u8 m_sysid = 1; // FPPRES
	u8 m_cpuauxctl = 0;
};

void pi4d2x_state::map(address_map &map)
{
	// silence local memory
	map(0x00000000, 0x0fffffff).noprw();

	// vme address space produces bus errors by default
	map(0x10000000, 0x1effffff).rw(FUNC(pi4d2x_state::buserror_r), FUNC(pi4d2x_state::buserror_w));

	// TODO: 1 32-bit 6U VME slot
	//map(0x10000000, 0x1bffffff); // vme a32 modifier 0x09 non-privileged
	//map(0x1c000000, 0x1cffffff); // vme a24 modifier 0x3d privileged
	//map(0x1d000000, 0x1d0fffff); // vme a16 modifier 0x2d privileged
	//map(0x1d100000, 0x1d1fffff); // vme a16 modifier 0x29 non-privileged
	//map(0x1df00000, 0x1dffffff).umask32(0x0000ff00); // VME_IACK: vme interrupt acknowledge
	//map(0x1e000000, 0x1effffff); // vme a24 modifier 0x39 non-privileged

	//map(0x1f000000, 0x1fbfffff); // local I/O (duarts, timers, etc.)
	map(0x1f000000, 0x1f007fff).m(m_gfx, FUNC(sgi_gr1_device::map)).mirror(0x8000);

	map(0x1f800000, 0x1f800003).lrw8(NAME([this]() { return m_memcfg; }), NAME([this](u8 data) { m_memcfg = data; })).umask32(0xff000000);
	map(0x1f800000, 0x1f800003).r(FUNC(pi4d2x_state::sysid_r)).umask32(0x00ff0000);

	map(0x1f840000, 0x1f840003).lrw8(NAME([this]() { return m_vme_isr; }), NAME([this](u8 data) { m_vme_isr = data; })).umask32(0x000000ff);
	map(0x1f840008, 0x1f84000b).lrw8(NAME([this]() { return m_vme_imr; }), NAME([this](u8 data) { m_vme_imr = data; })).umask32(0x000000ff);

	map(0x1f880000, 0x1f880003).lrw16(
		NAME([this]() { return m_cpuctrl; }),
		[this](u16 data)
		{
			m_eeprom->di_write(BIT(data, 8));

			// reset system
			if (BIT(data, 9))
				machine().schedule_soft_reset();

			//BIT(data, 10); // enable parity checking
			//BIT(data, 11); // enable slave accesses
			//BIT(data, 12); // enable vme arbiter
			//BIT(data, 13); // write bad parity
			//BIT(data, 14); // enable watchdog timer
			//BIT(data, 15); // fast peripheral cycle

			m_cpuctrl = data;
		}, "cpuctrl_w").umask32(0x0000ffff);
	//map(0x1f8c0000, 0x1f8c0003); // lca readback trigger (b)
	map(0x1f8e0000, 0x1f8e0003).lrw8(
		NAME([this]() { return m_cpuauxctl; }),
		[this](u8 data)
		{
			// cpu leds
			m_leds[LED_HBT] = !BIT(data, 0);
			m_leds[LED_CPU] = !BIT(data, 1);
			m_leds[LED_GFX] = !BIT(data, 2);
			m_leds[LED_FPU] = !BIT(data, 3);

			// console led
			m_leds[LED_CON] = !BIT(data, 4);

			// serial eeprom chip select and clock out
			m_eeprom->cs_write(BIT(data, 5));
			m_eeprom->clk_write(BIT(data, 6));

			m_gfx->reset_w(BIT(data, 7));

			m_cpuauxctl = data;
		}, "cpuauxctl_w").umask32(0xff000000);

	map(0x1f900000, 0x1f900003).lrw16(
		NAME([this]() { return m_dmalo; }),
		[this](u16 data)
		{
			m_dmalo = data;
			m_mapindex = 0;

			m_dmaaddr = (u32(m_dmahi[m_mapindex]) << 12) | (m_dmalo & 0x0ffc);
		}, "dmalo_w").umask32(0x0000ffff);

	map(0x1f910000, 0x1f910003).lrw8(
		NAME([this]() { return m_mapindex; }),
		NAME([this](u8 data) { m_mapindex = data; })).umask32(0x000000ff);

	/*
	 * DMA address mapping table is a pair of CY7C128-35PC 2048x8 SRAMs which
	 * read/write to data bus D27-12. A10 is tied high, giving 1024 entries.
	 */
	map(0x1f920000, 0x1f920fff).lrw16(
		NAME([this](offs_t offset) { return m_dmahi[offset]; }),
		NAME([this](offs_t offset, u16 data, u16 mem_mask) { COMBINE_DATA(&m_dmahi[offset]); })).umask32(0x0000ffff);

	// emulation can ignore dma flush
	map(0x1f940000, 0x1f940003).nopw();

	map(0x1f950000, 0x1f9501ff).rw(m_enet, FUNC(am7990_device::regs_r), FUNC(am7990_device::regs_w)).umask32(0xffff0000);
	map(0x1f960000, 0x1f960003).lr8([this]() { m_enet->reset_w(1); return 0; }, "etherrdy").umask32(0xff000000);
	map(0x1f960004, 0x1f960007).lr8([this]() { m_enet->reset_w(0); return 0; }, "etherrst").umask32(0xff000000);
	//map(0x1f960008, 0x1f96000b).rw().umask32(0xff000000); // etherwait: wait state control

	map(0x1f980000, 0x1f980003).lr16(NAME([this]() { return m_lio_isr; })).umask32(0x0000ffff);
	map(0x1f980008, 0x1f98000b).lrw8(
		NAME([this]() { return m_lio_imr; }),
		[this](u8 data)
		{
			m_lio_imr = data;

			// fifo interrupt status follows line state if not enabled
			if (!BIT(m_lio_imr, LIO_FIFO))
			{
				if (m_lio_fifo)
					m_lio_isr |= (1U << LIO_FIFO);
				else
					m_lio_isr &= ~(1U << LIO_FIFO);
			}

			// update interrupt line
			bool const lio_int = ~m_lio_isr & m_lio_imr;
			if (m_lio_int ^ lio_int)
			{
				m_lio_int = lio_int;
				m_cpu->set_input_line(INPUT_LINE_IRQ1, m_lio_int);
			}
		}, "lio_imr_w").umask32(0x000000ff);

	// 1 0 a7 a6 a5 a4 a3 a2 a1 a0 1 0  lance dmahi
	// 0 0 a7 a6 a5 a4 a3 a2 a1 a0 1 0  scsi dmahi
	// 0 1 a7 a6 a5 a4 a3 a2 a1 a0 1 0  printer/audio dmahi

	// TODO: printer/audio
	//map(0x1f970000, 0x1f970003).r().umask32(0x00ff0000); // pbstat - printer byte status
	//map(0x1f9c0000, 0x1f9c0003).rw().umask32(0x0000ffff); // prdmact - dma byte count
	//map(0x1f9c0004, 0x1f9c0007).w().umask32(0x00ff0000); // aogndac - audio output gain
	//map(0x1f9c0104, 0x1f9c0107).w().umask32(0x00ff0000);
	//map(0x1f9c0204, 0x1f9c0207).r().umask32(0x00ff0000); // prdmast - dma status
	//map(0x1f9c0304, 0x1f9c0307).r().umask32(0x00ff0000); // a/dreg - a/d i/o
	//map(0x1f9d0000, 0x1f9d0003).w().umask32(?); // pchrld - reload registers
	//map(0x1f9d0004, 0x1f9d0007).rw().umask32(0x0000ffff); // prdmalo - dma low addr reg
	//map(0x1f9e0000, 0x1f9e0003).rw().umask32(0x000000ff); // mapindex - printer map index (5-bit)
	//map(0x1f9e0004, 0x1f9e0007).w().umask32(0xff000000); // dmastop
	//map(0x1f9e0008, 0x1f9e000b).w().umask32(0x000000ff); // prswack - soft ack
	//map(0x1f9e000c, 0x1f9e000f).w().umask32(0xff000000); // dmastart
	//map(0x1f9f0000, 0x1f9f0003).r().umask32(0xff000000); // prdy - turn off reset
	//map(0x1f9f0004, 0x1f9f0007).r().umask32(0xff000000); // prst - turn on reset
	//map(0x1f9f0008, 0x1f9f000b).rw().umask32(0x0000ffff); // prdmacn - dma control
	//map(0x1f9f000c, 0x1f9f000f).rw().umask32(0xffffffff); // prdmadr - dma data reg

	// HACK: pass diagnostic iom3: ioc multiplexer registers test
	map(0x1f9c0000, 0x1f9c0003).ram().umask32(0x0000ffff);
	map(0x1f9d0004, 0x1f9d0007).ram().umask32(0x0000ffff);
	map(0x1f9e0000, 0x1f9e0003).ram().umask32(0x000000ff);
	map(0x1f9f000c, 0x1f9f000f).ram().umask32(0xffffffff);

	map(0x1fa00000, 0x1fa00003).lr8([this]() { m_cpu->set_input_line(INPUT_LINE_IRQ4, 0); return 0; }, "timer1_ack").umask32(0xff000000);
	map(0x1fa20000, 0x1fa20003).lr8([this]() { m_cpu->set_input_line(INPUT_LINE_IRQ2, 0); return 0; }, "timer0_ack").umask32(0xff000000);

	map(0x1fa40000, 0x1fa40003).lr32([this]() { m_cpu->set_input_line(INPUT_LINE_IRQ5, 0); m_cpu->berr_w(0); return m_erradr; }, "erradr");

	map(0x1fa40004, 0x1fa40007).lrw32(
		[this]()
		{
			if (m_memcfg & MEMCFG_TIMERDIS)
			{
				// refresh cycle is generated every 64μs
				u64 const refreshes = (machine().time() - m_refresh_timer).as_ticks(15.625_kHz_XTAL);

				// each refresh cycle generates 4 sequential accesses
				// TODO: should the other factor be 1024 for 1M DRAM?
				return u32(m_refadr + refreshes * 4096 * 4);
			}
			else
				return m_refadr;
		}, "refadr_r",
		[this](u32 data)
		{
			m_refadr = data;
			m_refresh_timer = machine().time();
		}, "refadr_w");

	map(0x1fa40008, 0x1fa4000b).lrw32(NAME([this]() { return m_gdma_dabr; }), NAME([this](u32 data) { m_gdma_dabr = data; }));
	map(0x1fa4000c, 0x1fa4000f).lrw32(NAME([this]() { return m_gdma_bufadr; }), NAME([this](u32 data) { m_gdma_bufadr = data; }));
	map(0x1fa40010, 0x1fa40013).lrw16(NAME([this]() { return m_gdma_burst; }), NAME([this](u16 data) { m_gdma_burst = data; })).umask32(0xffff0000);
	map(0x1fa40010, 0x1fa40013).lrw16(NAME([this]() { return m_gdma_buflen; }), NAME([this](u16 data) { m_gdma_buflen = data; })).umask32(0x0000ffff);

	map(0x1fa60000, 0x1fa60003).lrw8([this]() { m_sysid |= SYSID_VMERMW; return 0; }, "vmermw_r", [this](u8 data) { m_sysid |= SYSID_VMERMW; }, "vmermw_w").umask32(0xff000000);
	//map(0x1fa60004, 0x1fa60007).rw("actpup").umask32(0xff000000); // turn on active bus pullup
	map(0x1fa60018, 0x1fa6001b).lrw8([this]() { m_sysid |= SYSID_VMEFBT; return 0; }, "vmefbon_r", [this](u8 data) { m_sysid |= SYSID_VMEFBT; }, "vmefbon_w").umask32(0xff000000);
	map(0x1fa6001c, 0x1fa6001f).lrw8([this]() { m_sysid &= ~SYSID_VMEFBT; return 0; }, "vmefbof_r", [this](u8 data) { m_sysid &= ~SYSID_VMEFBT; }, "vmefbof_w").umask32(0xff000000);
	map(0x1fa60020, 0x1fa60023).nopr(); // reload gfx dma burst/delay reg (FIXME: silenced)
	//map(0x1fa60024, 0x1fa60027).rw("enraso").umask32(0xff000000); // enable ctl ras decoder

	map(0x1fa80000, 0x1fa80003).lr8([this]() { m_scsi->reset_w(0); return 0; }, "scsirdy").umask32(0xff000000);
	map(0x1fa80004, 0x1fa80007).lr8([this]() { m_scsi->reset_w(1); return 0; }, "scsirst").umask32(0xff000000);
	map(0x1fa80008, 0x1fa8000b).lr8([]() { return 0; }, "scsibstat").umask32(0x00ff0000);

	// TODO: IOC2 configuration register, bus error on IOC1
	//map(0x1fa80008, 0x1fa8000b).rw(FUNC(pi4d2x_state::buserror_r), FUNC(pi4d2x_state::buserror_w));

	map(0x1faa0000, 0x1faa0003).lrw8([this](offs_t offset) { m_parerr &= ~(PARERR_BYTE | (1 << offset)); return 0; }, "clrerr_r", [this](offs_t offset) { m_parerr &= ~(PARERR_BYTE | (1 << offset)); }, "clrerr_w");
	map(0x1faa0004, 0x1faa0007).lr8(NAME([this]() { return m_parerr; })).umask32(0x00ff0000);

	map(0x1fac0000, 0x1fac0003).lrw8([this]() { lio_interrupt<LIO_VR>(1); return 0; }, "vrrst_r", [this](u8 data) { lio_interrupt<LIO_VR>(1); }, "vrrst_w").umask32(0xff000000);

	map(0x1fb00000, 0x1fb00003).rw(m_scsi, FUNC(wd33c93_device::indir_addr_r), FUNC(wd33c93_device::indir_addr_w)).umask32(0x00ff0000);
	map(0x1fb00100, 0x1fb00103).rw(m_scsi, FUNC(wd33c93_device::indir_reg_r), FUNC(wd33c93_device::indir_reg_w)).umask32(0x00ff0000);

	map(0x1fb40000, 0x1fb4000f).rw(m_pit, FUNC(pit8254_device::read), FUNC(pit8254_device::write)).umask32(0xff000000);

	map(0x1fb80000, 0x1fb800ff).lrw8(
		NAME([this](offs_t offset) { return m_duart[BIT(offset, 0)]->read(offset >> 2); }),
		NAME([this](offs_t offset, u8 data) { m_duart[BIT(offset, 0)]->write(offset >> 2, data); })).umask32(0xff000000);

	map(0x1fbc0000, 0x1fbc007f).rw(m_rtc, FUNC(dp8573_device::read), FUNC(dp8573_device::write)).umask32(0xff000000);

	map(0x1fc00000, 0x1fc3ffff).rom().region("boot", 0);

	// unused memory address space produces bus errors
	map(0x40000000, 0xffffffff).rw(FUNC(pi4d2x_state::buserror_r), FUNC(pi4d2x_state::buserror_w));
}

void pi4d3x_state::map(address_map &map)
{

	//map(0x1fa00000, 0x1fa00003).noprw().umask32(0xffff0000); // CPUCTRL
	// RSTCONFIG
	//map(0x1fa00008, 0x1fa0000b).lr8([this](){ return m_sysid; }, "sysid").umask32(0xff000000);
	// MEMCFG0
	// MEMCFG1
	// REFTIM
	// PARERR
	//map(0x1fa10210, 0x1fa10213).nopw(); // CLERERR

	map(0x1fb80000, 0x1fb800bf).ram(); // FIXME: stub out ethernet, scsi and parallel registers

	map(0x1fb80100, 0x1fb8011f).m(m_enet, FUNC(seeq8003_device::map)).umask32(0x000000ff);

	map(0x1fb80120, 0x1fb80123).rw(m_scsi, FUNC(wd33c93_device::indir_addr_r), FUNC(wd33c93_device::indir_addr_w)).umask32(0x0000ff00);
	map(0x1fb80124, 0x1fb80127).rw(m_scsi, FUNC(wd33c93_device::indir_reg_r), FUNC(wd33c93_device::indir_reg_w)).umask32(0x0000ff00);

	map(0x1fb80180, 0x1fb801bb).ram(); // FIXME: stub out pbus registers
	map(0x1fb801bc, 0x1fb801bf).lrw8(
		[this]()
		{
			u8 data = m_cpuauxctl & ~0x10;

			// serial eeprom data in
			if (m_eeprom->do_read())
				data |= 0x10;

			return data;
		}, "cpu_aux_ctrl_r",
		[this](u8 data)
		{
			// console LED / protection register enable (PRE)
			//m_leds[LED_CON] = BIT(data, 0);

			// serial eeprom chip select, clock and data out
			m_eeprom->cs_write(BIT(data, 1));
			m_eeprom->clk_write(BIT(data, 2));
			m_eeprom->di_write(BIT(data, 3));

			m_cpuauxctl = data;
		}, "cpu_aux_ctrl_w").umask32(0x000000ff);

	map(0x1fb801c0, 0x1fb801c3).lr8(NAME([this]() { return m_lio_isr[0]; })).umask32(0x000000ff);
	map(0x1fb801c4, 0x1fb801c7).lrw8(
		NAME([this]() { return m_lio_imr[0]; }),
		[this](u8 data)
		{
			m_lio_imr[0] = data;

			// update interrupt line
			bool const lio_int = m_lio_isr[0] & m_lio_imr[0];
			if (m_lio_int[0] ^ lio_int)
			{
				m_lio_int[0] = lio_int;
				m_cpu->set_input_line(INPUT_LINE_IRQ1, lio_int);
			}
		}, "lio0_imr_w").umask32(0x000000ff);

	map(0x1fb801c8, 0x1fb801cb).lr8(NAME([this]() { return m_lio_isr[1]; })).umask32(0x000000ff);
	map(0x1fb801cc, 0x1fb801cf).lrw8(
		NAME([this]() { return m_lio_imr[1]; }),
		[this](u8 data)
		{
			m_lio_imr[1] = data;

			// update interrupt line
			bool const lio_int = m_lio_isr[1] & m_lio_imr[1];
			if (m_lio_int[1] ^ lio_int)
			{
				m_lio_int[1] = lio_int;
				m_cpu->set_input_line(INPUT_LINE_IRQ2, lio_int);
			}
		}, "lio1_imr_w").umask32(0x000000ff);

	map(0x1fb801d0, 0x1fb801df).ram(); // FIXME: stub out int2 registers
	map(0x1fb801e0, 0x1fb801e3).lw8(
		[this](u8 data)
		{
			// timer 0 acknowledge
			if (BIT(data, 0))
				m_cpu->set_input_line(INPUT_LINE_IRQ3, 0);

			// timer 1 acknowledge
			if (BIT(data, 1))
				m_cpu->set_input_line(INPUT_LINE_IRQ4, 0);
		}, "timer_ack").umask32(0x000000ff);
	map(0x1fb801f0, 0x1fb801ff).rw(m_pit, FUNC(pit8254_device::read), FUNC(pit8254_device::write)).umask32(0x000000ff);

	map(0x1fb80d00, 0x1fb80d0f).rw(m_duart[0], FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask32(0x000000ff);
	map(0x1fb80d10, 0x1fb80d1f).rw(m_duart[1], FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask32(0x000000ff);
	map(0x1fb80d20, 0x1fb80d2f).rw(m_duart[2], FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask32(0x000000ff);

	map(0x1fb80e00, 0x1fb80e7f).rw(m_rtc, FUNC(dp8573_device::read), FUNC(dp8573_device::write)).umask32(0x000000ff);

	map(0x1fbe0000, 0x1fbfffff).ram().share("dsp_sram"); // 3xTC55328J-25 32KiB CMOS static RAM

	map(0x1fbd0000, 0x1fbd0003).nopr(); // FIXME: board revision register

	map(0x1fc00000, 0x1fc7ffff).lr16([this](offs_t offset) { return m_eprom[offset]; }, "boot");
}

static void scsi_devices(device_slot_interface &device)
{
	device.option_add("cdrom", NSCSI_CDROM_SGI).machine_config(
		[](device_t *device)
		{
			downcast<nscsi_cdrom_device &>(*device).set_block_size(512);
		});
	device.option_add("harddisk", NSCSI_HARDDISK);
}

void pi4d2x_state::pi4d20(machine_config &config)
{
	R3000(config, m_cpu, 25_MHz_XTAL / 2, 16384, 8192);
	m_cpu->set_fpu(mips1_device_base::MIPS_R3010);

	common(config);
}

void pi4d2x_state::pi4d25(machine_config &config)
{
	R3000(config, m_cpu, 20_MHz_XTAL, 32768, 65536);
	m_cpu->set_fpu(mips1_device_base::MIPS_R3010);

	common(config);
}

void pi4d3x_state::pi4d30(machine_config &config)
{
	R3000A(config, m_cpu, 30_MHz_XTAL, 65536, 65536);
	m_cpu->set_fpu(mips1_device_base::MIPS_R3010A);

	common(config);
}

void pi4d3x_state::pi4d35(machine_config &config)
{
	R3000A(config, m_cpu, 36_MHz_XTAL, 65536, 65536);
	m_cpu->set_fpu(mips1_device_base::MIPS_R3010A);

	common(config);
}

void pi4d2x_state::common(machine_config &config)
{
	m_cpu->set_endianness(ENDIANNESS_BIG);
	m_cpu->set_addrmap(AS_PROGRAM, &pi4d2x_state::map);
	m_cpu->in_brcond<0>().set([]() { return 1; }); // writeback complete

	// 16 SIMM slots with 1, 2? or 4MB SIMMs installed in sets of 4
	RAM(config, m_ram);
	m_ram->set_default_size("16M");
	m_ram->set_extra_options("4M,8M,12M,32M,48M,64M");
	m_ram->set_default_value(0);

	EEPROM_93C56_16BIT(config, m_eeprom);

	DP8573(config, m_rtc); // DP8572AN

	PIT8254(config, m_pit);
	m_pit->set_clk<2>(3.6864_MHz_XTAL);
	m_pit->out_handler<0>().set([this](int state) { if (state) m_cpu->set_input_line(INPUT_LINE_IRQ2, 1); });
	m_pit->out_handler<1>().set([this](int state) { if (state) m_cpu->set_input_line(INPUT_LINE_IRQ4, 1); });
	m_pit->out_handler<2>().set(m_pit, FUNC(pit8254_device::write_clk0));
	m_pit->out_handler<2>().append(m_pit, FUNC(pit8254_device::write_clk1));

	NSCSI_BUS(config, "scsi");
	NSCSI_CONNECTOR(config, "scsi:0").option_set("wd33c93", WD33C93).machine_config(
		[this](device_t *device)
		{
			wd33c9x_base_device &wd33c93(downcast<wd33c9x_base_device &>(*device));

			wd33c93.set_clock(10000000);
			wd33c93.irq_cb().set(*this, FUNC(pi4d2x_state::lio_interrupt<LIO_SCSI>)).invert();
			wd33c93.drq_cb().set(*this, FUNC(pi4d2x_state::scsi_drq));
		});
	NSCSI_CONNECTOR(config, "scsi:1", scsi_devices, "harddisk", false);
	NSCSI_CONNECTOR(config, "scsi:2", scsi_devices, nullptr, false);
	NSCSI_CONNECTOR(config, "scsi:3", scsi_devices, nullptr, false);
	NSCSI_CONNECTOR(config, "scsi:4", scsi_devices, nullptr, false);
	NSCSI_CONNECTOR(config, "scsi:5", scsi_devices, nullptr, false);
	NSCSI_CONNECTOR(config, "scsi:6", scsi_devices, "cdrom", false);
	NSCSI_CONNECTOR(config, "scsi:7", scsi_devices, nullptr, false);

	AM7990(config, m_enet);
	m_enet->intr_out().set(FUNC(pi4d2x_state::lio_interrupt<LIO_ENET>));
	m_enet->dma_in().set(
		[this](offs_t offset)
		{
			unsigned const page = 0x200 + ((offset >> 12) & 0xff);
			u32 const address = (u32(m_dmahi[page]) << 12) | (offset & 0xfff);

			return m_cpu->space(0).read_word(address);
		});
	m_enet->dma_out().set(
		[this](offs_t offset, u16 data, u16 mem_mask)
		{
			unsigned const page = 0x200 + ((offset >> 12) & 0xff);
			u32 const address = (u32(m_dmahi[page]) << 12) | (offset & 0xfff);

			m_cpu->space(0).write_word(address, data, mem_mask);
		});

	// duart 0 (keyboard/mouse)
	SCN2681(config, m_duart[0], 3.6864_MHz_XTAL); // SCN2681AC1N24
	sgi_keyboard_port_device &keyboard_port(SGIKBD_PORT(config, "keyboard_port", default_sgi_keyboard_devices, "hlekbd"));
	rs232_port_device &mouse_port(RS232_PORT(config, "mouse_port",
		[](device_slot_interface &device)
		{
			device.option_add("mouse", SGI_HLE_SERIAL_MOUSE);
		},
		"mouse"));

	// duart 0 outputs
	m_duart[0]->irq_cb().set(FUNC(pi4d2x_state::lio_interrupt<LIO_D0>)).invert();
	m_duart[0]->a_tx_cb().set(keyboard_port, FUNC(sgi_keyboard_port_device::write_txd));
	m_duart[0]->b_tx_cb().set(mouse_port, FUNC(rs232_port_device::write_txd));

	// duart 0 inputs
	keyboard_port.rxd_handler().set(m_duart[0], FUNC(scn2681_device::rx_a_w));
	mouse_port.rxd_handler().set(m_duart[0], FUNC(scn2681_device::rx_b_w));

	// duart 1 (serial ports)
	SCN2681(config, m_duart[1], 3.6864_MHz_XTAL); // SCN2681AC1N40
	RS232_PORT(config, m_serial[0], default_rs232_devices, nullptr);
	RS232_PORT(config, m_serial[1], default_rs232_devices, nullptr);

	// duart 1 outputs
	m_duart[1]->irq_cb().set(FUNC(pi4d2x_state::lio_interrupt<LIO_D1>)).invert();
	m_duart[1]->a_tx_cb().set(m_serial[0], FUNC(rs232_port_device::write_txd));
	m_duart[1]->b_tx_cb().set(m_serial[1], FUNC(rs232_port_device::write_txd));
	m_duart[1]->outport_cb().set(
		[this](u8 data)
		{
			m_serial[0]->write_rts(BIT(data, 0));
			m_serial[1]->write_rts(BIT(data, 1));
			m_duart[1]->ip5_w(BIT(data, 3));
			m_duart[1]->ip6_w(BIT(data, 3));
			m_serial[0]->write_dtr(BIT(data, 4));
			m_serial[1]->write_dtr(BIT(data, 5));
		});

	// duart 1 inputs
	m_serial[0]->rxd_handler().set(m_duart[1], FUNC(scn2681_device::rx_a_w));
	m_serial[0]->cts_handler().set(m_duart[1], FUNC(scn2681_device::ip0_w));
	m_serial[0]->dcd_handler().set(m_duart[1], FUNC(scn2681_device::ip3_w));

	m_serial[1]->rxd_handler().set(m_duart[1], FUNC(scn2681_device::rx_b_w));
	m_serial[1]->cts_handler().set(m_duart[1], FUNC(scn2681_device::ip1_w));
	m_serial[1]->dcd_handler().set(m_duart[1], FUNC(scn2681_device::ip2_w));

	// graphics
	SGI_GR1(config, m_gfx);
	m_gfx->out_vblank().set(
		[this](int state)
		{
			if (state)
			{
				m_lio_isr &= ~(1U << LIO_VRSTAT);
				lio_interrupt<LIO_VR>(0);
			}
			else
				m_lio_isr |= (1U << LIO_VRSTAT);
		});
	m_gfx->out_int().set(*this, FUNC(pi4d2x_state::lio_interrupt<LIO_GE>)).invert();
	m_gfx->out_int_fifo().set(*this, FUNC(pi4d2x_state::lio_interrupt<LIO_FIFO>)).invert();

	// TODO: vme slot, cpu interrupt 0
}

void pi4d3x_state::common(machine_config &config)
{
	m_cpu->set_endianness(ENDIANNESS_BIG);
	m_cpu->set_addrmap(AS_PROGRAM, &pi4d3x_state::map);
	m_cpu->in_brcond<0>().set([]() { return 1; }); // writeback complete

	RAM(config, m_ram);
	m_ram->set_default_size("16M");
	m_ram->set_extra_options("8M,32M,64M,128M");
	m_ram->set_default_value(0);

	EEPROM_93C56_16BIT(config, m_eeprom);

	DP8573(config, m_rtc); // DP8572AV

	// 1: local0
	// 2: local1
	// 3: 8254.0
	// 4: 8254.1
	// int 7, 11 -> mappable?
	// level < 8 -> local0
	// level < 16 -> local1
	// level < 24 -> map0
	// level < 32 -> map1

	// FIXME: part of INT2 asic
	PIT8254(config, m_pit);
	m_pit->set_clk<2>(1_MHz_XTAL);
	m_pit->out_handler<0>().set([this](int state) { if (state) m_cpu->set_input_line(INPUT_LINE_IRQ3, 1); });
	m_pit->out_handler<1>().set([this](int state) { if (state) m_cpu->set_input_line(INPUT_LINE_IRQ4, 1); });
	m_pit->out_handler<2>().set(m_pit, FUNC(pit8254_device::write_clk0));
	m_pit->out_handler<2>().append(m_pit, FUNC(pit8254_device::write_clk1));

	NSCSI_BUS(config, "scsi");
	NSCSI_CONNECTOR(config, "scsi:0").option_set("wd33c93a", WD33C93A).machine_config(
		[this](device_t *device)
		{
			wd33c9x_base_device &wd33c93(downcast<wd33c9x_base_device &>(*device));

			wd33c93.set_clock(10'000'000);
			wd33c93.irq_cb().set(*this, &pi4d3x_state::lio_interrupt<0, 2>, "lio0.2");
			//wd33c93.drq_cb().set(*this, FUNC(pi4d2x_state::scsi_drq));
		});
	NSCSI_CONNECTOR(config, "scsi:1", scsi_devices, "harddisk", false);
	NSCSI_CONNECTOR(config, "scsi:2", scsi_devices, nullptr, false);
	NSCSI_CONNECTOR(config, "scsi:3", scsi_devices, nullptr, false);
	NSCSI_CONNECTOR(config, "scsi:4", scsi_devices, nullptr, false);
	NSCSI_CONNECTOR(config, "scsi:5", scsi_devices, nullptr, false);
	NSCSI_CONNECTOR(config, "scsi:6", scsi_devices, nullptr, false);
	NSCSI_CONNECTOR(config, "scsi:7", scsi_devices, nullptr, false);

	SEEQ8003(config, m_enet, 0);
	m_enet->out_int_cb().set(&pi4d3x_state::lio_interrupt<0, 3>, "lio0.3");

	input_merger_device &duart_int(INPUT_MERGER_ANY_HIGH(config, "duart_int"));
	duart_int.output_handler().set(&pi4d3x_state::lio_interrupt<0, 5>, "lio0.5");

	// duart 0: keyboard/mouse
	SCC85C30(config, m_duart[0], 10_MHz_XTAL); // Z8513010VSC ESCC
	m_duart[0]->out_int_callback().set(duart_int, FUNC(input_merger_device::in_w<0>));

	// keyboard
	sgi_keyboard_port_device &keyboard_port(SGIKBD_PORT(config, "keyboard_port", default_sgi_keyboard_devices, "hlekbd"));
	m_duart[0]->out_txdb_callback().set(keyboard_port, FUNC(sgi_keyboard_port_device::write_txd));
	keyboard_port.rxd_handler().set(m_duart[0], FUNC(z80scc_device::rxb_w));

	// mouse
	rs232_port_device &mouse_port(RS232_PORT(config, "mouse_port",
		[](device_slot_interface &device)
		{
			device.option_add("mouse", SGI_HLE_SERIAL_MOUSE);
		},
		"mouse"));
	m_duart[0]->out_txda_callback().set(mouse_port, FUNC(rs232_port_device::write_txd));
	mouse_port.rxd_handler().set(m_duart[0], FUNC(z80scc_device::rxa_w));

	// duart 1: serial ports
	SCC85C30(config, m_duart[1], 10_MHz_XTAL); // Z8513010VSC ESCC
	m_duart[1]->configure_channels(3'686'400, 0, 3'686'400, 0);
	m_duart[1]->out_int_callback().set(duart_int, FUNC(input_merger_device::in_w<1>));

	// serial port 1
	RS232_PORT(config, m_serial[0], default_rs232_devices, nullptr);
	m_duart[1]->out_dtra_callback().set(m_serial[0], FUNC(rs232_port_device::write_dtr));
	m_duart[1]->out_rtsa_callback().set(m_serial[0], FUNC(rs232_port_device::write_rts));
	m_duart[1]->out_txda_callback().set(m_serial[0], FUNC(rs232_port_device::write_txd));
	m_serial[0]->cts_handler().set(m_duart[1], FUNC(z80scc_device::ctsa_w));
	m_serial[0]->dcd_handler().set(m_duart[1], FUNC(z80scc_device::dcda_w));
	m_serial[0]->rxd_handler().set(m_duart[1], FUNC(z80scc_device::rxa_w));

	// serial port 2
	RS232_PORT(config, m_serial[1], default_rs232_devices, "terminal");
	m_duart[1]->out_dtrb_callback().set(m_serial[1], FUNC(rs232_port_device::write_dtr));
	m_duart[1]->out_rtsb_callback().set(m_serial[1], FUNC(rs232_port_device::write_rts));
	m_duart[1]->out_txdb_callback().set(m_serial[1], FUNC(rs232_port_device::write_txd));
	m_serial[1]->cts_handler().set(m_duart[1], FUNC(z80scc_device::ctsb_w));
	m_serial[1]->dcd_handler().set(m_duart[1], FUNC(z80scc_device::dcdb_w));
	m_serial[1]->rxd_handler().set(m_duart[1], FUNC(z80scc_device::rxb_w));

	// duart 2: "Apple" RS-422 serial ports
	SCC85C30(config, m_duart[2], 10_MHz_XTAL); // Z8513010VSC ESCC
	m_duart[2]->out_int_callback().set(duart_int, FUNC(input_merger_device::in_w<2>));

	// serial port 3
	// FIXME: HSKO/HSKI/GPI
	RS232_PORT(config, m_serial[2], default_rs232_devices, nullptr);
	m_duart[2]->out_txda_callback().set(m_serial[2], FUNC(rs232_port_device::write_txd));
	m_serial[2]->rxd_handler().set(m_duart[2], FUNC(z80scc_device::rxa_w));

	// serial port 4
	// FIXME: HSKO/HSKI/GPI
	RS232_PORT(config, m_serial[3], default_rs232_devices, nullptr);
	m_duart[2]->out_txdb_callback().set(m_serial[3], FUNC(rs232_port_device::write_txd));
	m_serial[3]->rxd_handler().set(m_duart[2], FUNC(z80scc_device::rxb_w));

	DSP56001(config, m_dsp, 20_MHz_XTAL);
}

void pi4d2x_state::initialize()
{
	// map the configured ram
	m_cpu->space(0).install_ram(0x00000000, m_ram->mask(), m_ram->pointer());

	m_memcfg = 0;
	m_sysid = 0;

	m_lio_isr = 0x3ff;
	m_lio_imr = 0;
	m_lio_int = false;

	m_refresh_timer = machine().time();

	m_dmahi = make_unique_clear<u16 []>(2048);

	m_leds.resolve();
}

void pi4d3x_state::initialize()
{
	// map the configured ram
	m_cpu->space(0).install_ram(0x00000000, m_ram->mask(), m_ram->pointer());
}

void pi4d2x_state::lio_interrupt(unsigned number, int state)
{
	u16 const mask = 1 << number;

	if (number == LIO_FIFO)
	{
		m_lio_fifo = state;

		// special handling for enabled fifo interrupt
		if ((m_lio_imr & mask) && !(m_lio_isr & mask))
			return;
	}

	// record interrupt state
	if (state)
		m_lio_isr |= mask;
	else
		m_lio_isr &= ~mask;

	// update interrupt line
	bool const lio_int = ~m_lio_isr & m_lio_imr;
	if (m_lio_int ^ lio_int)
	{
		m_lio_int = lio_int;
		m_cpu->set_input_line(INPUT_LINE_IRQ1, m_lio_int);
	}
}

void pi4d3x_state::lio_interrupt(unsigned const lio, unsigned const number, int state)
{
	u8 const mask = 1 << number;

	// record interrupt state
	if (state)
		m_lio_isr[lio] |= mask;
	else
		m_lio_isr[lio] &= ~mask;

	// update interrupt line
	bool const lio_int = m_lio_isr[lio] & m_lio_imr[lio];
	if (m_lio_int[lio] ^ lio_int)
	{
		m_lio_int[lio] = lio_int;

		m_cpu->set_input_line(lio ? INPUT_LINE_IRQ2 : INPUT_LINE_IRQ1, lio_int);
	}
}

void pi4d2x_state::scsi_drq(int state)
{
	if (state)
	{
		if (m_dmalo & 0x8000)
			m_cpu->space(0).write_byte(m_dmaaddr++, m_scsi->dma_r());
		else
			m_scsi->dma_w(m_cpu->space(0).read_byte(m_dmaaddr++));

		if (!(m_dmaaddr & 0xfff))
			m_dmaaddr = u32(m_dmahi[++m_mapindex]) << 12;
	}
}

u8 pi4d2x_state::sysid_r()
{
	u8 data = m_sysid;

	if (m_eeprom->do_read())
		data |= SYSID_SERDATA;

	return data;
}

ROM_START(4d20)
	ROM_REGION32_BE(0x40000, "boot", 0)
	ROM_SYSTEM_BIOS(0, "3.1c", "Version 4D1-3.1 Rev C, Tue Jan 10 15:11:42 PST 1989 SGI")
	ROMX_LOAD("070_8000_005_boot_0.h1c5", 0x000000, 0x010000, CRC(c7a182de) SHA1(56038f54b5a3254960ad7c8232f1a7cf058b9ead), ROM_BIOS(0) | ROM_SKIP(3))
	ROMX_LOAD("070_8000_005_boot_1.h1d2", 0x000001, 0x010000, CRC(4b1395f5) SHA1(926f3172b79ebaf7040ff04b0cfdc3d48d03293c), ROM_BIOS(0) | ROM_SKIP(3))
	ROMX_LOAD("070_8000_005_boot_2.h1d9", 0x000002, 0x010000, CRC(e0a55120) SHA1(0b675489ea94bf85a5a0e5f0ebf0c0b7ff5fc389), ROM_BIOS(0) | ROM_SKIP(3))
	ROMX_LOAD("070_8000_005_boot_3.h1e6", 0x000003, 0x010000, CRC(11536526) SHA1(5149f453347ae566e9fee4447615dff88c7f6a37), ROM_BIOS(0) | ROM_SKIP(3))

	// this firmware has been found in both 4D/20 and 4D/25 hardware
	ROM_SYSTEM_BIOS(1, "3.2e", "Version 3.2 Rev E, Fri Jul 14 14:37:38 PDT 1989 SGI")
	ROMX_LOAD("070_8000_007_boot_0.h1c5", 0x000000, 0x010000, CRC(e448b865) SHA1(f0276b76360ea0b3250dbdaa7a1e57ea8f6144d6), ROM_BIOS(1) | ROM_SKIP(3))
	ROMX_LOAD("070_8000_007_boot_1.h1d2", 0x000001, 0x010000, CRC(59fda717) SHA1(ef3ccb1f8a815e7b13c79deeea0d73006deed09f), ROM_BIOS(1) | ROM_SKIP(3))
	ROMX_LOAD("070_8000_007_boot_2.h1d9", 0x000002, 0x010000, CRC(569146ad) SHA1(5442a13ed93afdaa55c1951b97e335cf60dde834), ROM_BIOS(1) | ROM_SKIP(3))
	ROMX_LOAD("070_8000_007_boot_3.h1e6", 0x000003, 0x010000, CRC(682977c3) SHA1(d9bcf7cdc5caef4221929fe26eccf34253fa7f29), ROM_BIOS(1) | ROM_SKIP(3))
ROM_END

ROM_START(4d25)
	ROM_REGION32_BE(0x40000, "boot", 0)
	ROM_SYSTEM_BIOS(0, "3.2e", "Version 3.2 Rev E, Fri Jul 14 14:37:38 PDT 1989 SGI")
	ROMX_LOAD("070_8000_007_boot_0.h1c5", 0x000000, 0x010000, CRC(e448b865) SHA1(f0276b76360ea0b3250dbdaa7a1e57ea8f6144d6), ROM_BIOS(0) | ROM_SKIP(3))
	ROMX_LOAD("070_8000_007_boot_1.h1d2", 0x000001, 0x010000, CRC(59fda717) SHA1(ef3ccb1f8a815e7b13c79deeea0d73006deed09f), ROM_BIOS(0) | ROM_SKIP(3))
	ROMX_LOAD("070_8000_007_boot_2.h1d9", 0x000002, 0x010000, CRC(569146ad) SHA1(5442a13ed93afdaa55c1951b97e335cf60dde834), ROM_BIOS(0) | ROM_SKIP(3))
	ROMX_LOAD("070_8000_007_boot_3.h1e6", 0x000003, 0x010000, CRC(682977c3) SHA1(d9bcf7cdc5caef4221929fe26eccf34253fa7f29), ROM_BIOS(0) | ROM_SKIP(3))
ROM_END

ROM_START(4d30)
	ROM_REGION16_BE(0x80000, "boot", 0)
	ROM_SYSTEM_BIOS(0, "4.0.1c", "SGI Version 4.0.1 Rev C GR1/GR2/LG1,  Feb 14, 1992")
	ROMX_LOAD("ip14prom.bin", 0x000000, 0x080000, NO_DUMP, ROM_BIOS(0))
ROM_END

ROM_START(4d35)
	ROM_REGION16_BE(0x80000, "boot", 0) // TC574096D-120 (262,144x16-bit EEPROM)

	ROM_SYSTEM_BIOS(0, "4.0.1d", "SGI Version 4.0.1 Rev D LG1/GR2,  Mar 24, 1992")
	ROMX_LOAD("ip12prom.002be.u61", 0x000000, 0x040000, CRC(d35f105c) SHA1(3d08dfb961d7512bd8ed41cb6e01e89d14134f09), ROM_BIOS(0))

	ROM_SYSTEM_BIOS(1, "4.0.1c", "SGI Version 4.0.1 Rev C GR1/GR2/LG1,  Feb 14, 1992")
	ROMX_LOAD("ip12prom.070-8086-002.u61", 0x000000, 0x080000, CRC(543cfc3f) SHA1(a7331876f11bff40c960f822923503eca17191c5), ROM_BIOS(1))

	ROM_SYSTEM_BIOS(2, "4.0a", "SGI Version 4.0 Rev A IP12,  Aug 22, 1991")
	ROMX_LOAD("ip12prom.070-8045-002.u61", 0x000000, 0x040000, CRC(fe999bae) SHA1(eb054c365a6e018be3b9ae44169c0ffc6447c6f0), ROM_BIOS(2))
ROM_END

//   YEAR  NAME  PARENT  COMPAT  MACHINE  INPUT  CLASS         INIT        COMPANY                 FULLNAME                FLAGS
COMP(1988, 4d20, 0,      0,      pi4d20,  0,     pi4d2x_state, initialize, "Silicon Graphics Inc", "Personal IRIS 4D/20",  MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP(1989, 4d25, 0,      0,      pi4d25,  0,     pi4d2x_state, initialize, "Silicon Graphics Inc", "Personal IRIS 4D/25",  MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP(1991, 4d30, 0,      0,      pi4d30,  0,     pi4d3x_state, initialize, "Silicon Graphics Inc", "Personal IRIS 4D/30",  MACHINE_NOT_WORKING | MACHINE_NO_SOUND)
COMP(1991, 4d35, 0,      0,      pi4d35,  0,     pi4d3x_state, initialize, "Silicon Graphics Inc", "Personal IRIS 4D/35",  MACHINE_NOT_WORKING | MACHINE_NO_SOUND)