From b4109bea0706b8ded888cb5500ae3cb9bc44312c Mon Sep 17 00:00:00 2001 From: Michael Zapf Date: Sun, 21 Nov 2021 16:37:52 +0100 Subject: ti99/geneve: Added WHTech SCSI adapter card --- scripts/src/bus.lua | 2 + src/devices/bus/ti99/peb/peribox.cpp | 5 + src/devices/bus/ti99/peb/scsicard.cpp | 693 ++++++++++++++++++++++++++++++++++ src/devices/bus/ti99/peb/scsicard.h | 135 +++++++ 4 files changed, 835 insertions(+) create mode 100644 src/devices/bus/ti99/peb/scsicard.cpp create mode 100644 src/devices/bus/ti99/peb/scsicard.h diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index faec58fef07..5be5a3361fb 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -3506,6 +3506,8 @@ if (BUSES["TI99"]~=null) then MAME_DIR .. "src/devices/bus/ti99/peb/pgram.h", MAME_DIR .. "src/devices/bus/ti99/peb/samsmem.cpp", MAME_DIR .. "src/devices/bus/ti99/peb/samsmem.h", + MAME_DIR .. "src/devices/bus/ti99/peb/scsicard.cpp", + MAME_DIR .. "src/devices/bus/ti99/peb/scsicard.h", MAME_DIR .. "src/devices/bus/ti99/peb/sidmaster.cpp", MAME_DIR .. "src/devices/bus/ti99/peb/sidmaster.h", MAME_DIR .. "src/devices/bus/ti99/peb/spchsyn.cpp", diff --git a/src/devices/bus/ti99/peb/peribox.cpp b/src/devices/bus/ti99/peb/peribox.cpp index b4e047c9815..ab8981c444d 100644 --- a/src/devices/bus/ti99/peb/peribox.cpp +++ b/src/devices/bus/ti99/peb/peribox.cpp @@ -198,6 +198,7 @@ CRUCLK* 51||52 DBIN #include "forti.h" #include "pgram.h" #include "sidmaster.h" +#include "scsicard.h" #define LOG_WARN (1U<<1) // Warnings #define LOG_CONFIG (1U<<2) // Configuration @@ -501,6 +502,7 @@ void ti99_peribox_slot_standard(device_slot_interface &device) device.option_add("ddcc1", TI99_DDCC1); device.option_add("forti", TI99_FORTI); device.option_add("sidmaster", TI99_SIDMASTER); + device.option_add("whtscsi", TI99_WHTSCSI); } void peribox_device::device_add_mconfig(machine_config &config) @@ -546,6 +548,7 @@ void ti99_peribox_slot_evpc(device_slot_interface &device) device.option_add("ddcc1", TI99_DDCC1); device.option_add("forti", TI99_FORTI); device.option_add("sidmaster", TI99_SIDMASTER); + device.option_add("whtscsi", TI99_WHTSCSI); } void peribox_ev_device::device_add_mconfig(machine_config &config) @@ -602,6 +605,7 @@ void ti99_peribox_slot_geneve(device_slot_interface &device) device.option_add("ddcc1", TI99_DDCC1); device.option_add("forti", TI99_FORTI); device.option_add("sidmaster", TI99_SIDMASTER); + device.option_add("whtscsi", TI99_WHTSCSI); } void peribox_gen_device::device_add_mconfig(machine_config &config) @@ -658,6 +662,7 @@ void ti99_peribox_slot_sgcpu(device_slot_interface &device) device.option_add("ddcc1", TI99_DDCC1); device.option_add("forti", TI99_FORTI); device.option_add("sidmaster", TI99_SIDMASTER); + device.option_add("whtscsi", TI99_WHTSCSI); } void peribox_sg_device::device_add_mconfig(machine_config &config) diff --git a/src/devices/bus/ti99/peb/scsicard.cpp b/src/devices/bus/ti99/peb/scsicard.cpp new file mode 100644 index 00000000000..e84d5911f8e --- /dev/null +++ b/src/devices/bus/ti99/peb/scsicard.cpp @@ -0,0 +1,693 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + SCSI adapter card + designed and realized by Western Horizon Technologies + + Latest two revisions: + Rev F: using logic circuits and a PAL for decoding + Rev G: using a PLD custom chip + + This is an emulation of the WHTech SCSI adapter. It has been modified over + the years in various ways, in particular to get it working with the Geneve + 9640, and to enable word transfers. This modification was only effective + on the Geneve because the TMS9995 uses an even/odd word transfer, while the + TI-99/4A console uses an odd/even word transfer (see datamux.cpp), hence + swapping the bytes from the controller. An additional SWPB operation would + have been required which would have slowed down the transfer, so there would + not have be a measurable performance gain. Accordingly, the DSR (firmware) + of the card does not activate word transfer. + + Further modifications were done to enable block DMA transfer. This could + only be used with a new DSR (1.6) and a daughterboard to replace the + PLD circuit. + + Note that the DSR is not used when the card is used with the Geneve, since + the Geneve operating system brings its own SCSI driver. Block mode can + be explicitly activated with PDMA ON, but for this version of the emulation, + this will lead to a lockup, so PDMA OFF must be ensured. + + A clone card was designed by the System 99 user group (SNUG), called ASCSI, + which contained all modifications. + + + Components + ---------- + ispLSI2064 PLD (Custom decoder chip) (Rev G) + 62256 RAM 32Kx8 + 27512 EPROM 64Kx8 + NEC 53C80 SCSI Controller + Dip switches + + + Memory map + ---------- + + CB5=0 (CRU bit 5) + 4000-4FDF: EPROM (1 of 8 banks @ 8K) + 4FE0-4FFF: Controller + 5000-5FFF: SRAM (if CB1=1) or EPROM (if CB1=0) + + CB5=1: + 4000-4FFF: SRAM (if CB1=1) or EPROM (if CB1=0) + 5000-5FDF: EPROM (1 of 8 banks) + 5FE0-5FFF: Controller + + + DIP switches [1] + SW1: CRU base 0600 - 1f00 + SW2: 0: Driver LOAD/Parity enable + 1: SCSI ID Bit 0 (6 or 7) + 2: Normally on + 3: Normally on + 4: Geneve mode + + CRU mapping + ----------- + Read Write + 0: SCSI IRQ 0: Card select + 1: SCSI DRQ 1: SRAM enable (hides EPROM) + 2: SCSI READY 2: SCSI DMA mode enable + 3-7: DIP SW2 3: SCSI EOP (End of process) + 4: Word transfer mode select + 5: Bank swap + 6: - + 7: - + 8-10: EPROM bank (10=MSB) + 11: - + 12-14: SRAM bank (14=MSB) + 15: - + + + I/O ports (4Fxx for CB5=0, 5Fxx for CB5=1) + --------- + Read Write + 4FE0 Current SCSI data 4FF0 Output data (PIO and DMA) + 4FE2 Initiator command 4FF2 Initiator command + 4FE4 Mode 4FF4 Mode + 4FE6 Target command 4FF6 Target command + 4FE8 Current SCSI bus status 4FF8 Select enable + 4FEA Bus and status 4FFA Start DMA send + 4FEC Input data (DMA) 4FFC Start DMA target receive + 4FEE Reset parity/interrupt 4FFE Start DMA initiator receive + + + Drive mappings: + SCS1 = SCSI ID 0 + SCS2 = SCSI ID 1 + ... + SCS8 = SCSI ID 7 + + + Michael Zapf + + References + + [1] Western Horizon Technologies: SCSI Host Adapter Card / Hardware + Installation Manual + + Acknowledgements + + Thanks to Don O'Neil of WHT for providing the required schematics, ROM dumps, + and documentation + +*****************************************************************************/ + +#include "emu.h" +#include "scsicard.h" +#include "bus/nscsi/devices.h" + +#define LOG_WARN (1U<<1) +#define LOG_CRU (1U<<2) +#define LOG_EPROM (1U<<3) +#define LOG_RAM (1U<<4) +#define LOG_CONTR (1U<<5) +#define LOG_CB (1U<<6) +#define LOG_READY (1U<<7) +#define LOG_DMA (1U<<8) + +#define VERBOSE ( LOG_GENERAL | LOG_WARN ) + +#include "logmacro.h" + +#define BUFFER "ram" +#define PLD_TAG "pld" +#define CONTR_TAG "scsibus:7:controller" +#define SCSIBUS_TAG "scsibus" + +DEFINE_DEVICE_TYPE(TI99_WHTSCSI, bus::ti99::peb::whtech_scsi_card_device, "ti99_whtscsi", "Western Horizon Technologies SCSI host adapter") +DEFINE_DEVICE_TYPE(WHTSCSI_PLD, bus::ti99::peb::whtscsi_pld_device, PLD_TAG, "WHTech SCSI PLD") + +namespace bus::ti99::peb { + +whtech_scsi_card_device::whtech_scsi_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, TI99_WHTSCSI, tag, owner, clock), + device_ti99_peribox_card_interface(mconfig, *this), + m_buffer_ram(*this, BUFFER), + m_pld(*this, PLD_TAG), + m_controller(*this, CONTR_TAG), + m_scsibus(*this, SCSIBUS_TAG), + m_irq(false), + m_drq(false), + m_readyset(false) +{ +} + +void whtech_scsi_card_device::setaddress_dbin(offs_t offset, int state) +{ + // Do not allow setaddress for debugger + if (machine().side_effects_disabled()) return; + m_address = offset; + if (in_dsr_space(offset, true) && m_pld->card_selected()) + { + LOGMASKED(LOG_READY, "setadd %04x (%s)\n", offset & 0xffff, machine().describe_context()); + operate_ready_line(); + } +} + +void whtech_scsi_card_device::operate_ready_line() +{ + m_pld->update_line_states(m_address, m_drq, m_irq); + + // Clear or assert the outgoing READY line + bool newready = m_pld->ready(); + if (newready != m_readyset) + { + LOGMASKED(LOG_READY, "READY line changed to %d\n", newready); + m_slot->set_ready(newready); + m_readyset = newready; + } +} + +/* + Debugger access. +*/ +void whtech_scsi_card_device::debug_read(offs_t offset, uint8_t* value) +{ + offs_t addrcopy = m_address; + m_address = offset; + + if (m_pld->sram_cs()) + { + *value = m_buffer_ram->pointer()[(m_address & 0x0fff) | (m_pld->sram_bank()<<12)]; + } + + if (m_pld->eprom_cs()) + { + // EPROM selected + int base = (m_pld->eprom_bank()<<13); + *value = m_eprom[base | (m_address & 0x1fff)]; + } + m_address = addrcopy; +} + +/* + Debugger access. +*/ +void whtech_scsi_card_device::debug_write(offs_t offset, uint8_t data) +{ + offs_t addrcopy = m_address; + m_address = offset; + + if (m_pld->sram_cs()) + { + m_buffer_ram->pointer()[(m_address & 0x0fff) | (m_pld->sram_bank()<<12)] = data; + } + m_address = addrcopy; +} + +void whtech_scsi_card_device::readz(offs_t offset, uint8_t *value) +{ + if (machine().side_effects_disabled()) + { + debug_read(offset, value); + return; + } + + if (!m_pld->card_selected()) return; + + if (in_dsr_space(offset, true)) LOGMASKED(LOG_READY, "rd %04x\n", offset & 0xffff); + + if (m_pld->eprom_cs()) + { + // Lines A0-A12 directly connected to the EPROM (chip pin order) + // Lines A13-A15 connected to PLD + int base = (m_pld->eprom_bank()<<13); + uint8_t* rom = &m_eprom[base | (m_address & 0x1fff)]; + *value = *rom; + + if (WORD_ALIGNED(m_address)) + { + // Do logging by 16 bit words, as we typically have instructions in + // the eprom + uint16_t val = (*rom << 8) | (*(rom+1)); + LOGMASKED(LOG_EPROM, "DSR: %04x (bank %d) -> %04x\n", m_address & 0xffff, m_pld->eprom_bank(), val); + } + } + + if (m_pld->sram_cs()) + { + // Lines A0-A11 directly connected to the SRAM (chip pin order) + // Lines A12-A14 connected to PLD + *value = m_buffer_ram->pointer()[(m_address & 0x0fff) | (m_pld->sram_bank()<<12)]; + LOGMASKED(LOG_RAM, "RAM: %04x (bank %d) -> %02x\n", m_address & 0xffff, m_pld->sram_bank(), *value); + } + + if (m_pld->scsi_cs()) + { + // Only for addresses 4fe0-4fef + if ((m_address & 0x0010)==0x0000) + { + int reg = (m_address >> 1)&0x07; + // If we are in DMA mode, reading from register 6 means DMA read + if ((m_controller->read(2) & 0x02) && (reg == 6)) + { + LOGMASKED(LOG_DMA, "CTR: DMA in (%s)\n", machine().describe_context()); + *value = m_controller->dma_r(); + LOGMASKED(LOG_DMA, "CTR: DMA -> %02x\n", *value); + } + else + { + *value = m_controller->read(reg); + LOGMASKED(LOG_CONTR, "CTR: Reg %d (%04x) -> %02x (%s)\n", reg, m_address & 0xffff, *value, machine().describe_context()); + } + } + } +} + +void whtech_scsi_card_device::write(offs_t offset, uint8_t data) +{ + if (machine().side_effects_disabled()) + { + debug_write(offset, data); + return; + } + + if (!m_pld->card_selected()) return; + + if (in_dsr_space(offset, true)) LOGMASKED(LOG_READY, "wr %04x\n", offset & 0xffff); + + if (m_pld->sram_cs()) + { + // Lines A0-A11 directly connected to the SRAM (chip pin order) + // Lines A12-A14 connected to PLD + LOGMASKED(LOG_RAM, "RAM: %04x (bank %d) <- %02x\n", m_address & 0xffff, m_pld->sram_bank(), data); + m_buffer_ram->pointer()[(m_address & 0x0fff) | (m_pld->sram_bank()<<12)] = data; + } + + if (m_pld->scsi_cs()) + { + // Only for addresses 4ff0-4fff + if ((m_address & 0x0010)==0x0010) + { + int reg = (m_address >> 1)&0x07; + + // If we are in DMA mode, writing to register 0 means DMA write + if ((m_controller->read(2) & 0x02) && (reg == 0)) + { + LOGMASKED(LOG_DMA, "CTR: DMA out <- %02x (%s)\n", data, machine().describe_context()); + m_controller->dma_w(data); + } + else + { + LOGMASKED(LOG_CONTR, "CTR: Reg %d (%04x) <- %02x (%s)\n", reg, m_address & 0xffff, data, machine().describe_context()); + m_controller->write(reg, data); + } + } + } +} + +/* + CRU read access +*/ +void whtech_scsi_card_device::crureadz(offs_t offset, uint8_t *value) +{ + m_pld->crureadz(offset, value); +} + +/* + CRU write access. The flags are kept in the PLD. +*/ +void whtech_scsi_card_device::cruwrite(offs_t offset, uint8_t data) +{ + m_pld->cruwrite(offset, data); + operate_ready_line(); +} + +/* + Callbacks for the controller chip. +*/ +WRITE_LINE_MEMBER( whtech_scsi_card_device::drq_w ) +{ + LOGMASKED(LOG_CB, "DRQ pin from controller = %d\n", state); + bool drq = (state==ASSERT_LINE); + if (drq != m_drq) + { + m_drq = drq; + m_slot->set_inta((m_drq || m_irq)? ASSERT_LINE : CLEAR_LINE); + } + operate_ready_line(); +} + +WRITE_LINE_MEMBER( whtech_scsi_card_device::irq_w ) +{ + LOGMASKED(LOG_CB, "IRQ pin from controller = %d\n", state); + bool irq = (state==ASSERT_LINE); + if (irq != m_irq) + { + m_irq = irq; + m_slot->set_inta((m_drq || m_irq)? ASSERT_LINE : CLEAR_LINE); + } + operate_ready_line(); +} + +void whtech_scsi_card_device::device_add_mconfig(machine_config &config) +{ + // RAM circuit + RAM(config, BUFFER).set_default_size("32K").set_default_value(0); + + // PLD circuit + WHTSCSI_PLD(config, PLD_TAG, 0); + + // SCSI bus + NSCSI_BUS(config, m_scsibus); + NSCSI_CONNECTOR(config, "scsibus:0", default_scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsibus:1", default_scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsibus:2", default_scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsibus:3", default_scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsibus:4", default_scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsibus:5", default_scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsibus:6", default_scsi_devices, nullptr, false); + NSCSI_CONNECTOR(config, "scsibus:7").option_set("controller", NCR53C80).machine_config([this](device_t *device) { + ncr53c80_device &adapter = downcast(*device); + adapter.drq_handler().set(*this, FUNC(whtech_scsi_card_device::drq_w)); + adapter.irq_handler().set(*this, FUNC(whtech_scsi_card_device::irq_w)); + }); +} + +void whtech_scsi_card_device::device_start() +{ + m_eprom = memregion(TI99_DSRROM)->base(); + save_item(NAME(m_address)); + save_item(NAME(m_irq)); + save_item(NAME(m_drq)); + save_item(NAME(m_readyset)); +} + +void whtech_scsi_card_device::device_reset() +{ + m_cru_base = (ioport("SW1")->read()) << 8; + m_sw2 = ioport("SW2")->read(); + m_drq = false; + m_irq = false; +} + +int whtech_scsi_card_device::get_sw1() +{ + return m_cru_base; +} + +int whtech_scsi_card_device::get_sw2() +{ + return m_sw2; +} + +/* + The CRU address base for the card. According to [1], settings below + 1000 only make sense with an installed AT keyboard and ROM upgrade. +*/ +INPUT_PORTS_START( whtscsi ) + PORT_START("SW1") + PORT_DIPNAME(0x1f, 0x12, "SCSI card CRU base") + PORT_DIPSETTING(0x06, "0600") + PORT_DIPSETTING(0x07, "0700") + PORT_DIPSETTING(0x08, "0800") + PORT_DIPSETTING(0x09, "0900") + PORT_DIPSETTING(0x0a, "0a00") + PORT_DIPSETTING(0x0b, "0b00") + PORT_DIPSETTING(0x0c, "0c00") + PORT_DIPSETTING(0x0d, "0d00") + PORT_DIPSETTING(0x0e, "0e00") + PORT_DIPSETTING(0x0f, "0f00") + PORT_DIPSETTING(0x10, "1000") + PORT_DIPSETTING(0x11, "1100") + PORT_DIPSETTING(0x12, "1200") // Default setting + PORT_DIPSETTING(0x13, "1300") + PORT_DIPSETTING(0x14, "1400") + PORT_DIPSETTING(0x15, "1500") + PORT_DIPSETTING(0x16, "1600") + PORT_DIPSETTING(0x17, "1700") + PORT_DIPSETTING(0x18, "1800") + PORT_DIPSETTING(0x19, "1900") + PORT_DIPSETTING(0x1a, "1a00") + PORT_DIPSETTING(0x1b, "1b00") + PORT_DIPSETTING(0x1c, "1c00") + PORT_DIPSETTING(0x1d, "1d00") + PORT_DIPSETTING(0x1e, "1e00") + PORT_DIPSETTING(0x1f, "1f00") + + PORT_START("SW2") + PORT_DIPNAME(0x01, 0x00, "Driver LOAD/Parity enable") + PORT_DIPSETTING(0x00, DEF_STR(Off)) + PORT_DIPSETTING(0x01, DEF_STR(On)) + + // Currently, the controller is fixed to ID 7, according to device_add_mconfig, + // and we cannot relocate the card on the bus + PORT_DIPNAME(0x0e, 0x0e, "SCSI card ID") + // PORT_DIPSETTING(0x0c, "6") + PORT_DIPSETTING(0x0e, "7") + PORT_DIPNAME(0x10, 0x00, "Geneve mode") + PORT_DIPSETTING(0x00, DEF_STR(Off)) + PORT_DIPSETTING(0x10, DEF_STR(On)) +INPUT_PORTS_END + +ROM_START( whtscsi ) + ROM_REGION(0x10000, TI99_DSRROM, 0) + ROM_LOAD("scsidsr150.u6", 0x0000, 0x10000, CRC(6e067c22) SHA1(f8d8861863e6a17042428e94967fd4ffc4b9d1de)) /* HFDC disk DSR ROM */ +ROM_END + + +const tiny_rom_entry *whtech_scsi_card_device::device_rom_region() const +{ + return ROM_NAME( whtscsi ); +} + +ioport_constructor whtech_scsi_card_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(whtscsi); +} + +// ======================================================================== +// PLD circuit on the board +// ======================================================================== + +whtscsi_pld_device::whtscsi_pld_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, WHTSCSI_PLD, tag, owner, clock), + m_board(nullptr), + m_selected(false), + m_sram_shadow(false), + m_dma_lock(false), + m_word_transfer(false), + m_bank_swapped(false), + m_readyout(true), + m_eprom_bank(0), + m_sram_bank(0) +{ +} + +void whtscsi_pld_device::device_start() +{ + save_item(NAME(m_selected)); + save_item(NAME(m_sram_shadow)); + save_item(NAME(m_dma_lock)); + save_item(NAME(m_word_transfer)); + save_item(NAME(m_bank_swapped)); + save_item(NAME(m_readyout)); + save_item(NAME(m_eprom_bank)); + save_item(NAME(m_sram_bank)); +} + +void whtscsi_pld_device::device_reset() +{ + m_selected = false; + m_sram_shadow = false; + m_readyout = true; + m_dma_lock = false; + m_word_transfer = false; + m_bank_swapped = false; + m_eprom_bank = 0; + m_sram_bank = 0; +} + +/* + SRAM is accessible at 5000-5fff for bank_swapped=false, else at 4000-4fff. + Needs to be turned on with the flag sram_shadow. +*/ +line_state whtscsi_pld_device::sram_cs() +{ + if (!m_sram_shadow) return CLEAR_LINE; + return (busen() + && (((m_board->m_address & 0x1000)==0) == m_bank_swapped))? ASSERT_LINE : CLEAR_LINE; +} + +/* + EPROM is selected when we are in the correct address space and neither + SRAM nor the controller are selected. +*/ +line_state whtscsi_pld_device::eprom_cs() +{ + return (busen() + && (sram_cs()==CLEAR_LINE) + && (scsi_cs()==CLEAR_LINE))? ASSERT_LINE : CLEAR_LINE; +} + +/* + The controller is selected in the 4fe0-4ffe space, or in 5fe0-5ffe, depending + on the bank_swapped flag (4xxx for bank_swapped=false). + Also, for byte mode, only the even addresses are mapped. In word mode, the + controller shall be active for both even and odd address accesses. This is + only needed for DMA. +*/ +line_state whtscsi_pld_device::scsi_cs() +{ + return (busen() + && ((m_board->m_address & 0x0fe0)==0x0fe0) + && (((m_board->m_address & 0x1000)!=0) == m_bank_swapped) + && (((m_board->m_address & 1)==0) || m_word_transfer))? ASSERT_LINE : CLEAR_LINE; +} + +/* + Are we accessing the memory area 4000-5FFF, and this card has been turned on? +*/ +bool whtscsi_pld_device::busen() +{ + return (((m_board->m_address & 0x7e000)==0x74000) && m_selected); +} + +/* + CRU read access +*/ +void whtscsi_pld_device::crureadz(offs_t offset, uint8_t *value) +{ + int crubase = m_board->get_sw1(); + + if ((offset & 0xff00)==crubase) + { + int bit = (offset >> 1) & 0x1f; + switch (bit) + { + case 0: + *value = m_board->m_irq? 1 : 0; + break; + case 1: + *value = m_board->m_drq? 1 : 0; + break; + case 2: + // READY; not available in the current 53C80 emulation + break; + case 3: + case 4: + case 5: + case 6: + case 7: + *value = ((m_board->get_sw2() & (1<<(bit-3)))!=0)? 1 : 0; + break; + default: + break; + } + // LOGMASKED(LOG_CRU, "CRU %04x -> %d\n", offset & 0xffff, *value); + } +} + +/* + CRU write access +*/ +void whtscsi_pld_device::cruwrite(offs_t offset, uint8_t data) +{ + int crubase = m_board->get_sw1(); + if ((offset & 0xff00)==crubase) + { + LOGMASKED(LOG_CRU, "CRU %04x <- %d (%s)\n", offset & 0xffff, data, machine().describe_context()); + int bit = (offset >> 1) & 0x1f; + switch (bit) + { + case 0: // card activation + LOGMASKED(LOG_CRU, "DSR %s\n", (data!=0)? "on" : "off"); + m_selected = (data != 0); + break; + case 1: // SRAM shadow + LOGMASKED(LOG_CRU, "SRAM shadow %s\n", (data!=0)? "on" : "off"); + m_sram_shadow = (data != 0); + break; + case 2: // DMA lock enable + LOGMASKED(LOG_CRU, "DMA lock %s\n", (data!=0)? "on" : "off"); + m_dma_lock = (data != 0); + break; + case 3: // SCSI EOP + // signal_scsi_eop(data != 0); + LOGMASKED(LOG_CRU, "SCSI EOP %s\n", (data!=0)? "on" : "off"); + break; + case 4: + LOGMASKED(LOG_CRU, "Word transfer %s\n", (data!=0)? "on" : "off"); + m_word_transfer = (data != 0); + break; + case 5: + LOGMASKED(LOG_CRU, "Bank swap %s\n", (data!=0)? "on" : "off"); + m_bank_swapped = (data != 0); + break; + case 6: + LOGMASKED(LOG_CRU, "Block mode %s (not implemented)\n", (data!=0)? "on" : "off"); + break; + case 8: + case 9: + case 10: + if (data != 0) + m_eprom_bank = m_eprom_bank | (1<<(bit-8)); + else + m_eprom_bank = m_eprom_bank & ~(1<<(bit-8)); + break; + case 12: + case 13: + case 14: + if (data != 0) + m_sram_bank = m_sram_bank | (1<<(bit-12)); + else + m_sram_bank = m_sram_bank & ~(1<<(bit-12)); + break; + default: + break; + } + } +} + +bool whtscsi_pld_device::ready() +{ + return m_readyout; +} + +bool whtscsi_pld_device::card_selected() +{ + return m_selected; +} + +/* + Updates the state of the READY output of the PLD. In the real device, the + SCSIDACK line is also updated, but this line is not used with the current + implementation of the 53C80. + + READY is always asserted when an IRQ is pending or when we do not use DMA + Otherwise, READY is asserted when a DRQ is pending + When the DMA lock is active, and there is no DRQ yet, let the CPU wait +*/ +void whtscsi_pld_device::update_line_states(int address, bool drq, bool irq) +{ + m_readyout = (irq || !m_dma_lock)? true : drq; +} + +void whtscsi_pld_device::device_config_complete() +{ + m_board = static_cast(owner()); +} + +} // end namespace bus::ti99::peb diff --git a/src/devices/bus/ti99/peb/scsicard.h b/src/devices/bus/ti99/peb/scsicard.h new file mode 100644 index 00000000000..bc4576211d8 --- /dev/null +++ b/src/devices/bus/ti99/peb/scsicard.h @@ -0,0 +1,135 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + SCSI adapter card + See scsicard.cpp for documentation + + Michael Zapf + November 2021 + +*****************************************************************************/ + +#ifndef MAME_BUS_TI99_PEB_SCSI_H +#define MAME_BUS_TI99_PEB_SCSI_H + +#pragma once + +#include "peribox.h" +#include "machine/ram.h" +#include "machine/ncr5380.h" + +namespace bus::ti99::peb { +class whtscsi_pld_device; + +class whtech_scsi_card_device : public device_t, public device_ti99_peribox_card_interface +{ + friend class whtscsi_pld_device; + +public: + whtech_scsi_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + void readz(offs_t offset, uint8_t *value) override; + void write(offs_t offset, uint8_t data) override; + void setaddress_dbin(offs_t offset, int state) override; + + void crureadz(offs_t offset, uint8_t *value) override; + void cruwrite(offs_t offset, uint8_t data) override; + + DECLARE_WRITE_LINE_MEMBER( drq_w ); + DECLARE_WRITE_LINE_MEMBER( irq_w ); + + void debug_read(offs_t offset, uint8_t* value); + void debug_write(offs_t offset, uint8_t data); + +private: + void device_start() override; + void device_reset() override; + void device_add_mconfig(machine_config &config) override; + ioport_constructor device_input_ports() const override; + const tiny_rom_entry *device_rom_region() const override; + + // SCSI card on-board SRAM (32K) + required_device m_buffer_ram; + + // Decoder PLD + required_device m_pld; + + // SCSI controller chip + required_device m_controller; + + // SCSI bus + required_device m_scsibus; + + // DSR ROM + uint8_t* m_eprom; + + // Recent address + int m_address; + + // Settings + int m_sw2; + + // Latches for the lines + // Should be removed and accessor functions be added to ncr5380 + bool m_irq; + bool m_drq; + + // State of the READY line + bool m_readyset; + + // Accessor functions for the PLD + int get_sw1(); + int get_sw2(); + + // Determine the state of the READY line + void operate_ready_line(); +}; + +class whtscsi_pld_device : public device_t +{ +public: + whtscsi_pld_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + void crureadz(offs_t offset, uint8_t *value); + void cruwrite(offs_t offset, uint8_t data); + + bool card_selected(); + + // Selector output lines of the PLD + line_state sram_cs(); + line_state eprom_cs(); + line_state scsi_cs(); + + int eprom_bank() { return m_eprom_bank; } + int sram_bank() { return m_sram_bank; } + + bool ready(); + + void update_line_states(int address, bool drq, bool irq); + +private: + void device_start() override; + void device_reset() override; + void device_config_complete() override; + + whtech_scsi_card_device* m_board; + + bool busen(); + + // Flags + bool m_selected; + bool m_sram_shadow; + bool m_dma_lock; + bool m_word_transfer; + bool m_bank_swapped; + bool m_readyout; + int m_eprom_bank; + int m_sram_bank; +}; + +} // end namespace bus::ti99::peb + +DECLARE_DEVICE_TYPE_NS(TI99_WHTSCSI, bus::ti99::peb, whtech_scsi_card_device) +DECLARE_DEVICE_TYPE_NS(WHTSCSI_PLD, bus::ti99::peb, whtscsi_pld_device) + +#endif // MAME_BUS_TI99_PEB_SCSI_H -- cgit v1.2.3