bus/qbus: Add dump and skeleton device for TDL-12 SCSI Host Adapter [Bitsavers]

* z8536: Respect data direction registers when reading back from Ports A & B
This commit is contained in:
AJR 2025-02-21 09:59:27 -05:00
parent 762b250b7e
commit 0759cce9e7
5 changed files with 207 additions and 9 deletions

View File

@ -4790,6 +4790,8 @@ if (BUSES["QBUS"]~=null) then
MAME_DIR .. "src/devices/bus/qbus/qg640.h",
MAME_DIR .. "src/devices/bus/qbus/qtx.cpp",
MAME_DIR .. "src/devices/bus/qbus/qtx.h",
MAME_DIR .. "src/devices/bus/qbus/tdl12.cpp",
MAME_DIR .. "src/devices/bus/qbus/tdl12.h",
MAME_DIR .. "src/devices/bus/qbus/uknc_kmd.cpp",
MAME_DIR .. "src/devices/bus/qbus/uknc_kmd.h",
}

View File

@ -18,6 +18,7 @@
#include "pc11.h"
#include "qg640.h"
#include "qtx.h"
#include "tdl12.h"
#include "uknc_kmd.h"
@ -31,6 +32,7 @@ void qbus_cards(device_slot_interface &device)
device.option_add("mz", UKNC_KMD);
device.option_add("qg640", MATROX_QG640);
device.option_add("by", BK_KMD);
device.option_add("tdl12", TDL12);
}

View File

