// license:BSD-3-Clause // copyright-holders:Joakim Larsson Edstrom /*************************************************************************** * Interrupt scheme and dmac hookup shamelessly based on esq5505.cpp * * 11/04/2016 * Force SYS68K ISCSI-1 driver - This driver will be converted into a slot device once the VME bus driver exists. * The ISCSI-1 board is a VME slave board that reads command and returns results through dual ported RAM to the VME bus. * * http://bitsavers.trailing-edge.com/pdf/forceComputers/800114_Force_Introduction_to_the_SYS68K_ISCSI-1_Oct86.pdf * * || * || || * ||||--|| * ||||--|| * || ||__________________________________________________________ ___ * || |_| | * || | | | * || | | | * || | | | * || | | | * || | | | * || | |VME| * || | | | * || | |P1 | * || | | | * || | | | * || | | | * || | | | * || | | | * || | | | * || |_| | * || |___| * || | * || | * || | * || | * || | * || | * || | * || | * || |___ * || _| | * || | | | * || | | | * || | | | * || | | | * || | |VME| * || | | | * || | |P2 | * || | | | * || | | | * || | | | * || | | | * || | | | * || | | | * || | | | * || | | | * || |_| | * || |___| * || ||------------------------------------------------------------+-+ * ||||--|| * ||||--|| * || * * History of Force Computers *------------------------------------------------------------------------ * See fccpu30.cpp * * Description from datasheet etc * ------------------------------ * - 68010 CPU for local control (10MHz) * - 68450 DMA Controller for local transfers (10MHz) * - Dual Ported l28Kbyte 0 wait state static RAM between the VMEbus and the local CPU * - SCSlbus interface built with the NCR 5386S SCSlbus controller. * o Programmable as an initiator or target * o Transfer rate up to 1.5Mbyte/s * - SHUGART compatible floppy interface with the WD1772 FDC. Up to 4 floppy drives can be * controlled independent of the SCSlbus * - All I/O signals available on P2 connector 4 different interrupt request signals to the VMEbus. Each * channel contains a software programmable IRQ level (1 to 7) and vector * - Local parallel interface for controlling and monitoring board functions * - VMEbus Rev.C/IEEE P10l4 compatible interface A24:D16, D8, SYSFAIL (jumper) * - Watchdog timer controlling correct functions of on-board hard and software * - Status and control LEDs for monitoring local activities * - High level handling firmware for communication, self test, data caching/hashing and control * * Address Map * ---------------------------------------------------------- * Address Range Description * ---------------------------------------------------------- * 000000 - 000007 Initialisation vectors from system EPROM * 000008 - 001FFF Local SRAM * 002000 - 01FFFF Dynamic Dual Port RAM VME bus accessible * C40000 - C4001F SCSIbus controller * C80000 - C800FF DMAC * CC0000 - CC0007 FDC * CC0009 - CC0009 Control Register * D00000 - D0003F PI/T * E00000 - E70000 EPROMs * ---------------------------------------------------------- * * VME side A24 address map - Dual ported RAM * ---------------------------------------------------------- * Default Range Description * ---------------------------------------------------------- * A00000 - A00000 Status word Bits 8:RESET 9:HALT 10:WD * A00001 - A0000F BIM - See below * A01001 - A01001 Read generates local interrupt * A01801 - A01801 Read generates local reset * A02000 - A1FFFF Dynamic Dual Port RAM * ---------------------------------------------------------- * * BIM Ctrl Vect Req Toggle PI/T Status PI/T * ch adr adr pin write pin rea * ---------------------------------------------------------- * 0 A00001 A00009 PA0 PA4 * 1 A00003 A0000B PA1 PA5 * 2 A00005 A0000D PA2 PA6 * 3 A00007 A0000F PA3 PA7 * ---------------------------------------------------------- * * Interrupt sources * ---------------------------------------------------------- * Description Device Lvl IRQ VME board * /Board Vector Address * ---------------------------------------------------------- * On board Sources * ABORT P3 p13 1 AV1 * DMA controller 68450 2 DMAC/AV2 * SCSI bus controller NCR 5386S 3 AV3 * Floppy Disk controller WD 1772 4 AV4 * Parallel interface and timer 68230 5 PIT timer * --- 6 --- * Parallel interface and timer 68230 7 PIT port * ---------------------------------------------------------- * * TODO: * - Write and attach a NCR5386S SCSI device * - Find a floppy image and present it to the WD1772 floppy controller * - Add VME bus driver * - Let a controller CPU board (eg CPU-1 or CPU-30) boot from floppy or SCSI disk * ****************************************************************************/ #include "emu.h" #include "sys68k_iscsi.h" #include "cpu/m68000/m68010.h" #include "machine/68230pit.h" #include "machine/wd_fdc.h" #include "machine/hd63450.h" // compatible with MC68450 #include "machine/clock.h" #define VERBOSE (0) // (LOG_GENERAL) //#define LOG_OUTPUT_FUNC osd_printf_info #include "logmacro.h" #ifdef _MSC_VER #define FUNCNAME __func__ #else #define FUNCNAME __PRETTY_FUNCTION__ #endif #define TODO "Driver for SCSI NCR5386s device needed\n" //************************************************************************** // GLOBAL VARIABLES //************************************************************************** DEFINE_DEVICE_TYPE(VME_SYS68K_ISCSI1, vme_sys68k_iscsi1_card_device, "sys68k_iscsi1", "Force Computers SYS68K/ISCSI-1") #define CPU_CRYSTAL 20_MHz_XTAL /* Jauch */ #define PIT_CRYSTAL 16_MHz_XTAL /* Jauch */ void vme_sys68k_iscsi1_card_device::fcscsi1_mem(address_map &map) { map.unmap_value_high(); map(0x000000, 0x01ffff).ram(); /* SRAM */ map(0xe00000, 0xe1ffff).rom().region("eprom", 0); /* System EPROM Area 32Kb DEBUGGER supplied */ map(0xd00000, 0xd0003f).rw("pit", FUNC(pit68230_device::read), FUNC(pit68230_device::write)).umask16(0x00ff); // map(0xc40000, 0xc4001f).rw("scsi", FUNC(ncr5386_device::read), FUNC(ncr5386_device::write)).umask16(0x00ff); /* SCSI Controller interface - device support not yet available*/ map(0xc40000, 0xc4001f).rw(FUNC(vme_sys68k_iscsi1_card_device::scsi_r), FUNC(vme_sys68k_iscsi1_card_device::scsi_w)).umask16(0x00ff); map(0xc80000, 0xc800ff).rw("mc68450", FUNC(hd63450_device::read), FUNC(hd63450_device::write)); /* DMA Controller interface */ map(0xcc0000, 0xcc0007).rw("fdc", FUNC(wd1772_device::read), FUNC(wd1772_device::write)).umask16(0x00ff); /* Floppy Controller interface */ map(0xcc0009, 0xcc0009).rw(FUNC(vme_sys68k_iscsi1_card_device::tcr_r), FUNC(vme_sys68k_iscsi1_card_device::tcr_w)); /* The Control Register, SCSI ID and FD drive select bits */ } /* ---------------------------------------------------- IRQ IRQ Level Source B4l inserted B4l removed (Def) ----------------------------------------------------- 1 P3 Pin #13 AV1 Autovector AV1 Autovector 2 DMAC DMAC AV2 Autovector 3 SCSIBC AV3 Autovector AV3 Autovector 4 FDC AV4 Autovector AV4 Autovector 5 PI/T Timer PI/T Timer Vect PI/T Timer Vect 6 -- -- -- 7 PI/T Port PI/T Port Vect PI/T Port Vect ------------------------------------------------------ Default configuration: B41 jumper removed The PI/T port interrupt can be used under software control to cause non-maskable (Level 7) interrupts if the watchdog timer elapses and/or if the VMEbus interrupt trigger call occurs. */ /* TODO: Add configurable B41 jumper */ #define B41 0 void vme_sys68k_iscsi1_card_device::update_irq_to_maincpu() { if (fdc_irq_state) { m_maincpu->set_input_line(M68K_IRQ_3, ASSERT_LINE); m_maincpu->set_input_line(M68K_IRQ_2, CLEAR_LINE); m_maincpu->set_input_line(M68K_IRQ_1, CLEAR_LINE); } else if (dmac_irq_state) { m_maincpu->set_input_line(M68K_IRQ_3, CLEAR_LINE); m_maincpu->set_input_line(M68K_IRQ_1, CLEAR_LINE); m_maincpu->set_input_line(M68K_IRQ_2, ASSERT_LINE); } else { m_maincpu->set_input_line(M68K_IRQ_3, CLEAR_LINE); m_maincpu->set_input_line(M68K_IRQ_2, CLEAR_LINE); m_maincpu->set_input_line(M68K_IRQ_1, CLEAR_LINE); } } void vme_sys68k_iscsi1_card_device::cpu_space_map(address_map &map) { map(0xfffff0, 0xffffff).m(m_maincpu, FUNC(m68000_base_device::autovectors_map)); map(0xfffff5, 0xfffff5).r(FUNC(vme_sys68k_iscsi1_card_device::dma_iack)); } static void fcscsi_floppies(device_slot_interface &device) { device.option_add("525qd", FLOPPY_525_QD); } /* ROM definitions */ ROM_START (sys68k_iscsi1) ROM_REGION16_BE (0x20000, "eprom", 0) /* Besta ROM:s - apparantly patched Force ROM:s */ ROM_SYSTEM_BIOS(0, "besta88", "Besta 88") ROMX_LOAD ("besta88_scsi_lower.rom", 0x00001, 0x4000, CRC (fb3ab364) SHA1 (d79112100f1c4beaf358e006efd4dde5e300b0ba), ROM_SKIP(1) | ROM_BIOS(0)) ROMX_LOAD ("besta88_scsi_upper.rom", 0x00000, 0x4000, CRC (41f9cdf4) SHA1 (66b998bbf9459f0a613718260e05e97749532073), ROM_SKIP(1) | ROM_BIOS(0)) /* Force ROM:s */ ROM_SYSTEM_BIOS(1, "iscsi-1_v3.7", "Force Computer SYS68K/ISCSI-1 firmware v3.7") ROMX_LOAD ("iscsi-1_v3.7_l.bin", 0x00001, 0x4000, CRC (83d95ab7) SHA1 (bf249910bcb6cb0b04dda2a95a38a0f90b553352), ROM_SKIP(1) | ROM_BIOS(1)) ROMX_LOAD ("iscsi-1_v3.7_u.bin", 0x00000, 0x4000, CRC (58815831) SHA1 (074085ef96e1fe2a551938bdeee6a9cab40ff09c), ROM_SKIP(1) | ROM_BIOS(1)) ROM_END void vme_sys68k_iscsi1_card_device::device_add_mconfig(machine_config &config) { /* basic machine hardware */ M68010(config, m_maincpu, CPU_CRYSTAL / 2); /* 7474 based frequency divide by 2 */ m_maincpu->set_addrmap(AS_PROGRAM, &vme_sys68k_iscsi1_card_device::fcscsi1_mem); m_maincpu->set_addrmap(m68000_base_device::AS_CPU_SPACE, &vme_sys68k_iscsi1_card_device::cpu_space_map); /* FDC */ WD1772(config, m_fdc, PIT_CRYSTAL / 2); m_fdc->intrq_wr_callback().set(FUNC(vme_sys68k_iscsi1_card_device::fdc_irq)); m_fdc->drq_wr_callback().set("mc68450", FUNC(hd63450_device::drq1_w)); FLOPPY_CONNECTOR(config, "fdc:0", fcscsi_floppies, "525qd", floppy_image_device::default_pc_floppy_formats); FLOPPY_CONNECTOR(config, "fdc:1", fcscsi_floppies, "525qd", floppy_image_device::default_pc_floppy_formats); FLOPPY_CONNECTOR(config, "fdc:2", fcscsi_floppies, "525qd", floppy_image_device::default_pc_floppy_formats); FLOPPY_CONNECTOR(config, "fdc:3", fcscsi_floppies, "525qd", floppy_image_device::default_pc_floppy_formats); /* PIT Parallel Interface and Timer device */ PIT68230(config, m_pit, PIT_CRYSTAL / 2); /* 7474 based frequency divide by 2 */ m_pit->pb_out_callback().set(FUNC(vme_sys68k_iscsi1_card_device::led_w)); /* DMAC it is really a M68450 but the HD63850 is upwards compatible */ HD63450(config, m_dmac, CPU_CRYSTAL / 2, "maincpu"); // MC68450 compatible m_dmac->set_clocks(attotime::from_usec(32), attotime::from_nsec(450), attotime::from_usec(4), attotime::from_hz(15625/2)); m_dmac->set_burst_clocks(attotime::from_usec(32), attotime::from_nsec(450), attotime::from_nsec(50), attotime::from_nsec(50)); m_dmac->irq_callback().set(FUNC(vme_sys68k_iscsi1_card_device::dma_irq)); //m_dmac->dma_read<0>().set(FUNC(vme_sys68k_iscsi1_card_device::scsi_read_byte)); // ch 0 = SCSI //m_dmac->dma_write<0>().set(FUNC(vme_sys68k_iscsi1_card_device::scsi_write_byte)); m_dmac->dma_read<1>().set(FUNC(vme_sys68k_iscsi1_card_device::fdc_read_byte)); // ch 1 = fdc m_dmac->dma_write<1>().set(FUNC(vme_sys68k_iscsi1_card_device::fdc_write_byte)); } const tiny_rom_entry *vme_sys68k_iscsi1_card_device::device_rom_region() const { LOG("%s\n", FUNCNAME); return ROM_NAME(sys68k_iscsi1); } //************************************************************************** // LIVE DEVICE //************************************************************************** vme_sys68k_iscsi1_card_device::vme_sys68k_iscsi1_card_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, type, tag, owner, clock) , device_vme_card_interface(mconfig, *this) , m_maincpu(*this, "maincpu") , m_fdc(*this, "fdc") , m_pit(*this, "pit") , m_dmac(*this, "mc68450") , m_eprom(*this, "eprom") , m_ram(*this, "ram") , m_tcr(0) { LOG("%s\n", FUNCNAME); } vme_sys68k_iscsi1_card_device::vme_sys68k_iscsi1_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : vme_sys68k_iscsi1_card_device(mconfig, VME_SYS68K_ISCSI1, tag, owner, clock) { } /* Start it up */ void vme_sys68k_iscsi1_card_device::device_start() { LOG("%s\n", FUNCNAME); #if 0 // TODO: Setup VME access handlers for shared memory area uint32_t base = 0x00A00000; m_vme->install_device(base + 0, base + 1, // Channel B - Data read8_delegate(FUNC(z80sio_device::db_r), subdevice("pit")), write8_delegate(FUNC(z80sio_device::db_w), subdevice("pit")), 0x00ff); m_vme->install_device(base + 2, base + 3, // Channel B - Control read8_delegate(FUNC(z80sio_device::cb_r), subdevice("pit")), write8_delegate(FUNC(z80sio_device::cb_w), subdevice("pit")), 0x00ff); #endif } void vme_sys68k_iscsi1_card_device::device_reset() { LOG("%s\n", FUNCNAME); m_maincpu->space(AS_PROGRAM).install_rom(0, m_eprom->bytes() - 1, m_eprom->base()); m_boot_mph = m_maincpu->space(AS_PROGRAM).install_read_tap(0x000006, 0x000007, "boot", [this](offs_t offset, uint16_t &data, uint16_t mem_mask) { if (!machine().side_effects_disabled() && ACCESSING_BITS_0_7) { m_maincpu->space(AS_PROGRAM).install_ram(0, m_ram.bytes() - 1, m_ram.target()); m_boot_mph.remove(); } }); } /* The Control Register - discretely implemented on the PCB Bit #: 7 6 5 4 3 2 1 0 \ \ \ \ \ \ \ \ Floppy Disk Side Select \ \ \ \ \ \ \ Floppy Disk Drive Select 0 \ \ \ \ \ \ Floppy Disk Drive Select 1 \ \ \ \ \ Floppy Disk Drive Select 2 \ \ \ \ Floppy Disk Drive Select 3 \ \ \ ISCSI-l I.D. Bit #0 \ \ ISCSI-l I.D. Bit #1 \ ISCSI-l 1.D. Bit #2 */ uint8_t vme_sys68k_iscsi1_card_device::tcr_r(){ LOG("%s\n", FUNCNAME); return (uint8_t) m_tcr; } void vme_sys68k_iscsi1_card_device::tcr_w(uint8_t data){ floppy_image_device *floppy0 = m_fdc->subdevice("0")->get_device(); floppy_image_device *floppy1 = m_fdc->subdevice("1")->get_device(); floppy_image_device *floppy2 = m_fdc->subdevice("2")->get_device(); floppy_image_device *floppy3 = m_fdc->subdevice("3")->get_device(); floppy_image_device *floppy = nullptr; if (!BIT(data, 1)) floppy = floppy0; else if (!BIT(data, 2)) floppy = floppy1; else if (!BIT(data, 3)) floppy = floppy2; else if (!BIT(data, 4)) floppy = floppy3; if (floppy) { m_fdc->set_floppy(floppy); floppy->ss_w(!BIT(data, 0)); floppy->mon_w(0); } else { floppy0->mon_w(1); floppy1->mon_w(1); floppy2->mon_w(1); floppy3->mon_w(1); } LOG("%s [%02x]\n", FUNCNAME, data); m_tcr = data; return; } void vme_sys68k_iscsi1_card_device::led_w(uint8_t data) { LOG("%s [%02x]\n", FUNCNAME, data); m_fdc->dden_w(BIT(data, 7)); return; } void vme_sys68k_iscsi1_card_device::dma_irq(int state) { if(state != CLEAR_LINE) { logerror("DMAC IRQ, vector = %x\n", m_dmac->iack()); dmac_irq_state = 1; } else { dmac_irq_state = 0; } update_irq_to_maincpu(); } uint8_t vme_sys68k_iscsi1_card_device::dma_iack() { if (B41) return m_dmac->iack(); else return m68000_base_device::autovector(2); } void vme_sys68k_iscsi1_card_device::fdc_irq(int state) { if (state != 0) { fdc_irq_state = 1; } else { fdc_irq_state = 0; } update_irq_to_maincpu(); } uint8_t vme_sys68k_iscsi1_card_device::fdc_read_byte() { return m_fdc->data_r(); } void vme_sys68k_iscsi1_card_device::fdc_write_byte(uint8_t data) { m_fdc->data_w(data & 0xff); } uint8_t vme_sys68k_iscsi1_card_device::scsi_r(offs_t offset) { uint8_t data = 0; // fake diag status if (offset == 9) data = 0x80; LOG("scsi R %02x == %02x\n", offset, data); return data; } void vme_sys68k_iscsi1_card_device::scsi_w(offs_t offset, uint8_t data) { LOG("scsi W %02x <- %02x\n", offset, data); } uint8_t vme_sys68k_iscsi1_card_device::not_implemented_r(){ static int been_here = 0; if (!been_here++){ logerror(TODO); printf(TODO); } return (uint8_t) 0; } void vme_sys68k_iscsi1_card_device::not_implemented_w(uint8_t data){ static int been_here = 0; if (!been_here++){ logerror(TODO); printf(TODO); } return; } // This info isn't kept in a card driver atm so storing it as a comment for later use // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS //COMP( 1986, fcscsi1, 0, 0, fcscsi1, fcscsi1, driver_device, 0, "Force Computers Gmbh", "SYS68K/SCSI-1", MACHINE_NO_SOUND | MACHINE_NOT_WORKING )