// license:BSD-3-Clause // copyright-holders:Ryan Holtz /********************************************************************** SGI HPC1 "High-performance Peripheral Controller" emulation **********************************************************************/ #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 "bus/sgikbd/sgikbd.h" #include "machine/hpc1.h" #include "speaker.h" #define LOG_UNKNOWN (1 << 0) #define LOG_READS (1 << 1) #define LOG_WRITES (1 << 2) #define LOG_INT (1 << 3) #define LOG_EEPROM (1 << 4) #define LOG_SCSI (1 << 5) #define LOG_SCSI_DMA (1 << 6) #define LOG_DUART0 (1 << 7) #define LOG_DUART1 (1 << 8) #define LOG_DUART2 (1 << 9) #define LOG_PIT (1 << 10) #define LOG_CHAIN (1 << 11) #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 VERBOSE (LOG_UNKNOWN) #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"; /*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); 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") { } 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_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_duart_int_status)); } 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_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); } //************************************************************************** // DEVICE HARDWARE //************************************************************************** void hpc1_device::cdrom_config(device_t *device) { // cdda_device *cdda = device->subdevice("cdda"); // cdda->add_route(ALL_OUTPUTS, "^^mono", 1.0); } void hpc1_device::indigo_mice(device_slot_interface &device) { device.option_add("sgimouse", SGI_HLE_SERIAL_MOUSE); } void hpc1_device::scsi_devices(device_slot_interface &device) { device.option_add("cdrom", NSCSI_CDROM_SGI); device.option_add("harddisk", NSCSI_HARDDISK); } void hpc1_device::wd33c93(device_t *device) { 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)); } void hpc1_device::device_add_mconfig(machine_config &config) { 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", FUNC(sgi_keyboard_port_device::write_txd)); 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)); SGIKBD_PORT(config, "keyboard", default_sgi_keyboard_devices, "hlekbd").rxd_handler().set(m_scc[0], FUNC(z80scc_device::rxa_w)); rs232_port_device &mouseport(RS232_PORT(config, "mouseport", 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); DP8573(config, m_rtc); 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(); } //************************************************************************** // REGISTER ACCESS //************************************************************************** uint32_t hpc1_device::read(offs_t offset, uint32_t mem_mask) { if (offset >= 0x0e00/4 && offset <= 0x0e7c/4) return m_rtc->read(offset - 0xe00/4); 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; } void hpc1_device::write(offs_t offset, uint32_t data, uint32_t mem_mask) { if (offset >= 0x0e00/4 && offset <= 0x0e7c/4) { m_rtc->write(offset - 0xe00/4, (uint8_t)data); return; } switch (offset) { 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; 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) { 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)); } break; case 0x0124/4: if (ACCESSING_BITS_8_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)); } 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" ); if (BIT(data, 2)) LOGMASKED(LOG_WRITES, " Set IRQA polarity high\n" ); else LOGMASKED(LOG_WRITES, " Set IRQA polarity low\n" ); if (BIT(data, 3)) LOGMASKED(LOG_WRITES, " SRAM size: 32K\n" ); else LOGMASKED(LOG_WRITES, " SRAM size: 8K\n" ); 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)) { LOGMASKED(LOG_EEPROM, " CPU board LED on\n"); } 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)) { m_scsi_dma.m_active = false; m_scsi_dma.m_ctrl &= ~HPC_DMACTRL_ENABLE; return; } m_scsi_dma.m_desc = m_scsi_dma.m_next & 0x0fffffff; fetch_chain(); } } WRITE_LINE_MEMBER(hpc1_device::scsi_drq) { m_scsi_dma.m_drq = state; if (m_scsi_dma.m_drq && m_scsi_dma.m_active) { do_scsi_dma(); } } void hpc1_device::do_scsi_dma() { if (m_scsi_dma.m_to_mem) m_cpu_space->write_byte(m_scsi_dma.m_addr & 0x0fffffff, m_wd33c93->dma_r()); else m_wd33c93->dma_w(m_cpu_space->read_byte(m_scsi_dma.m_addr & 0x0fffffff)); m_scsi_dma.m_addr++; decrement_chain(); if (!m_scsi_dma.m_active) { // clear HPC3 DMA active flag m_scsi_dma.m_ctrl &= ~HPC_DMACTRL_ENABLE; } } //************************************************************************** // PIT TIMERS //************************************************************************** void hpc1_device::set_timer_int_clear(uint32_t 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); } } WRITE_LINE_MEMBER(hpc1_device::timer0_int) { LOGMASKED(LOG_PIT, "Timer0 Interrupt: %d\n", state); if (state) m_maincpu->set_input_line(MIPS3_IRQ2, ASSERT_LINE); } WRITE_LINE_MEMBER(hpc1_device::timer1_int) { LOGMASKED(LOG_PIT, "Timer2 Interrupt: %d\n", state); if (state) m_maincpu->set_input_line(MIPS3_IRQ3, ASSERT_LINE); } WRITE_LINE_MEMBER(hpc1_device::timer2_int) { LOGMASKED(LOG_PIT, "Timer2 Interrupt (Disabled): %d\n", state); } //************************************************************************** // SERIAL DUARTS //************************************************************************** WRITE_LINE_MEMBER(hpc1_device::duart0_int_w) { duart_int_w(0, state); } WRITE_LINE_MEMBER(hpc1_device::duart1_int_w) { duart_int_w(1, state); } WRITE_LINE_MEMBER(hpc1_device::duart2_int_w) { duart_int_w(2, state); } void hpc1_device::duart_int_w(int channel, int state) { m_duart_int_status &= ~(1 << channel); m_duart_int_status |= state << channel; 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); } } WRITE_LINE_MEMBER(hpc1_device::scsi_irq) { 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); } }