@ -0,0 +1,137 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/***********************************************************************************************************************************
TDL-12 SCSI Host Adapter (© 1985 T.D. Systems)
************************************************************************************************************************************/
#include "emu.h"
#include "tdl12.h"
#include "bus/nscsi/devices.h"
#include "cpu/z80/z80.h"
#include "machine/eepromser.h"
#include "machine/ncr5380.h"
#include "machine/z8536.h"
// device type definition
DEFINE_DEVICE_TYPE(TDL12, tdl12_device, "tdl12", "TDL-12 SCSI Host Adapter")
tdl12_device::tdl12_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, TDL12, tag, owner, clock)
, device_qbus_card_interface(mconfig, *this)
, m_tdcpu(*this, "tdcpu")
{
}
void tdl12_device::device_start()
{
}
u8 tdl12_device::latch_r(offs_t offset)
{
if (!machine().side_effects_disabled())
logerror("%s: Reading from latch %c\n", machine().describe_context(), offset ? 'H' : 'L');
return 0;
}
void tdl12_device::latch_w(offs_t offset, u8 data)
{
logerror("%s: Writing %02X to latch %c\n", machine().describe_context(), data, offset ? 'H' : 'L');
}
u8 tdl12_device::in40_r()
{
// Used as low 8 bits of jump offset
// Valid values include 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xd0, 0xff
return 0xff;
}
void tdl12_device::out40_w(u8 data)
{
logerror("%s: Output %02X to port 40\n", machine().describe_context(), data);
}
void tdl12_device::out70_w(u8 data)
{
// Data written is irrelevant
logerror("%s: Output to port 70\n", machine().describe_context());
}
void tdl12_device::out74_w(u8 data)
{
// Data written is irrelevant
logerror("%s: Output to port 74\n", machine().describe_context());
}
void tdl12_device::mem_map(address_map &map)
{
map(0x0000, 0x3fff).rom().region("firmware", 0);
map(0x4000, 0x47ff).ram();
map(0x8000, 0x8001).rw(FUNC(tdl12_device::latch_r), FUNC(tdl12_device::latch_w));
}
void tdl12_device::io_map(address_map &map)
{
map.global_mask(0xff);
map(0x00, 0x03).rw("cio", FUNC(z8536_device::read), FUNC(z8536_device::write));
map(0x40, 0x40).rw(FUNC(tdl12_device::in40_r), FUNC(tdl12_device::out40_w));
map(0x70, 0x70).w(FUNC(tdl12_device::out70_w));
map(0x74, 0x74).w(FUNC(tdl12_device::out74_w));
map(0x80, 0x87).m("scsi:7:ncr5380", FUNC(ncr5380_device::map));
}
void tdl12_device::device_add_mconfig(machine_config &config)
{
Z80(config, m_tdcpu, 12_MHz_XTAL / 2); // covered by "TD SYSTEMS INC." sticker (most likely Z80B)
m_tdcpu->set_addrmap(AS_PROGRAM, &tdl12_device::mem_map);
m_tdcpu->set_addrmap(AS_IO, &tdl12_device::io_map);
z8536_device &cio(Z8536(config, "cio", 12_MHz_XTAL / 2)); // ST Z8536AB1
cio.irq_wr_cb().set_inputline(m_tdcpu, 0);
cio.pb_wr_cb().set("eeprom", FUNC(eeprom_serial_93cxx_device::clk_write)).bit(0);
cio.pb_wr_cb().append("eeprom", FUNC(eeprom_serial_93cxx_device::di_write)).bit(1);
cio.pc_rd_cb().set("eeprom", FUNC(eeprom_serial_93cxx_device::do_read)).lshift(3);
cio.pc_wr_cb().set("eeprom", FUNC(eeprom_serial_93cxx_device::cs_write)).bit(2);
NSCSI_BUS(config, "scsi");
NSCSI_CONNECTOR(config, "scsi:0", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:1", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:2", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:3", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:4", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:5", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:6", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:7").option_set("ncr5380", NCR5380).machine_config([this](device_t *device) {
(void)this;
});
EEPROM_93C46_16BIT(config, "eeprom"); // NMC9346N
}
ROM_START(tdl12)
ROM_REGION(0x4000, "firmware", 0)
ROM_LOAD("tdl-12_v180.bin", 0x0000, 0x4000, CRC(fd0f4468) SHA1(1cf0bf8702747ff3047691d2b661bb08d40754f0)) // Am(27128?)-25DC
ROM_REGION(0x40, "proms", 0) // probably either Q-bus address decode or a short bootstrap program
ROM_LOAD("m_tdl-11.bin", 0x00, 0x20, NO_DUMP) // N82S123AN
ROM_LOAD("m_tdl-12.bin", 0x20, 0x20, NO_DUMP) // N82S123AN
ROM_REGION(0x7a1, "plds", 0)
ROM_LOAD("mst_tdl-13.bin", 0x000, 0x117, NO_DUMP) // TIBPAL16L8-25CN (socketed, next to A/B jumpers)
ROM_LOAD("mst_tdl-21.bin", 0x117, 0x117, NO_DUMP) // TIBPAL16L8-25CN
ROM_LOAD("mst_tdl-26.bin", 0x22e, 0x117, NO_DUMP) // TIBPAL16L8-25CN
ROM_LOAD("mst_tdl-31.bin", 0x345, 0x117, NO_DUMP) // TIBPAL16L8-25CN
ROM_LOAD("mst_tdl-40.bin", 0x45c, 0x117, NO_DUMP) // TIBPAL16L8-25CN
ROM_LOAD("mst_tdl-41.bin", 0x573, 0x117, NO_DUMP) // TIBPAL16L8-25CN
ROM_LOAD("mst_tdl-42.bin", 0x68a, 0x117, NO_DUMP) // TIBPAL16L8-25CN
ROM_END
const tiny_rom_entry *tdl12_device::device_rom_region() const
{
return ROM_NAME(tdl12);
}

View File

