diff --git a/src/mame/mame.lst b/src/mame/mame.lst index e8e57aa5f83..dd3bb1fcb71 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -40718,25 +40718,28 @@ tim011 // @source:sfrj/tim100.cpp tim100 // -@source:sgi/4dpi.cpp -4d20 // IP6: Personal Iris 4D/20, R2000 @12.5MHz -4d25 // IP10: Personal Iris 4D/25, R3000 @20MHz -4d30 // IP14: Personal Iris 4D/30, R3000A @30MHz -4d35 // IP12: Personal Iris 4D/35, R3000A @36MHz - @source:sgi/crimson.cpp crimson // (c) 1992 SGI -@source:sgi/indigo.cpp -indigo3k // IP12: Indigo 1, R3000, 33MHz -indigo4k // IP20: Indigo 1, R4400, 150MHz - @source:sgi/indy_indigo2.cpp indy_4610 // IP22: Indy, R4600, 100MHz indy_4613 // IP22: Indy, R4600, 133MHz indy_5015 // IP22: Indy, R5000, 150MHz indigo2_4415 // IP24: Indigo 2, R4400, 150MHz +@source:sgi/ip6.cpp +pi4d20 // Personal IRIS 4D/20 (R2000 @ 12.5MHz) +pi4d25 // Personal IRIS 4D/25 (R3000 @ 20MHz) + +@source:sgi/ip12.cpp +pi4d30 // Personal IRIS 4D/30 (R3000A @ 30MHz) +pi4d35 // Personal IRIS 4D/35 (R3000A @ 36MHz) +indigo // IRIS Indigo HP1 (R3000A @ 33MHz) + +@source:sgi/ip20.cpp +indigo_r4000 // Indigo HP2, PM1 (R4000 @ 100MHz) +indigo_r4400 // Indigo HP2, PM2 (R4400 @ 150MHz) + @source:sgi/iris3130.cpp iris3130 // IP2: IRIS 3xx0, 68020, 16MHz diff --git a/src/mame/sgi/hpc1.cpp b/src/mame/sgi/hpc1.cpp index fa982d28c4b..c14d3ce75bb 100644 --- a/src/mame/sgi/hpc1.cpp +++ b/src/mame/sgi/hpc1.cpp @@ -1,680 +1,555 @@ // license:BSD-3-Clause // copyright-holders:Ryan Holtz -/********************************************************************** - SGI HPC1 "High-performance Peripheral Controller" emulation - -**********************************************************************/ +/* + * Silicon Graphics High Performance Peripheral Controller (HPC1). + * + * TODO: + * - hpc1.5 (second-generation, includes little-endian support) + * - clean up ethernet interface, interrupt delay + * - pbus and dsp + */ #include "emu.h" -#include "cpu/mips/mips3.h" -#include "bus/rs232/rs232.h" -#include "bus/rs232/hlemouse.h" -#include "machine/nscsi_bus.h" -#include "bus/nscsi/cd.h" -#include "bus/nscsi/hd.h" -#include "kbd.h" #include "hpc1.h" -#include "speaker.h" -#define LOG_UNKNOWN (1U << 1) -#define LOG_READS (1U << 2) -#define LOG_WRITES (1U << 3) -#define LOG_INT (1U << 4) -#define LOG_EEPROM (1U << 5) -#define LOG_SCSI (1U << 6) -#define LOG_SCSI_DMA (1U << 7) -#define LOG_DUART0 (1U << 8) -#define LOG_DUART1 (1U << 9) -#define LOG_DUART2 (1U << 10) -#define LOG_PIT (1U << 11) -#define LOG_CHAIN (1U << 12) -#define LOG_REGS (LOG_UNKNOWN | LOG_READS | LOG_WRITES) -#define LOG_DUART (LOG_DUART0 | LOG_DUART1 | LOG_DUART2) -#define LOG_ALL (LOG_REGS | LOG_INT | LOG_EEPROM | LOG_SCSI | LOG_SCSI_DMA | LOG_DUART | LOG_PIT | LOG_CHAIN) +#define LOG_SCSI (1U << 1) +#define LOG_ENET (1U << 2) -#define VERBOSE (LOG_UNKNOWN) +//#define VERBOSE (LOG_SCSI | LOG_ENET) #include "logmacro.h" DEFINE_DEVICE_TYPE(SGI_HPC1, hpc1_device, "hpc1", "SGI HPC1") -/*static*/ char const *const hpc1_device::RS232A_TAG = "rs232a"; -/*static*/ char const *const hpc1_device::RS232B_TAG = "rs232b"; +enum enet_rxs_mask : u32 +{ + ENET_RXSTAT = 0x0000'bf00, // receive status + ENET_SRXDMA = 0x0000'4000, // start receiver dma +}; -/*static*/ const XTAL hpc1_device::SCC_PCLK = 10_MHz_XTAL; -/*static*/ const XTAL hpc1_device::SCC_RXA_CLK = 3.6864_MHz_XTAL; // Needs verification -/*static*/ const XTAL hpc1_device::SCC_TXA_CLK = XTAL(0); -/*static*/ const XTAL hpc1_device::SCC_RXB_CLK = 3.6864_MHz_XTAL; // Needs verification -/*static*/ const XTAL hpc1_device::SCC_TXB_CLK = XTAL(0); +enum enet_txs_mask : u32 +{ + ENET_TXSTAT = 0x00bf'0000, // transmit status + ENET_STXDMA = 0x0040'0000, // start transmitter dma +}; + +enum enet_ctrl_mask : u32 +{ + ENET_RESET = 0x01, // channel reset + ENET_CLRINT = 0x02, // interrupt pending + ENET_MODNORM = 0x04, // 0=loopback + ENET_RBO = 0x08, // receive buffer overflow +}; + +enum scsi_ctrl_mask : u32 +{ + SCSI_RESET = 0x01, + SCSI_FLUSH = 0x02, + SCSI_TO_MEM = 0x10, + SCSI_STARTDMA = 0x80, +}; + +enum scsi_cbp_mask : u32 +{ + SCSI_CBP_BUFADDR = 0x0fff'ffff, + SCSI_CBP_EOX = 0x8000'0000, +}; hpc1_device::hpc1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, SGI_HPC1, tag, owner, clock) - , m_maincpu(*this, finder_base::DUMMY_TAG) - , m_eeprom(*this, finder_base::DUMMY_TAG) - , m_wd33c93(*this, "scsibus:0:wd33c93") - , m_scc(*this, "scc%u", 0U) - , m_pit(*this, "pit") - , m_rtc(*this, "rtc") + , device_memory_interface(mconfig, *this) + , m_pbus("pbus", ENDIANNESS_BIG, 16, 20, -1, address_map_constructor(FUNC(hpc1_device::pbus_map), this)) + , m_gio(*this, finder_base::DUMMY_TAG, -1) + , m_enet(*this, finder_base::DUMMY_TAG) + , m_int_w(*this) + , m_eeprom_dati(*this, 0) + , m_dma_r(*this, 0) + , m_dma_w(*this) + , m_eeprom_out(*this) { } void hpc1_device::device_start() { - save_item(NAME(m_misc_status)); - save_item(NAME(m_cpu_aux_ctrl)); - save_item(NAME(m_parbuf_ptr)); - save_item(NAME(m_local_int_status)); - save_item(NAME(m_local_int_mask)); - save_item(NAME(m_int_status)); - save_item(NAME(m_vme_int_mask)); + save_item(NAME(m_drq)); - save_item(NAME(m_scsi_dma.m_desc)); - save_item(NAME(m_scsi_dma.m_addr)); - save_item(NAME(m_scsi_dma.m_ctrl)); - save_item(NAME(m_scsi_dma.m_length)); - save_item(NAME(m_scsi_dma.m_next)); - save_item(NAME(m_scsi_dma.m_irq)); - save_item(NAME(m_scsi_dma.m_drq)); - save_item(NAME(m_scsi_dma.m_to_mem)); - save_item(NAME(m_scsi_dma.m_active)); + save_item(NAME(m_enet_cxbp)); + save_item(NAME(m_enet_nxbdp)); + save_item(NAME(m_enet_xbc)); + save_item(NAME(m_enet_cxbdp)); + save_item(NAME(m_enet_cpfxbdp)); + save_item(NAME(m_enet_ppfxbdp)); + save_item(NAME(m_enet_intdelay)); + save_item(NAME(m_enet_txs)); + save_item(NAME(m_enet_rxs)); + save_item(NAME(m_enet_ctrl)); + save_item(NAME(m_enet_rbc)); + save_item(NAME(m_enet_crbp)); + save_item(NAME(m_enet_nrbdp)); + save_item(NAME(m_enet_crbdp)); - save_item(NAME(m_duart_int_status)); + save_item(NAME(m_scsi_bc)); + save_item(NAME(m_scsi_cbp)); + save_item(NAME(m_scsi_nbdp)); + save_item(NAME(m_scsi_ctrl)); + + save_item(NAME(m_dsp_bc)); + + save_item(NAME(m_aux)); + + m_drq = 0; } void hpc1_device::device_reset() { - m_misc_status = 0; - m_cpu_aux_ctrl = 0; - m_parbuf_ptr = 0; - memset(m_local_int_status, 0, sizeof(uint32_t) * 2); - memset(m_local_int_mask, 0, sizeof(uint32_t) * 2); - memset(m_int_status, 0, sizeof(bool) * 2); - memset(m_vme_int_mask, 0, sizeof(uint32_t) * 2); + m_enet_rxs = 0; + m_enet_txs = 0; + m_enet_ctrl = 0; - m_scsi_dma.m_desc = 0; - m_scsi_dma.m_addr = 0; - m_scsi_dma.m_ctrl = 0; - m_scsi_dma.m_length = 0; - m_scsi_dma.m_next = 0; - m_scsi_dma.m_irq = false; - m_scsi_dma.m_drq = false; - m_scsi_dma.m_to_mem = false; - m_scsi_dma.m_active = false; - - m_duart_int_status = 0; - - m_cpu_space = &m_maincpu->space(AS_PROGRAM); + m_scsi_nbdp = 0; + m_scsi_ctrl = 0; } -//************************************************************************** -// DEVICE HARDWARE -//************************************************************************** - -void hpc1_device::cdrom_config(device_t *device) +device_memory_interface::space_config_vector hpc1_device::memory_space_config() const { - // cdda_device *cdda = device->subdevice("cdda"); - // cdda->add_route(ALL_OUTPUTS, "^^mono", 1.0); + return space_config_vector{ std::make_pair(0, &m_pbus) }; } -void hpc1_device::indigo_mice(device_slot_interface &device) +void hpc1_device::map(address_map &map) { - device.option_add("sgimouse", SGI_HLE_SERIAL_MOUSE); + // xcount + map(0x000c, 0x000f).rw(FUNC(hpc1_device::cxbp_r), FUNC(hpc1_device::cxbp_w)); + map(0x0010, 0x0013).rw(FUNC(hpc1_device::nxbdp_r), FUNC(hpc1_device::nxbdp_w)); + map(0x0014, 0x0017).rw(FUNC(hpc1_device::xbc_r), FUNC(hpc1_device::xbc_w)); + // xpntr + // xfifo + map(0x0020, 0x0023).rw(FUNC(hpc1_device::cxbdp_r), FUNC(hpc1_device::cxbdp_w)); + map(0x0024, 0x0027).rw(FUNC(hpc1_device::cpfxbdp_r), FUNC(hpc1_device::cpfxbdp_w)); + map(0x0028, 0x002b).rw(FUNC(hpc1_device::ppfxbdp_r), FUNC(hpc1_device::ppfxbdp_w)); + map(0x002c, 0x002f).rw(FUNC(hpc1_device::intdelay_r), FUNC(hpc1_device::intdelay_w)); + // + map(0x0034, 0x0037).rw(FUNC(hpc1_device::trstat_r), FUNC(hpc1_device::trstat_w)); + map(0x0038, 0x003b).rw(FUNC(hpc1_device::rcvstat_r), FUNC(hpc1_device::rcvstat_w)); + map(0x003c, 0x003f).rw(FUNC(hpc1_device::ctl_r), FUNC(hpc1_device::ctl_w)); + // + // rcount + map(0x0048, 0x004b).rw(FUNC(hpc1_device::rbc_r), FUNC(hpc1_device::rbc_w)); + map(0x004c, 0x004f).rw(FUNC(hpc1_device::crbp_r), FUNC(hpc1_device::crbp_w)); + map(0x0050, 0x0053).rw(FUNC(hpc1_device::nrbdp_r), FUNC(hpc1_device::nrbdp_w)); + map(0x0054, 0x0057).rw(FUNC(hpc1_device::crbdp_r), FUNC(hpc1_device::crbdp_w)); + // rpntr + // rfifo + + //map(0x0084, 0x0087).rw(FUNC(hpc1_device::scsi_count_r), FUNC(hpc1_device::scsi_count_w)); + map(0x0088, 0x008b).rw(FUNC(hpc1_device::scsi_bc_r), FUNC(hpc1_device::scsi_bc_w)); + map(0x008c, 0x008f).rw(FUNC(hpc1_device::scsi_cbp_r), FUNC(hpc1_device::scsi_cbp_w)); + map(0x0090, 0x0093).rw(FUNC(hpc1_device::scsi_nbdp_r), FUNC(hpc1_device::scsi_nbdp_w)); + map(0x0094, 0x0097).rw(FUNC(hpc1_device::scsi_ctrl_r), FUNC(hpc1_device::scsi_ctrl_w)); + //map(0x0098, 0x009b); // scsi pointer register + //map(0x009c, 0x009f); // scsi fifo data register + + map(0x00a8, 0x00af).ram(); // parallel + //map(0x00a8, 0x00ab); // parallel byte count and ie (bc) + //map(0x00ac, 0x00af); // parallel current buf ptr (cbp) + //map(0x00b0, 0x00b3); // parallel next buffer descriptor (nbdp) + //map(0x00b4, 0x00b7); // parallel control (ctrl) + + map(0x0180, 0x01b7).ram(); // dsp interface + map(0x0180, 0x0183).rw(FUNC(hpc1_device::dsp_bc_r), FUNC(hpc1_device::dsp_bc_w)).umask32(0xffff); + + map(0x01bc, 0x01bf).rw(FUNC(hpc1_device::aux_r), FUNC(hpc1_device::aux_w)).umask32(0xff); } -void hpc1_device::scsi_devices(device_slot_interface &device) +void hpc1_device::pbus_map(address_map &map) { - device.option_add("cdrom", NSCSI_CDROM_SGI); - device.option_add("harddisk", NSCSI_HARDDISK); +/* + * Peripheral Bus (P-Bus): 20 bit address, 16-bit data + * - PROM + * - DUARTS + * - Real Time Clock + * - DSP (P-Bus master) + * - Audio SRAM + * Ethernet + * SCSI + * Parallel + * INT2 + * + * hpc1 pbus has 20 bit address space (1MB) + * 0x1fb8'0000-0x1fbf'ffff hpc i/o space (512KB) + * 0x1fc0'0000-0x1fc3'ffff hpc prom space (256KB) + * + * Indigo PROM is 256k, dsp ram is 128k + + DSP Y bus is 24 bit data, 16 bit address, word addressed + PBUS is 16 bit data, 20 bit address, word addressed + + #define HPC1DMAWDCNT 0x1fb80180 // DMA transfer size (SRAM words) + #define HPC1GIOADDL 0x1fb80184 // GIO-bus address, LSB (16 bit) + #define HPC1GIOADDM 0x1fb80188 // GIO-bus address, MSB (16 bit) + #define HPC1PBUSADD 0x1fb8018c // PBUS address (16 bit) + #define HPC1DMACTRL 0x1fb80190 // DMA Control (2 bit) + #define HPC1COUNTER 0x1fb80194 // Counter (24 bits) (ro) + #define HPC1HANDTX 0x1fb80198 // Handshake transmit (16 bit) + #define HPC1HANDRX 0x1fb8019c // Handshake receive (16 bit) + #define HPC1CINTSTAT 0x1fb801a0 // CPU Interrupt status (3 bit) + #define HPC1CINTMASK 0x1fb801a4 // CPU Interrupt masks (3 bit) + #define HPC1MISCSR 0x1fb801b0 // Misc. control and status (8 bit) + #define HPC1BURSTCTL 0x1fb801b4 // DMA Ballistics register (16 bit) + + ; DSP-HPC addresses + DSP_HPC_BYTECNT equ y:$ffe0 ; DMA transfer size + DSP_HPC_GIOADDL equ y:$ffe1 ; GIO-bus address, LSB + DSP_HPC_GIOADDM equ y:$ffe2 ; GIO-bus address, MSB + DSP_HPC_PBUSADD equ y:$ffe3 ; Pbus address + DSP_HPC_DMACTRL equ y:$ffe4 ; DMA control + DSP_HPC_HANDTX equ y:$ffe6 ; handshake transmit + DSP_HPC_HANDRX equ y:$ffe7 ; handshake receive + DSP_HPC_INTSTAT equ y:$ffe8 ; interrupt status + DSP_HPC_INTMASK equ y:$ffe9 ; interrupt mask + DSP_HPC_INTCONF equ y:$ffea ; interrupt configuration + DSP_HPC_INTPOL equ y:$ffeb ; interrupt polarity + DSP_HPC_MISCSR equ y:$ffec ; miscellaneous control and status + DSP_HPC_BURSTCTL equ y:$ffed ; dma burst control register + + # p: == x: + p:8000-8fff == x:8000-8fff + p:e000-efff == x:e000-efff + + # p: ^ 0x4000 == y: + p:8000-8fff == y:c000-cfff + 9=d + a=e + b=f + c=8 + d=9 + p:e000-efff == y:a000-afff + f=b + + HEADPHONE_MDAC_L equ y:$fffc + HEADPHONE_MDAC_R equ y:$fffd + + 32k x 24bit dsp ram + ram at c000 +*/ + map(0xffe0, 0xffe0).rw(FUNC(hpc1_device::dsp_bc_r), FUNC(hpc1_device::dsp_bc_w)); } -void hpc1_device::wd33c93(device_t *device) +void hpc1_device::scsi_nbdp_w(u32 data) { - device->set_clock(10000000); - downcast(device)->irq_cb().set(*this, FUNC(hpc1_device::scsi_irq)); - downcast(device)->drq_cb().set(*this, FUNC(hpc1_device::scsi_drq)); + LOGMASKED(LOG_SCSI, "nbdp_w 0x%08x\n", data); + m_scsi_nbdp = data & 0x0fff'ffffU; + + scsi_chain(); } -void hpc1_device::device_add_mconfig(machine_config &config) +void hpc1_device::scsi_ctrl_w(u32 data) { - SCC85C30(config, m_scc[0], SCC_PCLK); - m_scc[0]->configure_channels(SCC_RXA_CLK.value(), SCC_TXA_CLK.value(), SCC_RXB_CLK.value(), SCC_TXB_CLK.value()); - m_scc[0]->out_int_callback().set(FUNC(hpc1_device::duart0_int_w)); - m_scc[0]->out_txda_callback().set("keyboard_port", FUNC(sgi_kbd_port_device::write_txd)); + m_scsi_ctrl = data & ~(SCSI_FLUSH | SCSI_RESET); - SCC85C30(config, m_scc[1], SCC_PCLK); - m_scc[1]->configure_channels(SCC_RXA_CLK.value(), SCC_TXA_CLK.value(), SCC_RXB_CLK.value(), SCC_TXB_CLK.value()); - m_scc[1]->out_txda_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_txd)); - m_scc[1]->out_dtra_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_dtr)); - m_scc[1]->out_rtsa_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_rts)); - m_scc[1]->out_txdb_callback().set(RS232B_TAG, FUNC(rs232_port_device::write_txd)); - m_scc[1]->out_dtrb_callback().set(RS232B_TAG, FUNC(rs232_port_device::write_dtr)); - m_scc[1]->out_rtsb_callback().set(RS232B_TAG, FUNC(rs232_port_device::write_rts)); - m_scc[1]->out_int_callback().set(FUNC(hpc1_device::duart1_int_w)); - - SCC85C30(config, m_scc[2], SCC_PCLK); - m_scc[2]->configure_channels(SCC_RXA_CLK.value(), SCC_TXA_CLK.value(), SCC_RXB_CLK.value(), SCC_TXB_CLK.value()); - m_scc[2]->out_int_callback().set(FUNC(hpc1_device::duart2_int_w)); - - SGI_KBD_PORT(config, "keyboard_port", default_sgi_kbd_devices, "keyboard").rxd_handler().set(m_scc[0], FUNC(z80scc_device::rxa_w)); - - rs232_port_device &mouseport(RS232_PORT(config, "mouse_port", indigo_mice, "sgimouse")); - mouseport.set_fixed(true); - mouseport.rxd_handler().set(m_scc[0], FUNC(scc85c30_device::rxb_w)); - mouseport.cts_handler().set(m_scc[0], FUNC(scc85c30_device::ctsb_w)); - mouseport.dcd_handler().set(m_scc[0], FUNC(scc85c30_device::dcdb_w)); - - rs232_port_device &rs232a(RS232_PORT(config, RS232A_TAG, default_rs232_devices, nullptr)); - rs232a.cts_handler().set(m_scc[1], FUNC(scc85c30_device::ctsa_w)); - rs232a.dcd_handler().set(m_scc[1], FUNC(scc85c30_device::dcda_w)); - rs232a.rxd_handler().set(m_scc[1], FUNC(scc85c30_device::rxa_w)); - - rs232_port_device &rs232b(RS232_PORT(config, RS232B_TAG, default_rs232_devices, nullptr)); - rs232b.cts_handler().set(m_scc[1], FUNC(scc85c30_device::ctsb_w)); - rs232b.dcd_handler().set(m_scc[1], FUNC(scc85c30_device::dcdb_w)); - rs232b.rxd_handler().set(m_scc[1], FUNC(scc85c30_device::rxb_w)); - - NSCSI_BUS(config, "scsibus", 0); - NSCSI_CONNECTOR(config, "scsibus:0").option_set("wd33c93", WD33C93) - .machine_config([this](device_t *device) { wd33c93(device); }); - NSCSI_CONNECTOR(config, "scsibus:1", scsi_devices, "harddisk", false); - NSCSI_CONNECTOR(config, "scsibus:2", scsi_devices, nullptr, false); - NSCSI_CONNECTOR(config, "scsibus:3", scsi_devices, nullptr, false); - NSCSI_CONNECTOR(config, "scsibus:4", scsi_devices, "cdrom", false); - NSCSI_CONNECTOR(config, "scsibus:5", scsi_devices, nullptr, false); - NSCSI_CONNECTOR(config, "scsibus:6", scsi_devices, nullptr, false); - NSCSI_CONNECTOR(config, "scsibus:7", scsi_devices, nullptr, false); - - DP8572A(config, m_rtc, 32.768_kHz_XTAL).set_use_utc(true); - - PIT8254(config, m_pit, 0); - m_pit->set_clk<0>(1000000); - m_pit->set_clk<1>(1000000); - m_pit->set_clk<2>(1000000); - m_pit->out_handler<0>().set(FUNC(hpc1_device::timer0_int)); - m_pit->out_handler<1>().set(FUNC(hpc1_device::timer1_int)); - m_pit->out_handler<2>().set(FUNC(hpc1_device::timer2_int)); - - SPEAKER(config, "mono").front_center(); + if (BIT(m_drq, 0) && (m_scsi_ctrl & SCSI_STARTDMA)) + scsi_dma(); } -//************************************************************************** -// REGISTER ACCESS -//************************************************************************** - -uint32_t hpc1_device::read(offs_t offset, uint32_t mem_mask) +void hpc1_device::scsi_chain() { - if (offset >= 0x0e00/4 && offset <= 0x0e7c/4) - return m_rtc->read(offset - 0xe00/4); + u32 const bdp = m_scsi_nbdp; - switch (offset) - { - case 0x005c/4: - LOGMASKED(LOG_UNKNOWN, "%s: HPC Unknown Read: %08x & %08x\n", - machine().describe_context(), 0x1fb80000 + offset*4, mem_mask); - return 0; - case 0x0094/4: - LOGMASKED(LOG_SCSI_DMA, "%s: HPC SCSI DMA Control Register Read: %08x & %08x\n", machine().describe_context(), m_scsi_dma.m_ctrl, mem_mask); - return m_scsi_dma.m_ctrl; - case 0x00ac/4: - LOGMASKED(LOG_READS, "%s: HPC Parallel Buffer Pointer Read: %08x & %08x\n", machine().describe_context(), m_parbuf_ptr, mem_mask); - return m_parbuf_ptr; - case 0x00c0/4: - LOGMASKED(LOG_READS, "%s: HPC Endianness Read: %08x & %08x\n", machine().describe_context(), 0x00000000, mem_mask); - return 0x00000000; - case 0x0120/4: - { - uint32_t ret = m_wd33c93->indir_addr_r() << 8; - LOGMASKED(LOG_SCSI, "%s: HPC SCSI Offset 0 Read: %08x & %08x\n", machine().describe_context(), ret, mem_mask); - return ret; - } - case 0x0124/4: - { - uint32_t ret = m_wd33c93->indir_reg_r() << 8; - LOGMASKED(LOG_SCSI, "%s: HPC SCSI Offset 1 Read: %08x & %08x\n", machine().describe_context(), ret, mem_mask); - return ret; - } - case 0x01b0/4: - LOGMASKED(LOG_READS, "%s: HPC Misc. Status Read: %08x & %08x\n", machine().describe_context(), m_misc_status, mem_mask); - return m_misc_status; - case 0x01bc/4: - { - uint32_t ret = (m_cpu_aux_ctrl & ~0x10) | m_eeprom->do_read() << 4; - LOGMASKED(LOG_EEPROM, "%s: HPC Serial EEPROM Read: %08x & %08x\n", machine().describe_context(), ret, mem_mask); - return ret; - } - case 0x01c0/4: - LOGMASKED(LOG_INT, "%s: HPC Local Interrupt 0 Status Read: %08x & %08x\n", machine().describe_context(), m_local_int_status[0], mem_mask); - return m_local_int_status[0]; - case 0x01c4/4: - LOGMASKED(LOG_INT, "%s: HPC Local Interrupt 0 Mask Read: %08x & %08x\n", machine().describe_context(), m_local_int_mask[0], mem_mask); - return m_local_int_mask[0]; - case 0x01c8/4: - LOGMASKED(LOG_INT, "%s: HPC Local Interrupt 1 Status Read: %08x & %08x\n", machine().describe_context(), m_local_int_status[1], mem_mask); - return m_local_int_status[1]; - case 0x01cc/4: - LOGMASKED(LOG_INT, "%s: HPC Local Interrupt 1 Mask Read: %08x & %08x\n", machine().describe_context(), m_local_int_mask[1], mem_mask); - return m_local_int_mask[1]; - case 0x01d4/4: - LOGMASKED(LOG_INT, "%s: HPC VME Interrupt Mask 0 Read: %08x & %08x\n", machine().describe_context(), m_vme_int_mask[0], mem_mask); - return m_vme_int_mask[0]; - case 0x01d8/4: - LOGMASKED(LOG_INT, "%s: HPC VME Interrupt Mask 1 Read: %08x & %08x\n", machine().describe_context(), m_vme_int_mask[1], mem_mask); - return m_vme_int_mask[1]; - case 0x01f0/4: - { - const uint8_t data = m_pit->read(0); - LOGMASKED(LOG_PIT, "%s: Read Timer Count0 Register: %02x & %08x\n", machine().describe_context(), data, mem_mask); - return data; - } - case 0x01f4/4: - { - const uint8_t data = m_pit->read(1); - LOGMASKED(LOG_PIT, "%s: Read Timer Count1 Register: %02x & %08x\n", machine().describe_context(), data, mem_mask); - return data; - } - case 0x01f8/4: - { - const uint8_t data = m_pit->read(2); - LOGMASKED(LOG_PIT, "%s: Read Timer Count2 Register: %02x & %08x\n", machine().describe_context(), data, mem_mask); - return data; - } - case 0x01fc/4: - { - const uint8_t data = m_pit->read(3); - LOGMASKED(LOG_PIT, "%s: Read Timer Control Register: %02x & %08x\n", machine().describe_context(), data, mem_mask); - return data; - } - case 0x0d00/4: - case 0x0d10/4: - case 0x0d20/4: - { - const uint32_t index = (offset >> 2) & 3; - uint32_t ret = m_scc[index]->ab_dc_r(0); - LOGMASKED(LOG_DUART0 << index, "%s: HPC DUART%d Channel B Control Read: %08x & %08x\n", machine().describe_context(), index, ret, mem_mask); - return ret; - } - case 0x0d04/4: - case 0x0d14/4: - case 0x0d24/4: - { - const uint32_t index = (offset >> 2) & 3; - const uint32_t ret = m_scc[index]->ab_dc_r(1); - LOGMASKED(LOG_DUART0 << index, "%s: HPC DUART%d Channel B Data Read: %08x & %08x\n", machine().describe_context(), index, ret, mem_mask); - return ret; - } - case 0x0d08/4: - case 0x0d18/4: - case 0x0d28/4: - { - const uint32_t index = (offset >> 2) & 3; - const uint32_t ret = m_scc[index]->ab_dc_r(2); - LOGMASKED(LOG_DUART0 << index, "%s: HPC DUART%d Channel A Control Read: %08x & %08x\n", machine().describe_context(), index, ret, mem_mask); - return ret; - } - case 0x0d0c/4: - case 0x0d1c/4: - case 0x0d2c/4: - { - const uint32_t index = (offset >> 2) & 3; - const uint32_t ret = m_scc[index]->ab_dc_r(3); - LOGMASKED(LOG_DUART0 << index, "%s: HPC DUART%d Channel A Data Read: %08x & %08x\n", machine().describe_context(), index, ret, mem_mask); - return ret; - } - default: - LOGMASKED(LOG_UNKNOWN, "%s: Unknown HPC Read: %08x & %08x\n", machine().describe_context(), 0x1fb80000 + offset*4, mem_mask); - return 0; - } - return 0; + m_scsi_bc = m_gio->read_dword(bdp + 0) & 0x1fffU; + m_scsi_cbp = m_gio->read_dword(bdp + 4) & (SCSI_CBP_EOX | SCSI_CBP_BUFADDR); + m_scsi_nbdp = m_gio->read_dword(bdp + 8) & 0x0fff'ffffU; + + LOGMASKED(LOG_SCSI, "bdp 0x%08x bc 0x%04x cbp 0x%08x nbdp 0x%08x\n", bdp, m_scsi_bc, m_scsi_cbp, m_scsi_nbdp); } -void hpc1_device::write(offs_t offset, uint32_t data, uint32_t mem_mask) +template void hpc1_device::write_drq(int state) { - if (offset >= 0x0e00/4 && offset <= 0x0e7c/4) + if (state) { - m_rtc->write(offset - 0xe00/4, (uint8_t)data); - return; + m_drq |= 1U << N; + + if (N == 0 && (m_scsi_ctrl & SCSI_STARTDMA)) + scsi_dma(); + else if (N == 1) + enet_dma(); } + else + m_drq &= ~(1U << N); +} - switch (offset) +template void hpc1_device::write_drq<0>(int state); +template void hpc1_device::write_drq<1>(int state); + +void hpc1_device::write_int(int state) +{ + u8 const rxs = m_enet->read(6); + u8 const txs = m_enet->read(7); + + // update status registers + m_enet_rxs = (m_enet_rxs & ~ENET_RXSTAT) | ((u32(rxs) << 8) & ENET_RXSTAT); + m_enet_txs = (m_enet_txs & ~ENET_TXSTAT) | ((u32(txs) << 16) & ENET_TXSTAT); + + LOGMASKED(LOG_ENET, "write_int %d rxs 0x%02x txs 0x%02x\n", state, rxs, txs); + + if (state) { - case 0x0090/4: - LOGMASKED(LOG_SCSI_DMA, "%s: HPC SCSI DMA Descriptor Pointer Write: %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_scsi_dma.m_desc = data; - fetch_chain(); - break; + bool interrupt = false; - case 0x0094/4: - LOGMASKED(LOG_SCSI_DMA, "%s: HPC SCSI DMA Control Register Write: %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_scsi_dma.m_ctrl = data &~ (HPC_DMACTRL_FLUSH | HPC_DMACTRL_RESET); - m_scsi_dma.m_to_mem = (m_scsi_dma.m_ctrl & HPC_DMACTRL_TO_MEM); - m_scsi_dma.m_active = (m_scsi_dma.m_ctrl & HPC_DMACTRL_ENABLE); - if (m_scsi_dma.m_drq && m_scsi_dma.m_active) - do_scsi_dma(); - break; - - case 0x00ac/4: - LOGMASKED(LOG_WRITES, "%s: HPC Parallel Buffer Pointer Write: %08x (%08x)\n", machine().describe_context(), data, mem_mask); - m_parbuf_ptr = data; - break; - case 0x0120/4: - if (ACCESSING_BITS_8_15) + // receive interrupt + if (BIT(m_enet_rxs, 8, 6)) { - LOGMASKED(LOG_SCSI, "%s: HPC SCSI Controller Address Write: %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_wd33c93->indir_addr_w((uint8_t)(data >> 8)); + // seeq receive fifo overflow or receive buffer overflow? + if (BIT(m_enet_rxs, 8) || (m_enet_ctrl & ENET_RBO)) + m_enet_rxs &= ~ENET_SRXDMA; + + interrupt = true; } - break; - case 0x0124/4: - if (ACCESSING_BITS_8_15) + + // transmit interrupt + if (BIT(m_enet_txs, 16, 3) || (BIT(m_enet_txs, 19) && BIT(m_enet_xbc, 15))) { - LOGMASKED(LOG_SCSI, "%s: HPC SCSI Controller Data Write: %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_wd33c93->indir_reg_w((uint8_t)(data >> 8)); + m_enet_txs &= ~ENET_STXDMA; + + interrupt = true; } - break; - case 0x01b0/4: - LOGMASKED(LOG_WRITES, "%s: HPC Misc. Status Write: %08x & %08x\n", machine().describe_context(), data, mem_mask); - if (BIT(data, 0)) - LOGMASKED(LOG_WRITES, " Force DSP hard reset\n" ); - if (BIT(data, 1)) - LOGMASKED(LOG_WRITES, " Force IRQA\n" ); + // TODO: interrupt delay + if (interrupt) + { + m_enet_ctrl |= ENET_CLRINT; + m_int_w(1); + } + } +} - if (BIT(data, 2)) - LOGMASKED(LOG_WRITES, " Set IRQA polarity high\n" ); +void hpc1_device::scsi_dma() +{ + if (m_scsi_bc) + { + if (m_scsi_ctrl & SCSI_TO_MEM) + m_gio->write_byte(m_scsi_cbp & SCSI_CBP_BUFADDR, m_dma_r[0]()); else - LOGMASKED(LOG_WRITES, " Set IRQA polarity low\n" ); + m_dma_w[0](m_gio->read_byte(m_scsi_cbp &SCSI_CBP_BUFADDR)); - if (BIT(data, 3)) - LOGMASKED(LOG_WRITES, " SRAM size: 32K\n" ); + m_scsi_cbp++; + m_scsi_bc--; + + if (m_scsi_bc == 0) + { + if (m_scsi_cbp & SCSI_CBP_EOX) + m_scsi_ctrl &= ~SCSI_STARTDMA; + else + scsi_chain(); + } + } +} + +void hpc1_device::enet_dma() +{ + // transmit + while (m_enet_txs & ENET_STXDMA) + { + m_enet_xbc = m_gio->read_dword(BIT(m_enet_cxbdp, 0, 30) + 0); + m_enet_cxbp = m_gio->read_dword(BIT(m_enet_cxbdp, 0, 30) + 4); + m_enet_nxbdp = m_gio->read_dword(BIT(m_enet_cxbdp, 0, 30) + 8); + + LOGMASKED(LOG_ENET, "transmit cxbdp 0x%08x cxbp 0x%08x xbc 0x%08x count %d nxbdp 0x%08x\n", + m_enet_cxbdp, m_enet_cxbp, m_enet_xbc, BIT(m_enet_xbc, 0, 13), m_enet_nxbdp); + for (unsigned i = 0; i < BIT(m_enet_xbc, 0, 13); i++) + m_dma_w[1](m_gio->read_byte(BIT(m_enet_cxbp, 0, 28) + i)); + + // eoxp: end of packet + if (BIT(m_enet_xbc, 31)) + { + LOGMASKED(LOG_ENET, "transmit end of packet\n"); + m_enet->txeof_w(1); + } + + // eox: last descriptor + if (BIT(m_enet_cxbp, 31)) + { + LOGMASKED(LOG_ENET, "transmit stop\n"); + m_enet_txs &= ~ENET_STXDMA; + } else - LOGMASKED(LOG_WRITES, " SRAM size: 8K\n" ); + m_enet_cxbdp = m_enet_nxbdp; + } - m_misc_status = data; - break; - case 0x01bc/4: - m_cpu_aux_ctrl = data; - LOGMASKED(LOG_EEPROM, "%s: HPC Serial EEPROM Write: %08x & %08x\n", machine().describe_context(), data, mem_mask ); - if (BIT(data, 0)) + // receive + while (m_enet_rxs & ENET_SRXDMA) + { + // check rxrdy + if (!BIT(m_drq, 1)) + break; + + m_enet_crbdp = m_enet_nrbdp; + + m_enet_rbc = m_gio->read_dword(BIT(m_enet_crbdp, 0, 30) + 0); + m_enet_crbp = m_gio->read_dword(BIT(m_enet_crbdp, 0, 30) + 4); + m_enet_nrbdp = m_gio->read_dword(BIT(m_enet_crbdp, 0, 30) + 8); + + LOGMASKED(LOG_ENET, "receive crbdp 0x%08x crbp 0x%08x rbc 0x%08x count %d nrbdp 0x%08x\n", + m_enet_crbdp, m_enet_crbp, m_enet_rbc, BIT(m_enet_rbc, 0, 13), m_enet_nrbdp); + + // rown? + if (BIT(m_enet_rbc, 31)) { - LOGMASKED(LOG_EEPROM, " CPU board LED on\n"); + unsigned count = 2; + while (!m_enet->rxeof_r()) + m_gio->write_byte(BIT(m_enet_crbp, 0, 28) + count++, m_dma_r[1]()); + + // FIXME: store rxstatus byte in receive buffer + logerror("rx status 0x%02x\n", (m_enet_rxs & ENET_RXSTAT) >> 8); + m_gio->write_byte(BIT(m_enet_crbp, 0, 28) + count++, 0x30); + + LOGMASKED(LOG_ENET, "receive data length %d\n", count - 3); + m_gio->write_dword(BIT(m_enet_crbdp, 0, 28) + 0, BIT(m_enet_rbc, 0, 13) - count); } - m_eeprom->di_write(BIT(data, 3)); - m_eeprom->cs_write(BIT(data, 1)); - m_eeprom->clk_write(BIT(data, 2)); - break; - case 0x01c0/4: - LOGMASKED(LOG_INT, "%s: HPC Local Interrupt 0 Status Write (Ignored): %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case 0x01c4/4: - { - LOGMASKED(LOG_INT, "%s: HPC Local Interrupt 0 Mask Write: %08x & %08x\n", machine().describe_context(), data, mem_mask); - const uint32_t old_mask = m_local_int_mask[0]; - m_local_int_mask[0] = data; - if (old_mask != m_local_int_mask[0]) - update_irq(0); - break; - } - case 0x01c8/4: - LOGMASKED(LOG_INT, "%s: HPC Local Interrupt 1 Status Write (Ignored): %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case 0x01cc/4: - { - LOGMASKED(LOG_INT, "%s: HPC Local Interrupt 1 Mask Write: %08x & %08x\n", machine().describe_context(), data, mem_mask); - const uint32_t old_mask = m_local_int_mask[1]; - m_local_int_mask[1] = data; - if (old_mask != m_local_int_mask[1]) - update_irq(1); - break; - } - case 0x01d4/4: - LOGMASKED(LOG_INT, "%s: HPC VME Interrupt Mask 0 Write: %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_vme_int_mask[0] = data; - break; - case 0x01d8/4: - LOGMASKED(LOG_INT, "%s: HPC VME Interrupt Mask 1 Write: %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_vme_int_mask[1] = data; - break; - case 0x01e0/4: - LOGMASKED(LOG_PIT, "%s: HPC Write Timer Interrupt Clear Register: %08x\n", machine().describe_context(), data); - set_timer_int_clear(data); - break; - case 0x01f0/4: - LOGMASKED(LOG_PIT, "%s: HPC Write Timer Count0 Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); - if (ACCESSING_BITS_24_31) - m_pit->write(0, (uint8_t)(data >> 24)); - else if (ACCESSING_BITS_0_7) - m_pit->write(0, (uint8_t)data); - return; - case 0x01f4/4: - LOGMASKED(LOG_PIT, "%s: HPC Write Timer Count1 Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_pit->write(1, (uint8_t)data); - return; - case 0x01f8/4: - LOGMASKED(LOG_PIT, "%s: HPC Write Timer Count2 Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_pit->write(2, (uint8_t)data); - return; - case 0x01fc/4: - LOGMASKED(LOG_PIT, "%s: HPC Write Timer Control Register: %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_pit->write(3, (uint8_t)data); - return; - case 0x0d00/4: - case 0x0d10/4: - case 0x0d20/4: - { - const uint32_t index = (offset >> 2) & 3; - m_scc[index]->ab_dc_w(0, (uint8_t)data); - LOGMASKED(LOG_DUART0 << index, "%s: HPC DUART%d Channel B Control Write: %08x & %08x\n", machine().describe_context(), index, data, mem_mask); - break; - } - case 0x0d04/4: - case 0x0d14/4: - case 0x0d24/4: - { - const uint32_t index = (offset >> 2) & 3; - m_scc[index]->ab_dc_w(1, (uint8_t)data); - LOGMASKED(LOG_DUART0 << index, "%s: HPC DUART%d Channel B Data Write: %08x & %08x\n", machine().describe_context(), index, data, mem_mask); - break; - } - case 0x0d08/4: - case 0x0d18/4: - case 0x0d28/4: - { - const uint32_t index = (offset >> 2) & 3; - m_scc[index]->ab_dc_w(2, (uint8_t)data); - LOGMASKED(LOG_DUART0 << index, "%s: HPC DUART%d Channel A Control Write: %08x & %08x\n", machine().describe_context(), index, data, mem_mask); - break; - } - case 0x0d0c/4: - case 0x0d1c/4: - case 0x0d2c/4: - { - const uint32_t index = (offset >> 2) & 3; - m_scc[index]->ab_dc_w(3, (uint8_t)data); - LOGMASKED(LOG_DUART0 << index, "%s: HPC DUART%d Channel A Data Write: %08x & %08x\n", machine().describe_context(), index, data, mem_mask); - break; - } - default: - LOGMASKED(LOG_UNKNOWN, "%s: Unknown HPC write: %08x = %08x & %08x\n", machine().describe_context(), 0x1fb80000 + offset*4, data, mem_mask); - break; - } -} -//************************************************************************** -// SCSI DMA -//************************************************************************** - -void hpc1_device::dump_chain(uint32_t base) -{ - const uint32_t addr = m_cpu_space->read_dword(base); - const uint32_t ctrl = m_cpu_space->read_dword(base+4); - const uint32_t next = m_cpu_space->read_dword(base+8); - - LOGMASKED(LOG_CHAIN, "Chain Node:\n"); - LOGMASKED(LOG_CHAIN, " Addr: %08x\n", addr); - LOGMASKED(LOG_CHAIN, " Ctrl: %08x\n", ctrl); - LOGMASKED(LOG_CHAIN, " Next: %08x\n", next); - - if (next != 0 && !BIT(addr, 31)) - { - dump_chain(next & 0x0fffffff); - } -} -void hpc1_device::fetch_chain() -{ - m_scsi_dma.m_ctrl = m_cpu_space->read_dword(m_scsi_dma.m_desc); - m_scsi_dma.m_addr = m_cpu_space->read_dword(m_scsi_dma.m_desc+4); - m_scsi_dma.m_next = m_cpu_space->read_dword(m_scsi_dma.m_desc+8); - m_scsi_dma.m_length = m_scsi_dma.m_ctrl & 0x1fff; - - LOGMASKED(LOG_CHAIN, "Fetching chain from %08x:\n", m_scsi_dma.m_desc); - LOGMASKED(LOG_CHAIN, " Addr: %08x\n", m_scsi_dma.m_addr); - LOGMASKED(LOG_CHAIN, " Ctrl: %08x\n", m_scsi_dma.m_ctrl); - LOGMASKED(LOG_CHAIN, " Next: %08x\n", m_scsi_dma.m_next); -} - -void hpc1_device::decrement_chain() -{ - m_scsi_dma.m_length--; - if (m_scsi_dma.m_length == 0) - { - if (BIT(m_scsi_dma.m_addr, 31)) + // eor: last descriptor + if (BIT(m_enet_crbp, 31)) { - m_scsi_dma.m_active = false; - m_scsi_dma.m_ctrl &= ~HPC_DMACTRL_ENABLE; - return; + LOGMASKED(LOG_ENET, "receive stop\n"); + m_enet_rxs &= ~ENET_SRXDMA; } - m_scsi_dma.m_desc = m_scsi_dma.m_next & 0x0fffffff; - fetch_chain(); } } -void hpc1_device::scsi_drq(int state) +u32 hpc1_device::trstat_r() { - m_scsi_dma.m_drq = state; + LOGMASKED(LOG_ENET, "trstat_r 0x%08x\n", m_enet_txs); - if (m_scsi_dma.m_drq && m_scsi_dma.m_active) - { - do_scsi_dma(); - } + return m_enet_txs; } -void hpc1_device::do_scsi_dma() +u32 hpc1_device::rcvstat_r() { - if (m_scsi_dma.m_to_mem) - m_cpu_space->write_byte(m_scsi_dma.m_addr & 0x0fffffff, m_wd33c93->dma_r()); + LOGMASKED(LOG_ENET, "rcvstat_r 0x%08x\n", m_enet_rxs); + + return m_enet_rxs; +} + +u8 hpc1_device::aux_r() +{ + if (m_eeprom_dati()) + return m_aux | 0x10; else - m_wd33c93->dma_w(m_cpu_space->read_byte(m_scsi_dma.m_addr & 0x0fffffff)); + return m_aux & ~0x10; +} - m_scsi_dma.m_addr++; - decrement_chain(); +void hpc1_device::cxbp_w(u32 data) +{ + LOGMASKED(LOG_ENET, "cxbp_w 0x%08x\n", data); + m_enet_cxbp = data; +} - if (!m_scsi_dma.m_active) +void hpc1_device::nxbdp_w(u32 data) +{ + LOGMASKED(LOG_ENET, "nxbdp_w 0x%08x\n", data); + m_enet_nxbdp = data; +} + +void hpc1_device::xbc_w(u32 data) +{ + LOGMASKED(LOG_ENET, "xbc_w 0x%08x\n", data); + m_enet_xbc = data; +} + +void hpc1_device::cxbdp_w(u32 data) +{ + LOGMASKED(LOG_ENET, "cxbdp_w 0x%08x\n", data); + m_enet_cxbdp = data; +} + +void hpc1_device::cpfxbdp_w(u32 data) +{ + LOGMASKED(LOG_ENET, "cpfxbdp_w 0x%08x\n", data); + m_enet_cpfxbdp = data; +} + +void hpc1_device::ppfxbdp_w(u32 data) +{ + LOGMASKED(LOG_ENET, "ppfxbdp_w 0x%08x\n", data); + m_enet_ppfxbdp = data; +} + +void hpc1_device::intdelay_w(u32 data) +{ + LOGMASKED(LOG_ENET, "intdelay_w 0x%08x\n", data); + m_enet_intdelay = data; +} + +void hpc1_device::trstat_w(u32 data) +{ + LOGMASKED(LOG_ENET, "trstat_w 0x%08x (%s)\n", data, machine().describe_context()); + m_enet_txs = (m_enet_txs & ~ENET_STXDMA) | (data & ENET_STXDMA); + + if (data & ENET_STXDMA) + enet_dma(); +} + +void hpc1_device::rcvstat_w(u32 data) +{ + LOGMASKED(LOG_ENET, "rcvstat_w 0x%08x\n", data); + m_enet_rxs = (m_enet_rxs & ~ENET_SRXDMA) | (data & ENET_SRXDMA); + + if (data & ENET_SRXDMA) + enet_dma(); +} + + +void hpc1_device::ctl_w(u32 data) +{ + LOGMASKED(LOG_ENET, "ctl_w 0x%08x (%s)\n", data, machine().describe_context()); + + // reset + if (m_enet) + m_enet->reset_w(!(data & ENET_RESET)); + + // clear interrupt + if (data & ENET_CLRINT) { - // clear HPC3 DMA active flag - m_scsi_dma.m_ctrl &= ~HPC_DMACTRL_ENABLE; + m_enet_ctrl &= ~ENET_CLRINT; + m_int_w(0); } + + // loopback + if (m_enet) + m_enet->set_loopback(!(data & ENET_MODNORM)); + + // receive buffer overflow + if (data & ENET_RBO) + m_enet_ctrl &= ~ENET_RBO; + + m_enet_ctrl = (m_enet_ctrl & ~(ENET_MODNORM | ENET_RESET)) | (data & (ENET_MODNORM | ENET_RESET)); } -//************************************************************************** -// PIT TIMERS -//************************************************************************** - -void hpc1_device::set_timer_int_clear(uint32_t data) +void hpc1_device::rbc_w(u32 data) { - if (BIT(data, 0)) - { - LOGMASKED(LOG_PIT | LOG_INT, "Clearing Timer 0 Interrupt: %d\n", data); - m_maincpu->set_input_line(MIPS3_IRQ2, CLEAR_LINE); - } - if (BIT(data, 1)) - { - LOGMASKED(LOG_PIT | LOG_INT, "Clearing Timer 1 Interrupt: %d\n", data); - m_maincpu->set_input_line(MIPS3_IRQ3, CLEAR_LINE); - } + LOGMASKED(LOG_ENET, "rbc_w 0x%08x\n", data); + m_enet_rbc = data; } -void hpc1_device::timer0_int(int state) +void hpc1_device::crbp_w(u32 data) { - LOGMASKED(LOG_PIT, "Timer0 Interrupt: %d\n", state); - if (state) - m_maincpu->set_input_line(MIPS3_IRQ2, ASSERT_LINE); + LOGMASKED(LOG_ENET, "crbp_w 0x%08x\n", data); + m_enet_crbp = data; } -void hpc1_device::timer1_int(int state) +void hpc1_device::nrbdp_w(u32 data) { - LOGMASKED(LOG_PIT, "Timer2 Interrupt: %d\n", state); - if (state) - m_maincpu->set_input_line(MIPS3_IRQ3, ASSERT_LINE); + LOGMASKED(LOG_ENET, "nrbdp_w 0x%08x\n", data); + m_enet_nrbdp = data; } -void hpc1_device::timer2_int(int state) +void hpc1_device::crbdp_w(u32 data) { - LOGMASKED(LOG_PIT, "Timer2 Interrupt (Disabled): %d\n", state); + LOGMASKED(LOG_ENET, "crbdp_w 0x%08x\n", data); + m_enet_crbdp = data; } -//************************************************************************** -// SERIAL DUARTS -//************************************************************************** - -void hpc1_device::duart0_int_w(int state) { duart_int_w(0, state); } -void hpc1_device::duart1_int_w(int state) { duart_int_w(1, state); } -void hpc1_device::duart2_int_w(int state) { duart_int_w(2, state); } - -void hpc1_device::duart_int_w(int channel, int state) +void hpc1_device::aux_w(u8 data) { - m_duart_int_status &= ~(1 << channel); - m_duart_int_status |= state << channel; + m_eeprom_out(data); - if (m_duart_int_status) - { - LOGMASKED(LOG_DUART0 << channel, "Raising DUART Interrupt: %02x\n", m_duart_int_status); - raise_local_irq(0, LOCAL0_DUART); - } - else - { - LOGMASKED(LOG_DUART0 << channel, "Lowering DUART Interrupt\n"); - lower_local_irq(0, LOCAL0_DUART); - } -} - -//************************************************************************** -// INTERRUPTS -//************************************************************************** - -void hpc1_device::raise_local_irq(int channel, uint8_t source_mask) -{ - m_local_int_status[channel] |= source_mask; - update_irq(channel); -} - -void hpc1_device::lower_local_irq(int channel, uint8_t source_mask) -{ - m_local_int_status[channel] &= ~source_mask; - update_irq(channel); -} - -void hpc1_device::update_irq(int channel) -{ - bool old_status = m_int_status[channel]; - m_int_status[channel] = (m_local_int_status[channel] & m_local_int_mask[channel]); - - if (old_status != m_int_status[channel]) - { - LOGMASKED(LOG_INT, "%s IRQ%d: %02x & %02x\n", m_int_status[channel] ? "Asserting" : "Clearing", channel, - m_local_int_status[channel], m_local_int_mask[channel]); - m_maincpu->set_input_line(MIPS3_IRQ0 + channel, m_int_status[channel] ? ASSERT_LINE : CLEAR_LINE); - } -} - -void hpc1_device::scsi_irq(int state) -{ - if (state) - { - LOGMASKED(LOG_SCSI, "SCSI: Set IRQ\n"); - raise_local_irq(0, LOCAL0_SCSI); - } - else - { - LOGMASKED(LOG_SCSI, "SCSI: Clear IRQ\n"); - lower_local_irq(0, LOCAL0_SCSI); - } + m_aux = data; } diff --git a/src/mame/sgi/hpc1.h b/src/mame/sgi/hpc1.h index 34b1c15de67..33f0391c407 100644 --- a/src/mame/sgi/hpc1.h +++ b/src/mame/sgi/hpc1.h @@ -11,129 +11,131 @@ #pragma once -#include "machine/dp8573a.h" -#include "machine/eepromser.h" -#include "machine/pit8253.h" -#include "machine/wd33c9x.h" -#include "machine/z80scc.h" +#include "machine/edlc.h" -class hpc1_device : public device_t +class hpc1_device + : public device_t + , public device_memory_interface { public: - template - hpc1_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu_tag, U &&eeprom_tag) - : hpc1_device(mconfig, tag, owner, (uint32_t)0) - { - m_maincpu.set_tag(std::forward(cpu_tag)); - m_eeprom.set_tag(std::forward(eeprom_tag)); - } + hpc1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); - hpc1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + template void set_gio(T &&tag, int spacenum) { m_gio.set_tag(std::forward(tag), spacenum); } + template void set_enet(T &&tag) { m_enet.set_tag(std::forward(tag)); } - uint32_t read(offs_t offset, uint32_t mem_mask = ~0); - void write(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + auto int_w() { return m_int_w.bind(); } + template auto dma_r_cb() { return m_dma_r[N].bind(); } + template auto dma_w_cb() { return m_dma_w[N].bind(); } + auto eeprom_dati() { return m_eeprom_dati.bind(); } + auto eeprom_out() { return m_eeprom_out.bind(); } + + template void write_drq(int state); + void write_int(int state); + + void map(address_map &map); protected: + // device_t implementation virtual void device_start() override; virtual void device_reset() override; - virtual void device_add_mconfig(machine_config &config) override; - void scsi_irq(int state); - void scsi_drq(int state); + // device_memory_interface implementation + virtual space_config_vector memory_space_config() const override; - void set_timer_int_clear(uint32_t data); - void timer0_int(int state); - void timer1_int(int state); - void timer2_int(int state); - void duart0_int_w(int state); - void duart1_int_w(int state); - void duart2_int_w(int state); + // dma + void enet_dma(); + void scsi_dma(); + void scsi_chain(); - void duart_int_w(int channel, int status); - void raise_local_irq(int channel, uint8_t source_mask); - void lower_local_irq(int channel, uint8_t source_mask); - void update_irq(int channel); + // ethernet read handlers + u32 cxbp_r() { return m_enet_cxbp; } + u32 nxbdp_r() { return m_enet_nxbdp; } + u32 xbc_r() { return m_enet_xbc; } + u32 cxbdp_r() { return m_enet_cxbdp; } + u32 cpfxbdp_r() { return m_enet_cpfxbdp; } + u32 ppfxbdp_r() { return m_enet_ppfxbdp; } + u32 intdelay_r() { return m_enet_intdelay; } + u32 trstat_r(); + u32 rcvstat_r(); + u32 ctl_r() { return m_enet_ctrl; } + u32 rbc_r() { return m_enet_rbc; } + u32 crbp_r() { return m_enet_crbp; } + u32 nrbdp_r() { return m_enet_nrbdp; } + u32 crbdp_r() { return m_enet_crbdp; } - void do_scsi_dma(); + // ethernet write handlers + void cxbp_w(u32 data); + void nxbdp_w(u32 data); + void xbc_w(u32 data); + void cxbdp_w(u32 data); + void cpfxbdp_w(u32 data); + void ppfxbdp_w(u32 data); + void intdelay_w(u32 data); + void trstat_w(u32 data); + void rcvstat_w(u32 data); + void ctl_w(u32 data); + void rbc_w(u32 data); + void crbp_w(u32 data); + void nrbdp_w(u32 data); + void crbdp_w(u32 data); - void dump_chain(uint32_t base); - void fetch_chain(); - void decrement_chain(); + // scsi read handlers + u32 scsi_bc_r() { return m_scsi_bc; } + u32 scsi_cbp_r() { return m_scsi_cbp; } + u32 scsi_nbdp_r() { return m_scsi_nbdp; } + u32 scsi_ctrl_r() { return m_scsi_ctrl; } - required_device m_maincpu; - required_device m_eeprom; - required_device m_wd33c93; - required_device_array m_scc; - required_device m_pit; - required_device m_rtc; + // scsi write handlers + void scsi_bc_w(u32 data) { m_scsi_bc = data & 0x1fffU; } + void scsi_cbp_w(u32 data) { m_scsi_cbp = data & 0x8fff'ffffU; } + void scsi_nbdp_w(u32 data); + void scsi_ctrl_w(u32 data); - enum - { - LOCAL0_FIFO_GIO0 = 0x01, - LOCAL0_PARALLEL = 0x02, - LOCAL0_SCSI = 0x04, - LOCAL0_ETHERNET = 0x08, - LOCAL0_GFX_DMA = 0x10, - LOCAL0_DUART = 0x20, - LOCAL0_GIO1 = 0x40, - LOCAL0_VME0 = 0x80, + u16 dsp_bc_r() { return m_dsp_bc; } + void dsp_bc_w(u16 data) { m_dsp_bc = data; } - LOCAL1_GR1_CASE = 0x02, - LOCAL1_VME1 = 0x08, - LOCAL1_DSP = 0x10, - LOCAL1_ACFAIL = 0x20, - LOCAL1_VIDEO = 0x40, - LOCAL1_RETRACE_GIO2 = 0x80 - }; + u8 aux_r(); + void aux_w(u8 data); - enum - { - HPC_DMACTRL_RESET = 0x01, - HPC_DMACTRL_FLUSH = 0x02, - HPC_DMACTRL_TO_MEM = 0x10, - HPC_DMACTRL_ENABLE = 0x80 - }; + void pbus_map(address_map &map); - struct scsi_dma_t - { - uint32_t m_desc = 0; - uint32_t m_addr = 0; - uint32_t m_ctrl = 0; - uint32_t m_length = 0; - uint32_t m_next = 0; - bool m_irq = false; - bool m_drq = false; - bool m_to_mem = false; - bool m_active = false; - }; +private: + address_space_config const m_pbus; + required_address_space m_gio; - static void cdrom_config(device_t *device); - static void scsi_devices(device_slot_interface &device); - static void indigo_mice(device_slot_interface &device); - void wd33c93(device_t *device); + optional_device m_enet; - uint8_t m_misc_status = 0; - uint32_t m_cpu_aux_ctrl = 0; - uint32_t m_parbuf_ptr = 0; - uint32_t m_local_int_status[2]{}; - uint32_t m_local_int_mask[2]{}; - bool m_int_status[2]{}; - uint32_t m_vme_int_mask[2]{}; + devcb_write_line m_int_w; + devcb_read_line m_eeprom_dati; + devcb_read8::array<2> m_dma_r; + devcb_write8::array<2> m_dma_w; + devcb_write8 m_eeprom_out; - scsi_dma_t m_scsi_dma; + u8 m_drq; - uint8_t m_duart_int_status = 0; + u32 m_enet_cxbp; // enet current transmit buffer pointer + u32 m_enet_nxbdp; // enet current transmit buffer descriptor pointer + u32 m_enet_xbc; // enet transmit byte count + u32 m_enet_cxbdp; // enet current transmit buffer descriptor pointer + u32 m_enet_cpfxbdp; // enet current packet first transmit buffer descriptor pointer + u32 m_enet_ppfxbdp; // enet previous packet first transmit buffer descriptor pointer + u32 m_enet_intdelay; // enet interrupt delay count + u32 m_enet_txs; // enet transmit status + u32 m_enet_rxs; // enet receive status + u32 m_enet_ctrl; // enet interrupt, channel reset, buffer overflow + u32 m_enet_rbc; // enet receive byte count + u32 m_enet_crbp; // enet current receive buffer pointer + u32 m_enet_nrbdp; // enet next receive buffer desriptor pointer + u32 m_enet_crbdp; // enet current receive buffer descriptor pointer - address_space *m_cpu_space = nullptr; + u32 m_scsi_bc; // scsi byte count + u32 m_scsi_cbp; // scsi current buffer pointer + u32 m_scsi_nbdp; // scsi next buffer descriptor pointer + u32 m_scsi_ctrl; // scsi control - static char const *const RS232A_TAG; - static char const *const RS232B_TAG; + u16 m_dsp_bc; - static const XTAL SCC_PCLK; - static const XTAL SCC_RXA_CLK; - static const XTAL SCC_TXA_CLK; - static const XTAL SCC_RXB_CLK; - static const XTAL SCC_TXB_CLK; + u8 m_aux; }; DECLARE_DEVICE_TYPE(SGI_HPC1, hpc1_device) diff --git a/src/mame/sgi/indigo.cpp b/src/mame/sgi/indigo.cpp deleted file mode 100644 index 53d239bd434..00000000000 --- a/src/mame/sgi/indigo.cpp +++ /dev/null @@ -1,230 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz -/********************************************************************* - - SGI Indigo workstation - - To-Do: - - IP12 (R3000): - * Everything - - IP20 (R4000): - * Figure out why the keyboard/mouse diagnostic fails - * Work out a proper RAM mapping, or why the installer bails due - to trying to access virtual address ffffa02c: - 88002584: lw $sp,-$5fd4($0) - -**********************************************************************/ - -#include "emu.h" -//#include "cpu/dsp56156/dsp56156.h" -#include "cpu/mips/mips1.h" -#include "cpu/mips/r4000.h" -#include "machine/eepromser.h" - -#include "hpc1.h" -#include "mc.h" -#include "light.h" - -#define LOG_UNKNOWN (1U << 1) -#define LOG_INT (1U << 2) -#define LOG_DSP (1U << 3) -#define LOG_ALL (LOG_UNKNOWN | LOG_INT | LOG_DSP) - -#define VERBOSE (LOG_UNKNOWN) -#include "logmacro.h" - - -namespace { - -class indigo_state : public driver_device -{ -public: - indigo_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag) - , m_hpc(*this, "hpc") - , m_eeprom(*this, "eeprom") - , m_gfx(*this, "lg1") - { - } - - void indigo_base(machine_config &config); - -protected: - virtual void machine_start() override; - virtual void machine_reset() override; - - uint32_t int_r(offs_t offset, uint32_t mem_mask = ~0); - void int_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - uint32_t dsp_ram_r(offs_t offset, uint32_t mem_mask = ~0); - void dsp_ram_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - - void indigo_map(address_map &map); - - required_device m_hpc; - required_device m_eeprom; - std::unique_ptr m_dsp_ram; - required_device m_gfx; - address_space *m_space = nullptr; -}; - -class indigo3k_state : public indigo_state -{ -public: - indigo3k_state(const machine_config &mconfig, device_type type, const char *tag) - : indigo_state(mconfig, type, tag) - , m_maincpu(*this, "maincpu") - { - } - - void indigo3k(machine_config &config); - -protected: - void mem_map(address_map &map); - - required_device m_maincpu; -}; - -class indigo4k_state : public indigo_state -{ -public: - indigo4k_state(const machine_config &mconfig, device_type type, const char *tag) - : indigo_state(mconfig, type, tag) - , m_maincpu(*this, "maincpu") - , m_mem_ctrl(*this, "memctrl") - { - } - - void indigo4k(machine_config &config); - -protected: - virtual void machine_reset() override; - - void mem_map(address_map &map); - - required_device m_maincpu; - required_device m_mem_ctrl; -}; - -void indigo_state::machine_start() -{ - m_dsp_ram = std::make_unique(0x8000); - save_pointer(NAME(&m_dsp_ram[0]), 0x8000); -} - -void indigo_state::machine_reset() -{ -} - -void indigo4k_state::machine_reset() -{ - indigo_state::machine_reset(); -} - -uint32_t indigo_state::int_r(offs_t offset, uint32_t mem_mask) -{ - LOGMASKED(LOG_INT, "%s: INT Read: %08x & %08x\n", machine().describe_context(), 0x1fbd9000 + offset*4, mem_mask); - return 0; -} - -void indigo_state::int_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - LOGMASKED(LOG_INT, "%s: INT Write: %08x = %08x & %08x\n", machine().describe_context(), 0x1fbd9000 + offset*4, data, mem_mask); -} - -uint32_t indigo_state::dsp_ram_r(offs_t offset, uint32_t mem_mask) -{ - LOGMASKED(LOG_DSP, "%s: DSP RAM Read: %08x = %08x & %08x\n", machine().describe_context(), 0x1fbe0000 + offset*4, m_dsp_ram[offset], mem_mask); - return m_dsp_ram[offset]; -} - -void indigo_state::dsp_ram_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - LOGMASKED(LOG_DSP, "%s: DSP RAM Write: %08x = %08x & %08x\n", machine().describe_context(), 0x1fbe0000 + offset*4, data, mem_mask); - m_dsp_ram[offset] = data; -} - - -void indigo_state::indigo_map(address_map &map) -{ - map(0x1f3f0000, 0x1f3f7fff).m(m_gfx, FUNC(sgi_lg1_device::map)); - map(0x1fb80000, 0x1fb8ffff).rw(m_hpc, FUNC(hpc1_device::read), FUNC(hpc1_device::write)); - map(0x1fbd9000, 0x1fbd903f).rw(FUNC(indigo_state::int_r), FUNC(indigo_state::int_w)); - map(0x1fbe0000, 0x1fbfffff).rw(FUNC(indigo_state::dsp_ram_r), FUNC(indigo_state::dsp_ram_w)); -} - -void indigo3k_state::mem_map(address_map &map) -{ - indigo_map(map); - map(0x1fc00000, 0x1fc3ffff).rom().region("user1", 0); -} - -void indigo4k_state::mem_map(address_map &map) -{ - indigo_map(map); - map(0x1fa00000, 0x1fa1ffff).rw(m_mem_ctrl, FUNC(sgi_mc_device::read), FUNC(sgi_mc_device::write)); - map(0x1fc00000, 0x1fc7ffff).rom().region("user1", 0); -} - -static INPUT_PORTS_START(indigo) -INPUT_PORTS_END - -void indigo_state::indigo_base(machine_config &config) -{ - SGI_LG1(config, m_gfx); - - EEPROM_93C56_16BIT(config, m_eeprom); -} - -void indigo3k_state::indigo3k(machine_config &config) -{ - indigo_base(config); - - R3000A(config, m_maincpu, 33.333_MHz_XTAL, 32768, 32768); - downcast(*m_maincpu).set_endianness(ENDIANNESS_BIG); - m_maincpu->set_addrmap(AS_PROGRAM, &indigo3k_state::mem_map); - - SGI_HPC1(config, m_hpc, m_maincpu, m_eeprom); -} - -static DEVICE_INPUT_DEFAULTS_START(ip20_mc) - DEVICE_INPUT_DEFAULTS("VALID", 0x0f, 0x07) -DEVICE_INPUT_DEFAULTS_END - -void indigo4k_state::indigo4k(machine_config &config) -{ - indigo_base(config); - - R4000(config, m_maincpu, 50000000); - //m_maincpu->set_icache_size(32768); - //m_maincpu->set_dcache_size(32768); - m_maincpu->set_addrmap(AS_PROGRAM, &indigo4k_state::mem_map); - - SGI_MC(config, m_mem_ctrl, m_maincpu, m_eeprom, 50000000); - m_mem_ctrl->eisa_present().set_constant(0); - m_mem_ctrl->set_input_default(DEVICE_INPUT_DEFAULTS_NAME(ip20_mc)); - - SGI_HPC1(config, m_hpc, m_maincpu, m_eeprom); -} - -ROM_START( indigo3k ) - ROM_REGION32_BE( 0x40000, "user1", 0 ) - ROM_SYSTEM_BIOS( 0, "401-rev-c", "SGI Version 4.0.1 Rev C LG1/GR2, Jul 9, 1992" ) // dumped over serial connection from boot monitor and swapped - ROMX_LOAD( "ip12prom.070-8088-xxx.u56", 0x000000, 0x040000, CRC(25ca912f) SHA1(94b3753d659bfe50b914445cef41290122f43880), ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(0) ) - ROM_SYSTEM_BIOS( 1, "401-rev-d", "SGI Version 4.0.1 Rev D LG1/GR2, Mar 24, 1992" ) // dumped with EPROM programmer - ROMX_LOAD( "ip12prom.070-8088-002.u56", 0x000000, 0x040000, CRC(ea4329ef) SHA1(b7d67d0e30ae8836892f7170dd4757732a0a3fd6), ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(1) ) -ROM_END - -ROM_START( indigo4k ) - ROM_REGION64_BE( 0x80000, "user1", 0 ) - ROM_SYSTEM_BIOS( 0, "405d-rev-a", "SGI Version 4.0.5D Rev A IP20, Aug 19, 1992" ) - ROMX_LOAD( "ip20prom.070-8116-004.bin", 0x000000, 0x080000, CRC(940d960e) SHA1(596aba530b53a147985ff3f6f853471ce48c866c), ROM_GROUPDWORD | ROM_REVERSE | ROM_BIOS(0) ) - ROM_SYSTEM_BIOS( 1, "405g-rev-b", "SGI Version 4.0.5G Rev B IP20, Nov 10, 1992" ) // dumped over serial connection from boot monitor and swapped - ROMX_LOAD( "ip20prom.070-8116-005.bin", 0x000000, 0x080000, CRC(1875b645) SHA1(52f5d7baea3d1bc720eb2164104c177e23504345), ROM_GROUPDWORD | ROM_REVERSE | ROM_BIOS(1) ) -ROM_END - -} // anonymous namespace - - -// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 1991, indigo3k, 0, 0, indigo3k, indigo, indigo3k_state, empty_init, "Silicon Graphics Inc", "IRIS Indigo (R3000, 33MHz)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -COMP( 1993, indigo4k, 0, 0, indigo4k, indigo, indigo4k_state, empty_init, "Silicon Graphics Inc", "IRIS Indigo (R4400, 150MHz)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) diff --git a/src/mame/sgi/int2.cpp b/src/mame/sgi/int2.cpp new file mode 100644 index 00000000000..e571b1d96a8 --- /dev/null +++ b/src/mame/sgi/int2.cpp @@ -0,0 +1,214 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * Silicon Graphics Local I/O Interrupt Multiplexor (INT2). + * + * TODO: + * - bus error + * - fpu interrupt + */ + +/* + * # Source + * 0 floating-point unit + * 1 local I/O 0 + * 2 local I/O 1 + * 3 timer 0 + * 4 timer 1 + * 5 bus error + */ + +#include "emu.h" +#include "int2.h" + +//#define VERBOSE (LOG_GENERAL) + +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(SGI_INT2, sgi_int2_device, "sgi_int2", "SGI INT2") + +sgi_int2_device::sgi_int2_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : device_t(mconfig, SGI_INT2, tag, owner, clock) + , m_pit(*this, "pit") + , m_vme(*this, "vme%u_int", 0U) + , m_led(*this) + , m_poweroff(*this) + , m_intr(*this) + , m_intr_state{} +{ +} + +void sgi_int2_device::device_add_mconfig(machine_config &config) +{ + PIT8254(config, m_pit); + m_pit->set_clk<2>(clock() / 10); + m_pit->out_handler<0>().set([this](int state) { if (state) { m_intr_state[3] = true; m_intr[3](m_intr_state[3]); } }); + m_pit->out_handler<1>().set([this](int state) { if (state) { m_intr_state[4] = true; m_intr[4](m_intr_state[4]); } }); + m_pit->out_handler<2>().append(m_pit, FUNC(pit8254_device::write_clk0)); + m_pit->out_handler<2>().append(m_pit, FUNC(pit8254_device::write_clk1)); + + INPUT_MERGER_ANY_HIGH(config, m_vme[0]); + m_vme[0]->output_handler().set(FUNC(sgi_int2_device::lio0_w)); + + INPUT_MERGER_ANY_HIGH(config, m_vme[1]); + m_vme[1]->output_handler().set(FUNC(sgi_int2_device::lio1_w)); +} + +void sgi_int2_device::device_start() +{ + save_item(NAME(m_intr_state)); + save_item(NAME(m_lstatus)); + save_item(NAME(m_lmask)); + save_item(NAME(m_vstatus)); + save_item(NAME(m_vmask)); + save_item(NAME(m_config)); + + m_lstatus[0] = 0; + m_lstatus[1] = 0; + m_vstatus = 0; + m_config = 0; +} + +void sgi_int2_device::device_reset() +{ + config_w(0); + + m_lmask[0] = 0; + m_lmask[1] = 0; + m_vmask[0] = 0; + m_vmask[1] = 0; + + lio_update(); +} + +void sgi_int2_device::map(address_map &map) +{ + map(0x0, 0x0).r(FUNC(sgi_int2_device::lstatus_r<0>)); + map(0x1, 0x1).rw(FUNC(sgi_int2_device::lmask_r<0>), FUNC(sgi_int2_device::lmask_w<0>)); + map(0x2, 0x2).r(FUNC(sgi_int2_device::lstatus_r<1>)); + map(0x3, 0x3).rw(FUNC(sgi_int2_device::lmask_r<1>), FUNC(sgi_int2_device::lmask_w<1>)); + map(0x4, 0x4).r(FUNC(sgi_int2_device::vstatus_r)); + map(0x5, 0x5).rw(FUNC(sgi_int2_device::vmask_r<0>), FUNC(sgi_int2_device::vmask_w<0>)); + map(0x6, 0x6).rw(FUNC(sgi_int2_device::vmask_r<1>), FUNC(sgi_int2_device::vmask_w<1>)); + map(0x7, 0x7).rw(FUNC(sgi_int2_device::config_r), FUNC(sgi_int2_device::config_w)); + map(0x8, 0x8).w(FUNC(sgi_int2_device::tclear_w)); + + map(0xc, 0xf).rw(m_pit, FUNC(pit8254_device::read), FUNC(pit8254_device::write)); +} + +template void sgi_int2_device::lmask_w(u8 data) +{ + m_lmask[N] = data; + + lio_update(); +} + +template void sgi_int2_device::vmask_w(u8 data) +{ + m_vmask[N] = data; + + lio_update(); +} + +void sgi_int2_device::config_w(u8 data) +{ + for (unsigned led = 0; led < 4; led++) + if (BIT(data ^ m_config, led)) + m_led[led](BIT(data, led)); + + if (BIT(data ^ m_config, 4)) + m_poweroff(BIT(data, 4)); + + m_config = data & 0x1f; +} + +void sgi_int2_device::tclear_w(u8 data) +{ + // clear timer 0 level 3 + if (BIT(data, 0) && m_intr_state[3]) + { + m_intr_state[3] = false; + m_intr[3](m_intr_state[3]); + } + + // clear timer 1 level 4 + if (BIT(data, 1) && m_intr_state[4]) + { + m_intr_state[4] = false; + m_intr[4](m_intr_state[4]); + } +} + +template void sgi_int2_device::lio0_w(int state) +{ + LOG("lio0 interrupt %u input state %d\n", N, state); + if (state) + m_lstatus[0] |= 1U << N; + else + m_lstatus[0] &= ~(1U << N); + + lio_update(); +} + +template void sgi_int2_device::lio1_w(int state) +{ + LOG("lio1 interrupt %u input state %d\n", N, state); + if (state) + m_lstatus[1] |= 1U << N; + else + m_lstatus[1] &= ~(1U << N); + + lio_update(); +} + +template void sgi_int2_device::vme_w(int state) +{ + LOG("vme interrupt %u input state %d\n", N, state); + if (state) + m_vstatus |= 1U << N; + else + m_vstatus &= ~(1U << N); + + m_vme[0]->in_w(state); + m_vme[1]->in_w(state); +} + +void sgi_int2_device::lio_update() +{ + for (unsigned l = 0; l < 2; l++) + { + if (bool(m_lstatus[l] & m_lmask[l]) != m_intr_state[l + 1]) + { + LOG("lio%d output state %d\n", l, bool(m_lstatus[l] & m_lmask[l])); + m_intr_state[l + 1] = m_lstatus[l] & m_lmask[l]; + m_intr[l + 1](m_intr_state[l + 1]); + } + } +} + +template void sgi_int2_device::lio0_w<0>(int state); +template void sgi_int2_device::lio0_w<1>(int state); +template void sgi_int2_device::lio0_w<2>(int state); +template void sgi_int2_device::lio0_w<3>(int state); +template void sgi_int2_device::lio0_w<4>(int state); +template void sgi_int2_device::lio0_w<5>(int state); +template void sgi_int2_device::lio0_w<6>(int state); +template void sgi_int2_device::lio0_w<7>(int state); + +template void sgi_int2_device::lio1_w<0>(int state); +template void sgi_int2_device::lio1_w<1>(int state); +template void sgi_int2_device::lio1_w<2>(int state); +template void sgi_int2_device::lio1_w<3>(int state); +template void sgi_int2_device::lio1_w<4>(int state); +template void sgi_int2_device::lio1_w<5>(int state); +template void sgi_int2_device::lio1_w<6>(int state); +template void sgi_int2_device::lio1_w<7>(int state); + +template void sgi_int2_device::vme_w<1>(int state); +template void sgi_int2_device::vme_w<2>(int state); +template void sgi_int2_device::vme_w<3>(int state); +template void sgi_int2_device::vme_w<4>(int state); +template void sgi_int2_device::vme_w<5>(int state); +template void sgi_int2_device::vme_w<6>(int state); +template void sgi_int2_device::vme_w<7>(int state); diff --git a/src/mame/sgi/int2.h b/src/mame/sgi/int2.h new file mode 100644 index 00000000000..f4ef908ce6c --- /dev/null +++ b/src/mame/sgi/int2.h @@ -0,0 +1,86 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_SGI_INT2_H +#define MAME_SGI_INT2_H + +#pragma once + +#include "machine/input_merger.h" +#include "machine/pit8253.h" + +class sgi_int2_device + : public device_t +{ +public: + sgi_int2_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock); + + template auto write_led() { return m_led[N].bind(); } + auto write_poweroff() { return m_poweroff.bind(); } + template auto write_intr() { return m_intr[N].bind(); } + + enum lio_int : unsigned + { + LIO0_GIO0 = 0, // gio0/fifo full + LIO0_PARALLEL = 1, + LIO0_SCSI = 2, + LIO0_ETHERNET = 3, + LIO0_GDMA = 4, // graphics dma done + LIO0_DUART = 5, + LIO0_GIO1 = 6, // gio1/ge/second hpc1 + LIO0_VME0 = 7, + + LIO1_GR1MODE = 1, + LIO1_VME1 = 3, + LIO1_DSP = 4, // hpc + LIO1_ACFAIL = 5, + LIO1_VIDEO = 6, // video option + LIO1_GIO2 = 7, // gio2/vertical retrace + }; + // interrupt request inputs + template void lio0_w(int state); + template void lio1_w(int state); + template void vme_w(int state); + + void map(address_map &map); + +protected: + // device_t implementation + void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void device_reset() override; + + // read handlers + template u8 lstatus_r() { return m_lstatus[N]; } + template u8 lmask_r() { return m_lmask[N]; } + u8 vstatus_r() { return m_vstatus; } + template u8 vmask_r() { return m_vmask[N]; } + u8 config_r() { return m_config; } + + // write handlers + template void lmask_w(u8 data); + template void vmask_w(u8 data); + void config_w(u8 data); + void tclear_w(u8 data); + + void lio_update(); + +private: + required_device m_pit; + required_device_array m_vme; + + devcb_write_line::array<4> m_led; + devcb_write_line m_poweroff; + devcb_write_line::array<6> m_intr; + bool m_intr_state[6]; + + u8 m_lstatus[2]; + u8 m_lmask[2]; + u8 m_vstatus; + u8 m_vmask[2]; + u8 m_config; +}; + +DECLARE_DEVICE_TYPE(SGI_INT2, sgi_int2_device) + +#endif // MAME_SGI_INT2_H diff --git a/src/mame/sgi/ip12.cpp b/src/mame/sgi/ip12.cpp new file mode 100644 index 00000000000..b1177315691 --- /dev/null +++ b/src/mame/sgi/ip12.cpp @@ -0,0 +1,431 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * Silicon Graphics IP12 systems. + * + * Year Model Board Type CPU Clock I/D Cache Code Name(s) + * 1991 4D/30 IP14 IP12 R3000 30MHz 64KiB/64KiB Magnum + * 1991 4D/35 IP12 IP12 R3000 36MHz 64KiB/64KiB Magnum + * 1991 Indigo IP12 IP12 R3000 33MHz 32KiB/32KiB Hollywood, 4DRPC, HP1 + * + * TODO: + * - VME-based V30/V35 + * - DSP + * + */ + +/* + * WIP + * --- + * setenv bootmode d # enable diagnostic output (bootmode c is normal) + * + * ide usage: report=5; + * + * installing IRIX 4.0.5/5.3 (IRIX CDROM at SCSI ID 4): + * - boot -f dksc(0,4,8)sashIP12 + * - boot -f dksc(0,4,7)stand/fx.IP12 --x + * - create root partition and label disk + * - use firmware option 2 and inst to install OS from CDROM + * + * after installation, disable windowing system (until graphics work): + * - shroot (or sh and prefix commands with chroot /root) + * - /etc/chkconfig -f windowsystem off + * - /etc/chkconfig -f xdm off + * - for IRIX 5.3, also edit /etc/inittab to spawn getty on console + * + */ + +#include "emu.h" +#include "cpu/mips/mips1.h" +#include "cpu/dsp56000/dsp56000.h" + +#include "machine/dp8573a.h" +#include "machine/edlc.h" +#include "machine/eepromser.h" +#include "machine/input_merger.h" +#include "machine/nscsi_bus.h" +#include "machine/wd33c9x.h" +#include "machine/z80scc.h" + +#include "bus/rs232/rs232.h" +#include "bus/rs232/hlemouse.h" +#include "bus/nscsi/cd.h" +#include "bus/nscsi/hd.h" + +#include "hpc1.h" +#include "int2.h" +#include "kbd.h" +#include "light.h" +#include "pic1.h" + +//#define VERBOSE (LOG_GENERAL) +#include "logmacro.h" + +namespace { + +class ip12_state : public driver_device +{ +public: + ip12_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_cpu(*this, "cpu") + , m_pic(*this, "pic") + , m_hpc(*this, "hpc") + , m_int(*this, "int") + , m_nvram(*this, "nvram") + , m_rtc(*this, "rtc") + , m_scsi(*this, "scsi:0:wd33c93a") + , m_eth(*this, "eth") + , m_scc(*this, "scc%u", 0U) + , m_scc_irq(*this, "scc_irq") + , m_dsp(*this, "dsp") + , m_gfx(*this, "gfx") + { + } + + void indigo(machine_config &config); + void pi4d30(machine_config &config); + void pi4d35(machine_config &config); + +protected: + virtual void machine_start() override; + virtual void machine_reset() override; + + void ip12(machine_config &config); + void pi4d3x(machine_config &config); + + void ip12_map(address_map &map); + void pi4d3x_map(address_map &map); + void pbus_map(address_map &map); + + required_device m_cpu; + required_device m_pic; + required_device m_hpc; + required_device m_int; + required_device m_nvram; + required_device m_rtc; + required_device m_scsi; + required_device m_eth; + required_device_array m_scc; + required_device m_scc_irq; + required_device m_dsp; + required_device m_gfx; + + /* + * board revisions according to NetBSD source: + * 0x0000-0x6000 -> IP12 4D/3x + * 0x7000 -> IP12 VIP12 + * 0x8000-0xd000 -> IP12 HP1 + * 0xe000-0xf000 -> IP12 HPLC + */ + u32 m_brdrev; +}; + +void ip12_state::machine_start() +{ +} + +void ip12_state::machine_reset() +{ +} + +void ip12_state::ip12_map(address_map &map) +{ + // 0x0000'0000-0fff'ffff // local memory + // 0x1000'0000-1eff'ffff // vme + // 0x1f00'0000-1fbf'ffff // local i/o + // 0x1fc0'0000-1fff'ffff // boot prom + + // 0x2000'0000-3fff'ffff // vme (normally inaccessible) + // 0x4000'0000-ffff'ffff // unused (normally inaccessible), bus error (read) interrupt (write) + + map(0x1000'0000, 0x1eff'ffff).lr32([this]() { m_cpu->berr_w(1); return 0; }, "buserror"); // vme + + map(0x1f3f'0000, 0x1f3f'7fff).m(m_gfx, FUNC(sgi_lg1_device::map)); + // 1f3f'8000-1f3f'ffff // lg2x2 second head + + // 0x1f40'0000-0x1f5'ffff gio slot 0 + // 0x1f60'0000-0x1f7'ffff gio slot 1 + + //map(0x1f90'0000, 0x1f97'ffff); // hpc 3 + //map(0x1f98'0000, 0x1f9f'ffff); // hpc 2 + map(0x1fa0'0000, 0x1faf'ffff).m(m_pic, FUNC(sgi_pic1_device::map)); + //map(0x1fb0'0000, 0x1fb7'ffff); // hpc 1 + //map(0x1fb8'0000, 0x1fbf'ffff); // hpc 0 + + map(0x1fb8'0000, 0x1fb8'ffff).m(m_hpc, FUNC(hpc1_device::map)); + map(0x1fb8'0100, 0x1fb8'011f).m(m_eth, FUNC(seeq8003_device::map)).umask32(0xff); + map(0x1fb8'0120, 0x1fb8'0127).rw(m_scsi, FUNC(wd33c93a_device::indir_r), FUNC(wd33c93a_device::indir_w)).umask32(0xff00); + map(0x1fb8'01c0, 0x1fb8'01ff).m(m_int, FUNC(sgi_int2_device::map)).umask32(0xff); + map(0x1fb8'0d00, 0x1fb8'0d0f).rw(m_scc[0], FUNC(scc85c30_device::ab_dc_r), FUNC(scc85c30_device::ab_dc_w)).umask32(0xff); + map(0x1fb8'0d10, 0x1fb8'0d1f).rw(m_scc[1], FUNC(scc85c30_device::ab_dc_r), FUNC(scc85c30_device::ab_dc_w)).umask32(0xff); + map(0x1fb8'0d30, 0x1fb8'0d3f).noprw(); // TODO: left/right headphone gain mdacs + map(0x1fb8'0e00, 0x1fb8'0e7f).rw(m_rtc, FUNC(dp8572a_device::read), FUNC(dp8572a_device::write)).umask32(0xff); + + map(0x1fbd'0000, 0x1fbd'0003).lr32([this]() { return m_brdrev; }, "board_rev"); // board revision register + + map(0x1fbe'0000, 0x1fbf'ffff).ram().share("dsp_ram"); // 3xTC55328J-35 (24 bits x 32k) + + map(0x1fc0'0000, 0x1fc3'ffff).rom().region("prom", 0); +} + +void ip12_state::pi4d3x_map(address_map &map) +{ + ip12_map(map); + + map(0x1fb8'0d20, 0x1fb8'0d2f).rw(m_scc[2], FUNC(scc85c30_device::ab_dc_r), FUNC(scc85c30_device::ab_dc_w)).umask32(0xff); +} + +// HPC1 PBUS decode? +// 00100-0011f == 00040-00047 -> net +// 00120-00127 == 00048-00049 -> scsi +// 001c0-001ff == 00070-0007f -> int2 +// 00d00-00d3f == 00340-0034f -> fff0-ffff duart +// 00e00-00e7f == 00380-0039f -> ffc0-ffdf rtc +// 60000-7ffff == 18000-1ffff -> 8000-ffff? ram +// +// Actel/AUD1 and audio adc/dac via DSP SCI +// +void ip12_state::pbus_map(address_map &map) +{ + map(0xffc0, 0xffdf).rw(m_rtc, FUNC(dp8572a_device::read), FUNC(dp8572a_device::write)); + + map(0xfff0, 0xfff3).rw(m_scc[0], FUNC(scc85c30_device::ab_dc_r), FUNC(scc85c30_device::ab_dc_w)); + map(0xfff4, 0xfff7).rw(m_scc[1], FUNC(scc85c30_device::ab_dc_r), FUNC(scc85c30_device::ab_dc_w)); + map(0xfff8, 0xfffb).rw(m_scc[2], FUNC(scc85c30_device::ab_dc_r), FUNC(scc85c30_device::ab_dc_w)); + //map(0xfffc, 0xffff).rw(m_scc[3], FUNC(scc85c30_device::ab_dc_r), FUNC(scc85c30_device::ab_dc_w)); +} + +static DEVICE_INPUT_DEFAULTS_START(pi4d3x_pic1) + DEVICE_INPUT_DEFAULTS("VALID", 0x0f, 0x0f) +DEVICE_INPUT_DEFAULTS_END + +static DEVICE_INPUT_DEFAULTS_START(indigo_pic1) + DEVICE_INPUT_DEFAULTS("VALID", 0x0f, 0x07) +DEVICE_INPUT_DEFAULTS_END + +static void scsi_devices(device_slot_interface &device) +{ + device.option_add("cdrom", NSCSI_CDROM_SGI).machine_config( + [](device_t *device) + { + downcast(*device).set_block_size(512); + }); + device.option_add("harddisk", NSCSI_HARDDISK); +} + +void ip12_state::ip12(machine_config &config) +{ + SGI_PIC1(config, m_pic, 0); + m_pic->set_bus(m_cpu, AS_PROGRAM); + + SGI_HPC1(config, m_hpc, 0); + m_hpc->set_addrmap(0, &ip12_state::pbus_map); + m_hpc->set_gio(m_cpu, AS_PROGRAM); + m_hpc->set_enet(m_eth); + m_hpc->int_w().set(m_int, FUNC(sgi_int2_device::lio0_w)); + m_hpc->dma_r_cb<0>().set(m_scsi, FUNC(wd33c93a_device::dma_r)); + m_hpc->dma_w_cb<0>().set(m_scsi, FUNC(wd33c93a_device::dma_w)); + m_hpc->eeprom_dati().set(m_nvram, FUNC(eeprom_serial_93cxx_device::do_read)); + m_hpc->eeprom_out().set( + [this](u8 data) + { + // TODO: bit 0 console led + m_nvram->di_write(BIT(data, 3)); + m_nvram->cs_write(BIT(data, 1)); + m_nvram->clk_write(BIT(data, 2)); + }); + + SGI_INT2(config, m_int, 10_MHz_XTAL); + m_int->write_intr<1>().set_inputline(m_cpu, INPUT_LINE_IRQ1); + m_int->write_intr<2>().set_inputline(m_cpu, INPUT_LINE_IRQ2); + m_int->write_intr<3>().set_inputline(m_cpu, INPUT_LINE_IRQ3); + m_int->write_intr<4>().set_inputline(m_cpu, INPUT_LINE_IRQ4); + m_int->write_intr<5>().set_inputline(m_cpu, INPUT_LINE_IRQ5); + // TODO: write_led and write_poweroff outputs + // + // 0 scc.clk.sel external clock on for hp1 port 0 + // 1 ser0.sel rts/tx+ for hp1 port 0 (rts=1) + // 2 ser1.sel rts/tx+ for hp1 port 1 (rts=1) + // 3 clr.retrace- disable/enable vert. retrace intr. + // 4 poweroff + + EEPROM_93C56_16BIT(config, m_nvram); + + DP8572A(config, m_rtc, 32.768_kHz_XTAL).set_use_utc(true); + + NSCSI_BUS(config, "scsi", 0); + NSCSI_CONNECTOR(config, "scsi:0").option_set("wd33c93a", WD33C93A).machine_config( + [this](device_t *device) + { + wd33c93a_device &scsi = downcast(*device); + + scsi.set_clock(10_MHz_XTAL); + scsi.irq_cb().set(m_int, FUNC(sgi_int2_device::lio0_w)); + scsi.drq_cb().set(m_hpc, FUNC(hpc1_device::write_drq<0>)); + }); + 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, "cdrom", 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_eth, 0); + m_eth->out_int_cb().set(m_hpc, FUNC(hpc1_device::write_int)); + m_eth->out_rxrdy_cb().set(m_hpc, FUNC(hpc1_device::write_drq<1>)); + m_hpc->dma_r_cb<1>().set(m_eth, FUNC(seeq8003_device::fifo_r)); + m_hpc->dma_w_cb<1>().set(m_eth, FUNC(seeq8003_device::fifo_w)); + + // 24.576MHz + // 22.5792MHz + // 3.6720MHz + input_merger_any_high_device &scc_irq(INPUT_MERGER_ANY_HIGH(config, "scc_irq")); + scc_irq.output_handler().set(m_int, FUNC(sgi_int2_device::lio0_w)); + + // duart 0: keyboard/mouse ports + SCC85C30(config, m_scc[0], 10_MHz_XTAL); + m_scc[0]->configure_channels(3'686'400, 0, 3'686'400, 0); + m_scc[0]->out_int_callback().set(scc_irq, FUNC(input_merger_any_high_device::in_w<0>)); + + sgi_kbd_port_device &kbd_port(SGI_KBD_PORT(config, "keyboard_port")); + kbd_port.option_set("keyboard", SGI_KBD); + rs232_port_device &mouse_port(RS232_PORT(config, "mouse_port", 0)); + mouse_port.option_set("mouse", SGI_HLE_SERIAL_MOUSE); + m_scc[0]->out_txda_callback().set(kbd_port, FUNC(sgi_kbd_port_device::write_txd)); + kbd_port.rxd_handler().set(m_scc[0], FUNC(scc85c30_device::rxa_w)); + mouse_port.rxd_handler().set(m_scc[0], FUNC(scc85c30_device::rxb_w)); + + // duart 1: serial ports + SCC85C30(config, m_scc[1], 10_MHz_XTAL); + m_scc[1]->configure_channels(3'686'400, 0, 3'686'400, 0); + m_scc[1]->out_int_callback().set(scc_irq, FUNC(input_merger_any_high_device::in_w<1>)); + + rs232_port_device &rs232a(RS232_PORT(config, "rs232a", default_rs232_devices, nullptr)); + rs232_port_device &rs232b(RS232_PORT(config, "rs232b", default_rs232_devices, nullptr)); + m_scc[1]->out_txda_callback().set(rs232a, FUNC(rs232_port_device::write_txd)); + m_scc[1]->out_dtra_callback().set(rs232a, FUNC(rs232_port_device::write_dtr)); + m_scc[1]->out_rtsa_callback().set(rs232a, FUNC(rs232_port_device::write_rts)); + m_scc[1]->out_txdb_callback().set(rs232b, FUNC(rs232_port_device::write_txd)); + m_scc[1]->out_dtrb_callback().set(rs232b, FUNC(rs232_port_device::write_dtr)); + m_scc[1]->out_rtsb_callback().set(rs232b, FUNC(rs232_port_device::write_rts)); + rs232a.cts_handler().set(m_scc[1], FUNC(scc85c30_device::ctsa_w)); + rs232a.dcd_handler().set(m_scc[1], FUNC(scc85c30_device::dcda_w)); + rs232a.rxd_handler().set(m_scc[1], FUNC(scc85c30_device::rxa_w)); + rs232b.cts_handler().set(m_scc[1], FUNC(scc85c30_device::ctsb_w)); + rs232b.dcd_handler().set(m_scc[1], FUNC(scc85c30_device::dcdb_w)); + rs232b.rxd_handler().set(m_scc[1], FUNC(scc85c30_device::rxb_w)); + + // duart 2: "Apple" RS-422 serial ports (4D/PI only) + SCC85C30(config, m_scc[2], 10_MHz_XTAL); // Z8513010VSC ESCC + m_scc[2]->configure_channels(3'686'400, 0, 3'686'400, 0); + m_scc[2]->out_int_callback().set(scc_irq, FUNC(input_merger_any_high_device::in_w<1>)); + + DSP56001(config, m_dsp, 20_MHz_XTAL); + //m_dsp->moda_w(1); + //m_dsp->modb_w(0); + + SGI_LG1(config, m_gfx); + m_gfx->write_vblank().set(m_int, FUNC(sgi_int2_device::lio1_w)); +} + +void ip12_state::pi4d3x(machine_config &config) +{ + ip12(config); + + m_pic->set_input_default(DEVICE_INPUT_DEFAULTS_NAME(pi4d3x_pic1)); + + // serial port 3 + // FIXME: HSKO/HSKI/GPI + rs232_port_device &rs232c(RS232_PORT(config, "rs232c", default_rs232_devices, nullptr)); + m_scc[2]->out_txda_callback().set(rs232c, FUNC(rs232_port_device::write_txd)); + rs232c.rxd_handler().set(m_scc[2], FUNC(z80scc_device::rxa_w)); + + // serial port 4 + // FIXME: HSKO/HSKI/GPI + rs232_port_device &rs232d(RS232_PORT(config, "rs232d", default_rs232_devices, nullptr)); + m_scc[2]->out_txdb_callback().set(rs232d, FUNC(rs232_port_device::write_txd)); + rs232d.rxd_handler().set(m_scc[2], FUNC(z80scc_device::rxb_w)); +} + +void ip12_state::indigo(machine_config &config) +{ + R3000A(config, m_cpu, 66.0_MHz_XTAL / 2, 32768, 32768); + m_cpu->set_addrmap(AS_PROGRAM, &ip12_state::ip12_map); + // FIXME: route fpu interrupt via int2 + m_cpu->set_fpu(r3000a_device::MIPS_R3010A, INPUT_LINE_IRQ0); + + ip12(config); + + m_pic->set_input_default(DEVICE_INPUT_DEFAULTS_NAME(indigo_pic1)); + + m_brdrev = 0x8000; +} + +void ip12_state::pi4d30(machine_config &config) +{ + R3000A(config, m_cpu, 30_MHz_XTAL, 65536, 65536); + m_cpu->set_addrmap(AS_PROGRAM, &ip12_state::pi4d3x_map); + // FIXME: route fpu interrupt via int2 + m_cpu->set_fpu(r3000a_device::MIPS_R3010A, INPUT_LINE_IRQ0); + + pi4d3x(config); + + m_brdrev = 0x0000; +} + +void ip12_state::pi4d35(machine_config &config) +{ + R3000A(config, m_cpu, 36_MHz_XTAL, 65536, 65536); + m_cpu->set_addrmap(AS_PROGRAM, &ip12_state::pi4d3x_map); + // FIXME: route fpu interrupt via int2 + m_cpu->set_fpu(r3000a_device::MIPS_R3010A, INPUT_LINE_IRQ0); + + pi4d3x(config); + + // FIXME: higher revisions fail scsi power fuse diagnostic + m_brdrev = 0x0000; +} + +ROM_START(indigo) + ROM_REGION32_BE(0x40000, "prom", 0) // Am27C2048 128Kx16 + + // dumped over serial connection from boot monitor and swapped + ROM_SYSTEM_BIOS(0, "401-rev-c", "SGI Version 4.0.1 Rev C LG1/GR2, Jul 9, 1992") + ROMX_LOAD("ip12prom.070-8088-xxx.u56", 0x000000, 0x040000, CRC(25ca912f) SHA1(94b3753d659bfe50b914445cef41290122f43880), ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(0)) + + // dumped with EPROM programmer + ROM_SYSTEM_BIOS(1, "401-rev-d", "SGI Version 4.0.1 Rev D LG1/GR2, Mar 24, 1992") + ROMX_LOAD("ip12prom.070-8088-002.u56", 0x000000, 0x040000, CRC(ea4329ef) SHA1(b7d67d0e30ae8836892f7170dd4757732a0a3fd6), ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(1)) + + ROM_SYSTEM_BIOS(2, "sni", "SGI Version 4.0.1 Rev C LG1/GR2, Feb 14, 1992") + ROMX_LOAD("070-8088-001__a.u56", 0x000000, 0x040000, CRC(40eae7a0) SHA1(d60ef74cf04a16d9dad6b9594a66724d944b1208), ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(2)) +ROM_END + +ROM_START(pi4d30) + ROM_REGION32_BE(0x80000, "prom", 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(pi4d35) + ROM_REGION32_BE(0x80000, "prom", 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 + +} // anonymous namespace + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP(1991, pi4d30, 0, 0, pi4d30, 0, ip12_state, empty_init, "Silicon Graphics", "Personal IRIS 4D/30", MACHINE_NO_SOUND | MACHINE_IMPERFECT_GRAPHICS) +COMP(1991, pi4d35, 0, 0, pi4d35, 0, ip12_state, empty_init, "Silicon Graphics", "Personal IRIS 4D/35", MACHINE_NO_SOUND | MACHINE_IMPERFECT_GRAPHICS) +COMP(1991, indigo, 0, 0, indigo, 0, ip12_state, empty_init, "Silicon Graphics", "IRIS Indigo", MACHINE_NO_SOUND | MACHINE_IMPERFECT_GRAPHICS) diff --git a/src/mame/sgi/ip20.cpp b/src/mame/sgi/ip20.cpp new file mode 100644 index 00000000000..d68cbd29c06 --- /dev/null +++ b/src/mame/sgi/ip20.cpp @@ -0,0 +1,291 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * Silicon Graphics Indigo R4000/R4400 aka 4DRPC-50/Blackjack/HP2 (also VME-based V50) + * + * INT2 local I/O interrupt multiplexor + * HPC1.5 high-performance peripheral controller + * MC memory controller + * + */ + /* board revs of IP20 are: 1 & 2 were early blackjack spins + * 10 decimal == 0x0a == 1010binary == VME IP 20 board (V50) + * V50 board lacks audio hardware + * The upper bit used to change the standard (rev 2) board + * to the V50 designation (i.e the 0x8 bit) used to be known + * internally as the 'Hollywood processor 1 bit' or hp1 bit + */ + +#include "emu.h" +#include "cpu/mips/r4000.h" +#include "cpu/dsp56000/dsp56000.h" + +#include "machine/dp8573a.h" +#include "machine/edlc.h" +#include "machine/eepromser.h" +#include "machine/input_merger.h" +#include "machine/nscsi_bus.h" +#include "machine/wd33c9x.h" +#include "machine/z80scc.h" + +#include "bus/rs232/rs232.h" +#include "bus/rs232/hlemouse.h" +#include "bus/nscsi/cd.h" +#include "bus/nscsi/hd.h" + +#include "hpc1.h" +#include "int2.h" +#include "kbd.h" +#include "light.h" +#include "mc.h" + +//#define VERBOSE (LOG_GENERAL) +#include "logmacro.h" + +namespace { + +class ip20_state : public driver_device +{ +public: + ip20_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_cpu(*this, "cpu") + , m_eerom(*this, "eerom") + , m_mc(*this, "mc") + , m_hpc(*this, "hpc") + , m_int(*this, "int") + , m_nvram(*this, "nvram") + , m_rtc(*this, "rtc") + , m_scsi(*this, "scsi:0:wd33c93a") + , m_eth(*this, "eth") + , m_scc(*this, "scc%u", 0U) + , m_dsp(*this, "dsp") + , m_gfx(*this, "gfx") + { + } + + void indigo_r4000(machine_config &config); + void indigo_r4400(machine_config &config); + +protected: + void ip20(machine_config &config); + + virtual void machine_start() override; + virtual void machine_reset() override; + + void cpu_map(address_map &map); + + required_device m_cpu; + required_device m_eerom; + required_device m_mc; + required_device m_hpc; + required_device m_int; + required_device m_nvram; + required_device m_rtc; + required_device m_scsi; + required_device m_eth; + required_device_array m_scc; + required_device m_dsp; + required_device m_gfx; +}; + +void ip20_state::machine_start() +{ +} + +void ip20_state::machine_reset() +{ +} + +void ip20_state::cpu_map(address_map &map) +{ + //map(0x1fbd9000, 0x1fbd903f).rw(FUNC(indigo_state::int_r), FUNC(indigo_state::int_w)); + + //map(0x0000'0000, 0x0007'ffff); // system memory alias (512K) + //map(0x0008'0000, 0x0008'ffff); // EISA I/O space (64K) + //map(0x0009'0000, 0x0009'ffff); // EISA I/O space alias (64K) + //map(0x000a'0000, 0x07ff'ffff); // EISA memory (128M) + //map(0x0800'0000, 0x17ff'ffff); // physical memory segment 0 (256M) + //map(0x1800'0000, 0x1eff'ffff); // reserved (future GIO space) (112M) + //map(0x1f00'0000, 0x1f3f'ffff); // graphics system (4M) + //map(0x1f40'0000, 0x1f5f'ffff); // gio64 expansion slot 0 (2M) + //map(0x1f60'0000, 0x1f9f'ffff); // gio64 expansion slot 1 (4M) + //map(0x1fa0'0000, 0x1faf'ffff); // mc registers (1M) + //map(0x1fb0'0000, 0x1fbf'ffff); // hpc and i/o devices (1M) + //map(0x1fc0'0000, 0x1fff'ffff); // boot prom (4M) + //map(0x2000'0000, 0x2fff'ffff); // physical memory segment 1 (256M) + //map(0x3000'0000, 0x7fff'ffff); // reserved (1.25G) + //map(0x8000'0000, 0xffff'ffff); // EISA memory (2G) + + //map(0x1000'0000, 0x1eff'ffff).lr32([this]() { m_cpu->berr_w(1); return 0; }, "buserror"); // vme + + map(0x1f3f'0000, 0x1f3f'7fff).m(m_gfx, FUNC(sgi_lg1_device::map)); + + map(0x1fa0'0000, 0x1fa1'ffff).rw(m_mc, FUNC(sgi_mc_device::read), FUNC(sgi_mc_device::write)); + + map(0x1fb8'0000, 0x1fb8'ffff).m(m_hpc, FUNC(hpc1_device::map)); + map(0x1fb8'0100, 0x1fb8'011f).m(m_eth, FUNC(seeq8003_device::map)).umask32(0xff); + map(0x1fb8'0120, 0x1fb8'0127).rw(m_scsi, FUNC(wd33c93a_device::indir_r), FUNC(wd33c93a_device::indir_w)).umask32(0xff00); + map(0x1fb8'01c0, 0x1fb8'01ff).m(m_int, FUNC(sgi_int2_device::map)).umask32(0xff); + map(0x1fb8'0d00, 0x1fb8'0d0f).rw(m_scc[0], FUNC(scc85c30_device::ab_dc_r), FUNC(scc85c30_device::ab_dc_w)).umask32(0xff); + map(0x1fb8'0d10, 0x1fb8'0d1f).rw(m_scc[1], FUNC(scc85c30_device::ab_dc_r), FUNC(scc85c30_device::ab_dc_w)).umask32(0xff); + //map(0x1fb8'0d20, 0x1fb8'0d2f).rw(m_scc[2], FUNC(scc85c30_device::ab_dc_r), FUNC(scc85c30_device::ab_dc_w)).umask32(0xff); // V50 only? + map(0x1fb8'0d30, 0x1fb8'0d37).noprw(); // TODO: left/right headphone gain mdacs + map(0x1fb8'0e00, 0x1fb8'0e7f).rw(m_rtc, FUNC(dp8572a_device::read), FUNC(dp8572a_device::write)).umask32(0xff); + map(0x1fbd'0000, 0x1fbd'0003).lr32([]() { return 0x0000'8000; }, "board_rev"); // board revision register + + map(0x1fbe'0000, 0x1fbf'ffff).ram().share("dsp_ram"); // 3xTC55328J-35 (24 bits x 32k) + + map(0x1fc0'0000, 0x1fc7'ffff).rom().region("prom", 0); +} + +static void scsi_devices(device_slot_interface &device) +{ + device.option_add("cdrom", NSCSI_CDROM_SGI).machine_config( + [](device_t *device) + { + downcast(*device).set_block_size(512); + }); + device.option_add("harddisk", NSCSI_HARDDISK); +} + +void ip20_state::indigo_r4000(machine_config &config) +{ + R4000(config, m_cpu, 50'000'000); + + ip20(config); +} + +void ip20_state::indigo_r4400(machine_config &config) +{ + R4400(config, m_cpu, 75'000'000); + + ip20(config); +} + +void ip20_state::ip20(machine_config &config) +{ + m_cpu->set_addrmap(AS_PROGRAM, &ip20_state::cpu_map); + + EEPROM_93C56_16BIT(config, m_eerom); + + SGI_MC(config, m_mc, m_cpu, m_eerom, 50'000'000); + m_mc->eisa_present().set_constant(0); + + SGI_HPC1(config, m_hpc, 0); + m_hpc->set_gio(m_cpu, AS_PROGRAM); + m_hpc->set_enet(m_eth); + m_hpc->int_w().set(m_int, FUNC(sgi_int2_device::lio0_w)); + m_hpc->dma_r_cb<0>().set(m_scsi, FUNC(wd33c93a_device::dma_r)); + m_hpc->dma_w_cb<0>().set(m_scsi, FUNC(wd33c93a_device::dma_w)); + m_hpc->eeprom_dati().set(m_nvram, FUNC(eeprom_serial_93cxx_device::do_read)); + m_hpc->eeprom_out().set( + [this](u8 data) + { + // TODO: bit 0 console led + m_nvram->di_write(BIT(data, 3)); + m_nvram->cs_write(BIT(data, 1)); + m_nvram->clk_write(BIT(data, 2)); + }); + + SGI_INT2(config, m_int, 10_MHz_XTAL); + m_int->write_intr<1>().set_inputline(m_cpu, INPUT_LINE_IRQ1); + m_int->write_intr<2>().set_inputline(m_cpu, INPUT_LINE_IRQ2); + m_int->write_intr<3>().set_inputline(m_cpu, INPUT_LINE_IRQ3); + m_int->write_intr<4>().set_inputline(m_cpu, INPUT_LINE_IRQ4); + m_int->write_intr<5>().set_inputline(m_cpu, INPUT_LINE_IRQ5); + // TODO: write_led and write_poweroff outputs + // + // 0 cache parity error? + // 1 1Hz heartbeat + // 2 off when cpu is idle + // 3 graphics + // 4 poweroff? + + EEPROM_93C56_16BIT(config, m_nvram); + + DP8572A(config, m_rtc, 32.768_kHz_XTAL).set_use_utc(true); + + NSCSI_BUS(config, "scsi", 0); + NSCSI_CONNECTOR(config, "scsi:0").option_set("wd33c93a", WD33C93A).machine_config( + [this](device_t *device) + { + wd33c93a_device &scsi = downcast(*device); + + scsi.set_clock(10_MHz_XTAL); + scsi.irq_cb().set(m_int, FUNC(sgi_int2_device::lio0_w)); + scsi.drq_cb().set(m_hpc, FUNC(hpc1_device::write_drq<0>)); + }); + 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, "cdrom", 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_eth, 0); + m_eth->out_int_cb().set(m_hpc, FUNC(hpc1_device::write_int)); + m_eth->out_rxrdy_cb().set(m_hpc, FUNC(hpc1_device::write_drq<1>)); + m_hpc->dma_r_cb<1>().set(m_eth, FUNC(seeq8003_device::fifo_r)); + m_hpc->dma_w_cb<1>().set(m_eth, FUNC(seeq8003_device::fifo_w)); + + input_merger_any_high_device &scc_irq(INPUT_MERGER_ANY_HIGH(config, "scc_irq")); + scc_irq.output_handler().set(m_int, FUNC(sgi_int2_device::lio0_w)); + + // duart 0 + SCC85C30(config, m_scc[0], 10_MHz_XTAL); + m_scc[0]->configure_channels(3'686'400, 0, 3'686'400, 0); + m_scc[0]->out_int_callback().set(scc_irq, FUNC(input_merger_any_high_device::in_w<0>)); + + sgi_kbd_port_device &kbd_port(SGI_KBD_PORT(config, "keyboard_port")); + kbd_port.option_set("keyboard", SGI_KBD); + rs232_port_device &mouse_port(RS232_PORT(config, "mouse_port", 0)); + mouse_port.option_set("mouse", SGI_HLE_SERIAL_MOUSE); + m_scc[0]->out_txda_callback().set(kbd_port, FUNC(sgi_kbd_port_device::write_txd)); + kbd_port.rxd_handler().set(m_scc[0], FUNC(scc85c30_device::rxa_w)); + mouse_port.rxd_handler().set(m_scc[0], FUNC(scc85c30_device::rxb_w)); + + // duart 1 + SCC85C30(config, m_scc[1], 10_MHz_XTAL); + m_scc[1]->configure_channels(3'686'400, 0, 3'686'400, 0); + m_scc[1]->out_int_callback().set(scc_irq, FUNC(input_merger_any_high_device::in_w<1>)); + + rs232_port_device &rs232a(RS232_PORT(config, "rs232a", default_rs232_devices, nullptr)); + rs232_port_device &rs232b(RS232_PORT(config, "rs232b", default_rs232_devices, nullptr)); + m_scc[1]->out_txda_callback().set(rs232a, FUNC(rs232_port_device::write_txd)); + m_scc[1]->out_dtra_callback().set(rs232a, FUNC(rs232_port_device::write_dtr)); + m_scc[1]->out_rtsa_callback().set(rs232a, FUNC(rs232_port_device::write_rts)); + m_scc[1]->out_txdb_callback().set(rs232b, FUNC(rs232_port_device::write_txd)); + m_scc[1]->out_dtrb_callback().set(rs232b, FUNC(rs232_port_device::write_dtr)); + m_scc[1]->out_rtsb_callback().set(rs232b, FUNC(rs232_port_device::write_rts)); + rs232a.cts_handler().set(m_scc[1], FUNC(scc85c30_device::ctsa_w)); + rs232a.dcd_handler().set(m_scc[1], FUNC(scc85c30_device::dcda_w)); + rs232a.rxd_handler().set(m_scc[1], FUNC(scc85c30_device::rxa_w)); + rs232b.cts_handler().set(m_scc[1], FUNC(scc85c30_device::ctsb_w)); + rs232b.dcd_handler().set(m_scc[1], FUNC(scc85c30_device::dcdb_w)); + rs232b.rxd_handler().set(m_scc[1], FUNC(scc85c30_device::rxb_w)); + + // duart 2 + SCC85C30(config, m_scc[2], 10_MHz_XTAL); + m_scc[2]->configure_channels(3'686'400, 0, 3'686'400, 0); + m_scc[2]->out_int_callback().set(scc_irq, FUNC(input_merger_any_high_device::in_w<2>)); + + DSP56001(config, m_dsp, 20_MHz_XTAL); + + SGI_LG1(config, m_gfx); + m_gfx->write_vblank().set(m_int, FUNC(sgi_int2_device::lio1_w)); +} + +ROM_START(indigo_r4000) + ROM_REGION64_BE(0x80000, "prom", 0) + ROMX_LOAD("ip20prom.070-8116-004.bin", 0x000000, 0x080000, CRC(940d960e) SHA1(596aba530b53a147985ff3f6f853471ce48c866c), ROM_GROUPDWORD | ROM_REVERSE) +ROM_END + +#define rom_indigo_r4400 rom_indigo_r4000 +} // anonymous namespace + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP(1992, indigo_r4000, 0, 0, indigo_r4000, 0, ip20_state, empty_init, "Silicon Graphics", "IRIS Indigo R4000", MACHINE_NO_SOUND | MACHINE_IMPERFECT_GRAPHICS) +COMP(1991, indigo_r4400, 0, 0, indigo_r4400, 0, ip20_state, empty_init, "Silicon Graphics", "IRIS Indigo R4400", MACHINE_NO_SOUND | MACHINE_IMPERFECT_GRAPHICS) diff --git a/src/mame/sgi/4dpi.cpp b/src/mame/sgi/ip6.cpp similarity index 61% rename from src/mame/sgi/4dpi.cpp rename to src/mame/sgi/ip6.cpp index 59f06222013..e7f0cf2da36 100644 --- a/src/mame/sgi/4dpi.cpp +++ b/src/mame/sgi/ip6.cpp @@ -1,35 +1,40 @@ // license:BSD-3-Clause // copyright-holders:Patrick Mackinlay /* - * SGI Personal IRIS family driver + * Silicon Graphics Personal IRIS 4D/20 and 4D/25. * * 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 + * - VME-Eclipse CPU (VIP10) Specification, Silicon Graphics, Inc. + * - SGI IP-6 Schematic * - 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) + * - 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) + */ + +/* + * Installation instructions + * -- + * 1. boot, enter monitor, set ethernet address: eaddr 08:00:69:12:34:56 + * 2. start mame with CDROM iso image as hard disk ID 6: mame 4d20 ... -scsi:6 harddisk -hard2 pathname.iso + * 3. boot, enter monitor, launch sash: boot -f dksc(0,6,8)sash.IP6 + * 4. */ #include "emu.h" @@ -71,10 +76,10 @@ namespace { -class pi4d2x_state : public driver_device +class ip6_state : public driver_device { public: - pi4d2x_state(machine_config const &mconfig, device_type type, char const *tag) + ip6_state(machine_config const &mconfig, device_type type, char const *tag) : driver_device(mconfig, type, tag) , m_cpu(*this, "maincpu") , m_ram(*this, "ram") @@ -233,66 +238,13 @@ private: u16 m_gdma_buflen = 0; // 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") - { - std::fill(std::begin(m_lio_isr), std::end(m_lio_isr), 0 ); - } - - void pi4d30(machine_config &config); - void pi4d35(machine_config &config); - - void initialize(); - -private: - required_device m_cpu; - required_device m_ram; - required_region_ptr m_eprom; - required_device m_eeprom; - - required_device m_rtc; - required_device m_pit; - required_device m_scsi; - required_device m_enet; - required_device_array m_duart; - required_device_array m_serial; - required_device m_dsp; - - void common(machine_config &config); - void map(address_map &map); - - template 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) +void ip6_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)); + map(0x10000000, 0x1effffff).rw(FUNC(ip6_state::buserror_r), FUNC(ip6_state::buserror_w)); // TODO: 1 32-bit 6U VME slot //map(0x10000000, 0x1bffffff); // vme a32 modifier 0x09 non-privileged @@ -306,7 +258,7 @@ void pi4d2x_state::map(address_map &map) 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(0x1f800000, 0x1f800003).r(FUNC(ip6_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); @@ -479,7 +431,7 @@ void pi4d2x_state::map(address_map &map) 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(0x1fa80008, 0x1fa8000b).rw(FUNC(ip6_state::buserror_r), FUNC(ip6_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); @@ -500,110 +452,7 @@ void pi4d2x_state::map(address_map &map) 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(dp8572a_device::read), FUNC(dp8572a_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"); + map(0x40000000, 0xffffffff).rw(FUNC(ip6_state::buserror_r), FUNC(ip6_state::buserror_w)); } static void scsi_devices(device_slot_interface &device) @@ -616,7 +465,7 @@ static void scsi_devices(device_slot_interface &device) device.option_add("harddisk", NSCSI_HARDDISK); } -void pi4d2x_state::pi4d20(machine_config &config) +void ip6_state::pi4d20(machine_config &config) { R3000(config, m_cpu, 25_MHz_XTAL / 2, 16384, 8192); m_cpu->set_fpu(mips1_device_base::MIPS_R3010); @@ -624,7 +473,7 @@ void pi4d2x_state::pi4d20(machine_config &config) common(config); } -void pi4d2x_state::pi4d25(machine_config &config) +void ip6_state::pi4d25(machine_config &config) { R3000(config, m_cpu, 20_MHz_XTAL, 32768, 65536); m_cpu->set_fpu(mips1_device_base::MIPS_R3010); @@ -632,26 +481,9 @@ void pi4d2x_state::pi4d25(machine_config &config) common(config); } -void pi4d3x_state::pi4d30(machine_config &config) +void ip6_state::common(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->set_addrmap(AS_PROGRAM, &ip6_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 @@ -678,8 +510,8 @@ void pi4d2x_state::common(machine_config &config) wd33c9x_base_device &wd33c93(downcast(*device)); wd33c93.set_clock(10000000); - wd33c93.irq_cb().set(*this, FUNC(pi4d2x_state::lio_interrupt)).invert(); - wd33c93.drq_cb().set(*this, FUNC(pi4d2x_state::scsi_drq)); + wd33c93.irq_cb().set(*this, FUNC(ip6_state::lio_interrupt)).invert(); + wd33c93.drq_cb().set(*this, FUNC(ip6_state::scsi_drq)); }); NSCSI_CONNECTOR(config, "scsi:1", scsi_devices, "harddisk", false); NSCSI_CONNECTOR(config, "scsi:2", scsi_devices, nullptr, false); @@ -690,7 +522,7 @@ void pi4d2x_state::common(machine_config &config) NSCSI_CONNECTOR(config, "scsi:7", scsi_devices, nullptr, false); AM7990(config, m_enet); - m_enet->intr_out().set(FUNC(pi4d2x_state::lio_interrupt)); + m_enet->intr_out().set(FUNC(ip6_state::lio_interrupt)); m_enet->dma_in().set( [this](offs_t offset) { @@ -719,7 +551,7 @@ void pi4d2x_state::common(machine_config &config) "mouse")); // duart 0 outputs - m_duart[0]->irq_cb().set(FUNC(pi4d2x_state::lio_interrupt)).invert(); + m_duart[0]->irq_cb().set(FUNC(ip6_state::lio_interrupt)).invert(); m_duart[0]->a_tx_cb().set(keyboard_port, FUNC(sgi_kbd_port_device::write_txd)); m_duart[0]->b_tx_cb().set(mouse_port, FUNC(rs232_port_device::write_txd)); @@ -733,7 +565,7 @@ void pi4d2x_state::common(machine_config &config) RS232_PORT(config, m_serial[1], default_rs232_devices, nullptr); // duart 1 outputs - m_duart[1]->irq_cb().set(FUNC(pi4d2x_state::lio_interrupt)).invert(); + m_duart[1]->irq_cb().set(FUNC(ip6_state::lio_interrupt)).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( @@ -769,8 +601,8 @@ void pi4d2x_state::common(machine_config &config) else m_lio_isr |= (1U << LIO_VRSTAT); }); - m_gfx->out_int().set(*this, FUNC(pi4d2x_state::lio_interrupt)).invert(); - m_gfx->out_int_fifo().set(*this, FUNC(pi4d2x_state::lio_interrupt)).invert(); + m_gfx->out_int().set(*this, FUNC(ip6_state::lio_interrupt)).invert(); + m_gfx->out_int_fifo().set(*this, FUNC(ip6_state::lio_interrupt)).invert(); // TODO: vme slot, cpu interrupt 0 @@ -779,125 +611,7 @@ void pi4d2x_state::common(machine_config &config) config.set_default_layout(layout_4dpi); } -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); - - DP8572A(config, m_rtc, 32.768_kHz_XTAL); - - // 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(*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_kbd_port_device &keyboard_port(SGI_KBD_PORT(config, "keyboard_port", default_sgi_kbd_devices, "keyboard")); - m_duart[0]->out_txdb_callback().set(keyboard_port, FUNC(sgi_kbd_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() +void ip6_state::initialize() { // map the configured ram m_cpu->space(0).install_ram(0x00000000, m_ram->mask(), m_ram->pointer()); @@ -916,13 +630,7 @@ void pi4d2x_state::initialize() 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) +void ip6_state::lio_interrupt(unsigned number, int state) { u16 const mask = 1 << number; @@ -950,27 +658,7 @@ void pi4d2x_state::lio_interrupt(unsigned number, int state) } } -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) +void ip6_state::scsi_drq(int state) { if (state) { @@ -984,7 +672,7 @@ void pi4d2x_state::scsi_drq(int state) } } -u8 pi4d2x_state::sysid_r() +u8 ip6_state::sysid_r() { u8 data = m_sysid; @@ -994,7 +682,7 @@ u8 pi4d2x_state::sysid_r() return data; } -ROM_START(4d20) +ROM_START(pi4d20) ROM_REGION32_BE(0x40000, "boot", 0) // 3.2e firmware has been found in both 4D/20 and 4D/25 hardware ROM_SYSTEM_BIOS(0, "3.2e", "Version 3.2 Rev E, Fri Jul 14 14:37:38 PDT 1989 SGI") @@ -1016,7 +704,7 @@ ROM_START(4d20) ROMX_LOAD("070_8000_003_boot_3.h1e6", 0x000003, 0x010000, CRC(48b9322c) SHA1(600554a0ccc4bab4881a96a9886eea40cd04c8e4), ROM_BIOS(2) | ROM_SKIP(3)) ROM_END -ROM_START(4d25) +ROM_START(pi4d25) 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)) @@ -1025,30 +713,8 @@ ROM_START(4d25) 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 - } // anonymous namespace - -// 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) +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP(1988, pi4d20, 0, 0, pi4d20, 0, ip6_state, initialize, "Silicon Graphics", "Personal IRIS 4D/20", MACHINE_NO_SOUND | MACHINE_IMPERFECT_GRAPHICS) +COMP(1989, pi4d25, 0, 0, pi4d25, 0, ip6_state, initialize, "Silicon Graphics", "Personal IRIS 4D/25", MACHINE_NO_SOUND | MACHINE_IMPERFECT_GRAPHICS) diff --git a/src/mame/sgi/pic1.cpp b/src/mame/sgi/pic1.cpp new file mode 100644 index 00000000000..d60b150f93c --- /dev/null +++ b/src/mame/sgi/pic1.cpp @@ -0,0 +1,237 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * Silicon Graphics Processor Interface Controller (PIC1). + * + * TODO: + * - parity + * - graphics dma + * - vme bus + * + */ +#include "emu.h" +#include "pic1.h" + +//#define VERBOSE (LOG_GENERAL) + +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(SGI_PIC1, sgi_pic1_device, "sgi_pic1", "SGI PIC1") + +enum config_mask : u32 +{ + CONFIG_RFE = 0x0001, // refresh enable + CONFIG_BIGEND = 0x0002, // endianness + CONFIG_DBE = 0x0004, // enable data block refill + CONFIG_IBE = 0x0008, // enable instr block refill + CONFIG_GDE = 0x0010, // graphics dma complete int enable + CONFIG_GSE = 0x0020, // graphics dma sync enable + CONFIG_FREF = 0x0040, // fast refresh (giobus >= 33 mhz) + CONFIG_DVMEBE = 0x0080, // disable vme bus error + CONFIG_OLDFREF = 0x0080, // rfr for pre pic1.5 (rev <= b) + CONFIG_GR2 = 0x0100, // gr2 giobus mode + CONFIG_INIT = 0x0200, // drive vme sysreset (will reset cpu) + CONFIG_ENPAR = 0x0400, // parity check on memory reads + CONFIG_SLAVE = 0x0800, // allow slave accesses to board + CONFIG_ARB = 0x1000, // enable vme arbiter function + CONFIG_BADPAR = 0x2000, // write bad parity + CONFIG_DOG = 0x4000, // enable watchdog timeout + CONFIG_GRRESET = 0x8000, // reset graphics subsystem +}; + +enum sid_mask : u32 +{ + SID_FPPRES = 0x0001, // fpu present (1=absent) + SID_DMAERR = 0x0004, // dma error + SID_DMAIDLE = 0x0008, // dma ended + SID_VMERMW = 0x0020, // vme read-modify-write cycle active + SID_REV = 0x01c0, // chip revision + + SID_REVA = 0x0000, + SID_REVB = 0x0040, + SID_REVC = 0x0080, +}; + +sgi_pic1_device::sgi_pic1_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : device_t(mconfig, SGI_PIC1, tag, owner, clock) + , m_bus(*this, finder_base::DUMMY_TAG, -1, 32) + , m_simms(*this, "SIMMS") + , m_memcfg{ 0x003f003f, 0x003f003f } +{ +} + +void sgi_pic1_device::device_start() +{ +} + +void sgi_pic1_device::device_reset() +{ + u8 const simms = m_simms->read(); + + // allocate installed memory + unsigned bank16m = 0; + for (unsigned bank = 0; bank < 4; bank++) + { + unsigned const size = BIT(simms, bank * 2, 2); + + switch (size) + { + case 0: + LOG("ram bank %c empty\n", bank + 'A'); + m_ram[bank].reset(); + break; + case 2: + bank16m++; + [[fallthrough]]; + default: + LOG("ram bank %c size %dM\n", bank + 'A', 1U << (size + 2)); + m_ram[bank] = std::make_unique(1U << (size + 22)); + break; + } + } + + if (bank16m > 1) + logerror("invalid memory configuration, at most one bank may contain 4M SIMMs\n"); + + m_cpuctrl = CONFIG_BIGEND; + + // assume memory configuration is invalidated by reset + memcfg_w(0, 0x003f003f); + memcfg_w(1, 0x003f003f); + + m_sid = SID_DMAIDLE; + + m_dabr = 0; +} + +void sgi_pic1_device::map(address_map &map) +{ + // system registers + map(0x0'0000, 0x0'0003).rw(FUNC(sgi_pic1_device::cpuctrl_r), FUNC(sgi_pic1_device::cpuctrl_w)); + //map(0x0'0004, 0x0'0007); // RSTCONFIG system mode register + map(0x0'0008, 0x0'000b).r(FUNC(sgi_pic1_device::sid_r)); + + // memory configuration registers + map(0x1'0000, 0x1'0007).rw(FUNC(sgi_pic1_device::memcfg_r), FUNC(sgi_pic1_device::memcfg_w)); + //map(0x1'0100, 0x1'0103); // REFTIM0 refresh timer (wo) + + // memory parity error registers + map(0x1'0200, 0x1'0203).nopr(); // PARERR parity error register (ro) + map(0x1'0204, 0x1'0207).nopr(); // CPUPARADR cpu parity error address (ro) + map(0x1'0208, 0x1'020b).nopr(); // DMAPARADR dma slave parity error address (ro) + map(0x1'0210, 0x1'0213).w(FUNC(sgi_pic1_device::parcl_ws)); + + // gio bus config + map(0x2'0000, 0x2'0003).nopw(); // GIO_SLOT0 slot 0 config register + map(0x2'0004, 0x2'0007).nopw(); // GIO_SLOT1 slot 1 config register + map(0x2'0008, 0x2'000b).nopw(); // GIO_BURST arbiter burst register + map(0x2'000c, 0x2'000f).nopw(); // GIO_DELAY arbiter delay register + + // three-way transfer + //map(0x7'0000, 0x7'0003); // TW_TRIG 3-way transfer trigger data + //map(0x8'0000, 0x8'0003); // TW_STATUS 3-way status (ro) + //map(0x8'0004, 0x8'0007); // TW_START 3-way transfer start address (ro) + //map(0x8'0008, 0x8'000b); // TW_MASK 3-way transfer address mask + //map(0x8'000c, 0x8'000f); // TW_SUBS 3-way transfer address substitute + + // graphics channel registers + map(0xa'0000, 0xa'0003).rw(FUNC(sgi_pic1_device::dabr_r), FUNC(sgi_pic1_device::dabr_w)); + //map(0xa'0004, 0xa'0007); // buffer address (ro) + //map(0xa'0008, 0xa'000b); // buffer length (ro) + //map(0xa'000c, 0xa'000f); // graphics operand address (ro) + //map(0xa'0010, 0xa'0013); // stride/line count (ro) + //map(0xa'0014, 0xa'0017); // next descriptor pointer (ro) + //map(0xa'0100, 0xa'0103); // start graphics dma +} + +void sgi_pic1_device::memcfg_w(offs_t offset, u32 data) +{ + LOG("memcfg%d 0x%08x\n", offset, data); + + // remove existing mapping + for (unsigned bank = 0; bank < 2; bank++) + { + u32 const base = BIT(m_memcfg[offset], 16 - bank * 16, 6) << 22; + + if (base != 0x3f) + { + unsigned const size = ram_size(offset * 2 + bank); + if (size) + { + LOG("unmap bank %c 0x%08x to 0x%08x\n", offset * 2 + bank + 'A', base, base + size - 1); + m_bus->unmap_readwrite(base, base + size - 1); + } + } + } + + m_memcfg[offset] = data; + + // install configured mapping + for (unsigned bank = 0; bank < 2; bank++) + { + u32 const base = BIT(m_memcfg[offset], 16 - bank * 16, 6) << 22; + + if (base != 0x3f) + { + unsigned const size = ram_size(offset * 2 + bank); + if (size) + { + LOG("remap bank %c 0x%08x to 0x%08x\n", offset * 2 + bank + 'A', base, base + size - 1); + m_bus->install_ram(base, base + size - 1, m_ram[offset * 2 + bank].get()); + } + } + } +} + +void sgi_pic1_device::parcl_ws(u32 data) +{ + LOG("clear parity error\n"); +} + +// return bytes available in a bank (minimum of installed and configured ram) +unsigned sgi_pic1_device::ram_size(unsigned bank) const +{ + unsigned const inst_size = BIT(m_simms->read(), bank * 2, 2); + unsigned const conf_size = BIT(m_memcfg[bank >> 1], 24 - (bank & 1) * 16, 4); + + if (inst_size && conf_size) + return std::min((conf_size + 1) << 22, 1U << (inst_size + 22)); + else + return 0; +} + +static INPUT_PORTS_START(pic1) + PORT_START("VALID") + PORT_CONFNAME(0x0f, 0x00, "Valid Banks") + + PORT_START("SIMMS") + PORT_CONFNAME(0x03, 0x02, "RAM bank A") PORT_CONDITION("VALID", 0x01, EQUALS, 0x01) + PORT_CONFSETTING(0x00, "Empty") + PORT_CONFSETTING(0x01, "4x2M") + PORT_CONFSETTING(0x02, "4x4M") + PORT_CONFSETTING(0x03, "4x8M") + + PORT_CONFNAME(0x0c, 0x00, "RAM bank B") PORT_CONDITION("VALID", 0x02, EQUALS, 0x02) + PORT_CONFSETTING(0x00, "Empty") + PORT_CONFSETTING(0x04, "4x2M") + PORT_CONFSETTING(0x08, "4x4M") + PORT_CONFSETTING(0x0c, "4x8M") + + PORT_CONFNAME(0x30, 0x00, "RAM bank C") PORT_CONDITION("VALID", 0x04, EQUALS, 0x04) + PORT_CONFSETTING(0x00, "Empty") + PORT_CONFSETTING(0x10, "4x2M") + PORT_CONFSETTING(0x20, "4x4M") + PORT_CONFSETTING(0x30, "4x8M") + + PORT_CONFNAME(0xc0, 0x00, "RAM bank D") PORT_CONDITION("VALID", 0x08, EQUALS, 0x08) + PORT_CONFSETTING(0x00, "Empty") + PORT_CONFSETTING(0x40, "4x2M") + PORT_CONFSETTING(0x80, "4x4M") + PORT_CONFSETTING(0xc0, "4x8M") +INPUT_PORTS_END + +ioport_constructor sgi_pic1_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(pic1); +} diff --git a/src/mame/sgi/pic1.h b/src/mame/sgi/pic1.h new file mode 100644 index 00000000000..3629ff96db8 --- /dev/null +++ b/src/mame/sgi/pic1.h @@ -0,0 +1,54 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_SGI_PIC1_H +#define MAME_SGI_PIC1_H + +#pragma once + +class sgi_pic1_device + : public device_t +{ +public: + sgi_pic1_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock); + + template void set_bus(T &&tag, int spacenum) { m_bus.set_tag(std::forward(tag), spacenum); } + + void map(address_map &map); + +protected: + // device_t implementation + virtual void device_start() override; + virtual void device_reset() override; + virtual ioport_constructor device_input_ports() const override; + + // read handlers + u32 cpuctrl_r() { return m_cpuctrl; } + u32 sid_r() { return m_sid; } + u32 memcfg_r(offs_t offset) { return m_memcfg[offset]; } + u32 dabr_r() { return m_dabr; } + + // write handlers + void cpuctrl_w(u32 data) { m_cpuctrl = data; } + void memcfg_w(offs_t offset, u32 data); + void parcl_ws(u32 data); + void dabr_w(u32 data) { m_dabr = data; } + + // helpers + unsigned ram_size(unsigned bank) const; + +private: + required_address_space m_bus; + required_ioport m_simms; + + std::unique_ptr m_ram[4]; + + u32 m_cpuctrl; // cpu board control and status + u32 m_sid; // system id/coprocessor present + u32 m_memcfg[2]; // memory configuration + u32 m_dabr; // descriptor array base +}; + +DECLARE_DEVICE_TYPE(SGI_PIC1, sgi_pic1_device) + +#endif // MAME_SGI_PIC1_H