@ -0,0 +1,42 @@
// license:BSD-3-Clause
// copyright-holders:AJR
#ifndef MAME_BUS_QBUS_TDL12_H
#define MAME_BUS_QBUS_TDL12_H
#pragma once
#include "qbus.h"
#include "machine/ncr5380.h"
class tdl12_device : public device_t, public device_qbus_card_interface
{
public:
// device type constructor
tdl12_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
// device-level overrides
virtual void device_start() override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
private:
u8 latch_r(offs_t offset);
void latch_w(offs_t offset, u8 data);
u8 in40_r();
void out40_w(u8 data);
void out70_w(u8 data);
void out74_w(u8 data);
void mem_map(address_map &map) ATTR_COLD;
void io_map(address_map &map) ATTR_COLD;
required_device<cpu_device> m_tdcpu;
};
// device type declaration
DECLARE_DEVICE_TYPE(TDL12, tdl12_device)
#endif // MAME_BUS_QBUS_TDL12_H

View File

@ -201,15 +201,22 @@ u8 cio_base_device::read_register(offs_t offset)
switch (offset)
{
case PORT_A_DATA:
data = m_read_pa(0);
// TODO: take data path polarity into account
data = m_output[PORT_A];
if (m_register[PORT_A_DATA_DIRECTION] != 0)
data = (data & ~m_register[PORT_A_DATA_DIRECTION]) | (m_read_pa() & m_register[PORT_A_DATA_DIRECTION]);
break;
case PORT_B_DATA:
data = m_read_pb(0);
// TODO: take data path polarity into account
data = m_output[PORT_B];
if (m_register[PORT_B_DATA_DIRECTION] != 0)
data = (data & ~m_register[PORT_B_DATA_DIRECTION]) | (m_read_pb() & m_register[PORT_B_DATA_DIRECTION]);
break;
case PORT_C_DATA:
data = 0xf0 | (m_read_pc(0) & 0x0f);
// TODO: take data path polarity into account
data = 0xf0 | (m_read_pc() & 0x0f);
break;
case COUNTER_TIMER_1_CURRENT_COUNT_MS_BYTE:
@ -340,17 +347,17 @@ void cio_base_device::write_register(offs_t offset, u8 data)
case PORT_C_DATA_PATH_POLARITY:
LOG("%s CIO Port C Data Path Polarity: %02x\n", machine().describe_context(), data);
m_register[offset] = data;
m_register[offset] = data & 0x0f;
break;
case PORT_C_DATA_DIRECTION:
LOG("%s CIO Port C Data Direction: %02x\n", machine().describe_context(), data);
m_register[offset] = data;
m_register[offset] = data & 0x0f;
break;
case PORT_C_SPECIAL_IO_CONTROL:
LOG("%s CIO Port C Special I/O Control: %02x\n", machine().describe_context(), data);
m_register[offset] = data;
m_register[offset] = data & 0x0f;
break;
case PORT_A_COMMAND_AND_STATUS:
@ -422,11 +429,15 @@ void cio_base_device::write_register(offs_t offset, u8 data)
break;
case PORT_A_DATA:
m_write_pa((offs_t)0, data);
// TODO: take data path polarity into account
m_output[PORT_A] = data;
m_write_pa(data);
break;
case PORT_B_DATA:
m_write_pb((offs_t)0, data);
// TODO: take data path polarity into account
m_output[PORT_B] = data;
m_write_pb(data);
break;
case PORT_C_DATA:
@ -435,7 +446,8 @@ void cio_base_device::write_register(offs_t offset, u8 data)
m_output[PORT_C] = (m_output[PORT_C] & mask) | ((data & 0x0f) & (mask ^ 0xff));
m_write_pc((offs_t)0, m_output[PORT_C]);
// TODO: take data path polarity into account
m_write_pc(m_output[PORT_C]);
}
break;
@ -862,6 +874,9 @@ void cio_base_device::device_reset()
m_register[PORT_A_COMMAND_AND_STATUS] = PCS_ORE;
m_register[PORT_B_COMMAND_AND_STATUS] = PCS_ORE;
m_register[CURRENT_VECTOR] = 0xff;
m_register[PORT_A_DATA_DIRECTION] = 0xff;
m_register[PORT_B_DATA_DIRECTION] = 0xff;
m_register[PORT_C_DATA_DIRECTION] = 0x0f;
check_interrupt();
}