New S-100 device: ASC Associates SASI Host Computer Adapter [AJR, Bitsavers]

This commit is contained in:
AJR 2019-12-06 19:00:26 -05:00
parent 05d6c01a48
commit efbe4b30ba
4 changed files with 384 additions and 0 deletions

View File

@ -1796,6 +1796,8 @@ if (BUSES["S100"]~=null) then
MAME_DIR .. "src/devices/bus/s100/s100.h",
MAME_DIR .. "src/devices/bus/s100/am310.cpp",
MAME_DIR .. "src/devices/bus/s100/am310.h",
MAME_DIR .. "src/devices/bus/s100/ascsasi.cpp",
MAME_DIR .. "src/devices/bus/s100/ascsasi.h",
MAME_DIR .. "src/devices/bus/s100/dg640.cpp",
MAME_DIR .. "src/devices/bus/s100/dg640.h",
MAME_DIR .. "src/devices/bus/s100/dj2db.cpp",

View File

@ -0,0 +1,362 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/**********************************************************************
ASC Associates SASI Host Computer Adapter
This is a simple host adapter using LSTTL latches and buffers to
interface a SASI Winchester drive to the S-100 bus. The 2716 PROM
contains 8080 bootstrap code for a CP/M system.
For a technical description of this board by its designers, see
"Building a Hard-Disk Interface for a S-100 Bus System" by Andrew
C. Cruce and Scott A. Alexander in the March, April and May 1983
issues of BYTE magazine. (The schematic diagrams contain various
minor errors.)
**********************************************************************/
#include "emu.h"
#include "ascsasi.h"
#include "bus/nscsi/devices.h"
#include "machine/nscsi_bus.h"
#include "machine/nscsi_cb.h"
class asc_sasi_device : public device_t, public device_s100_card_interface
{
// N.B. actual pulse widths depend on S-100 bus characteristics
static constexpr attotime s_pulse_width = attotime::from_nsec(500);
public:
// construction/destruction
asc_sasi_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
virtual ioport_constructor device_input_ports() const override;
virtual void device_add_mconfig(machine_config &config) override;
virtual const tiny_rom_entry *device_rom_region() const override;
// device_s100_card_interface overrides
virtual u8 s100_smemr_r(offs_t offset) override;
virtual u8 s100_sinp_r(offs_t offset) override;
virtual void s100_sout_w(offs_t offset, u8 data) override;
private:
DECLARE_WRITE_LINE_MEMBER(iio_w);
DECLARE_WRITE_LINE_MEMBER(req_w);
void sasi_sel_pulse();
void sasi_rst_pulse();
TIMER_CALLBACK_MEMBER(sel_off);
TIMER_CALLBACK_MEMBER(rst_off);
// object finders
required_device<nscsi_bus_device> m_sasi;
required_region_ptr<u8> m_bootstrap;
required_ioport m_memsel;
required_ioport m_iosel;
// pulse timers
emu_timer *m_sel_off_timer;
emu_timer *m_rst_off_timer;
// internal state
u8 m_data_latch;
bool m_boot;
};
constexpr attotime asc_sasi_device::s_pulse_width; // stupid non-inline semantics
DEFINE_DEVICE_TYPE_PRIVATE(S100_ASC_SASI, device_s100_card_interface, asc_sasi_device, "ascsasi", "ASC Associates SASI Host Computer Adapter")
asc_sasi_device::asc_sasi_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, S100_ASC_SASI, tag, owner, clock)
, device_s100_card_interface(mconfig, *this)
, m_sasi(*this, "sasi")
, m_bootstrap(*this, "bootstrap")
, m_memsel(*this, "MEMSEL")
, m_iosel(*this, "IOSEL")
, m_sel_off_timer(nullptr)
, m_rst_off_timer(nullptr)
, m_data_latch(0)
, m_boot(false)
{
}
void asc_sasi_device::device_start()
{
// initialize timers
m_sel_off_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(asc_sasi_device::sel_off), this));
m_rst_off_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(asc_sasi_device::rst_off), this));
// save state
save_item(NAME(m_data_latch));
save_item(NAME(m_boot));
}
void asc_sasi_device::device_reset()
{
// POC causes RST pulse on SASI bus (unless jumper is removed)
sasi_rst_pulse();
// CLR sets flip-flop (IC10a)
m_boot = true;
}
WRITE_LINE_MEMBER(asc_sasi_device::iio_w)
{
// Release data bus when I/O is asserted
if (state)
m_sasi->data_w(7, 0);
else
m_sasi->data_w(7, m_data_latch);
}
WRITE_LINE_MEMBER(asc_sasi_device::req_w)
{
// Clear ACK when REQ is negated
if (!state)
m_sasi->ctrl_w(7, 0, nscsi_device::S_ACK);
}
void asc_sasi_device::sasi_sel_pulse()
{
m_sel_off_timer->adjust(s_pulse_width);
}
void asc_sasi_device::sasi_rst_pulse()
{
m_rst_off_timer->adjust(s_pulse_width);
}
TIMER_CALLBACK_MEMBER(asc_sasi_device::sel_off)
{
}
TIMER_CALLBACK_MEMBER(asc_sasi_device::rst_off)
{
}
u8 asc_sasi_device::s100_smemr_r(offs_t offset)
{
u8 memsel = m_memsel->read();
if (m_boot && BIT(memsel, 0) && (offset & 0xf800) == (memsel & 0x3e) << 10)
return m_bootstrap[offset & 0x7ff];
else
return 0xff;
}
u8 asc_sasi_device::s100_sinp_r(offs_t offset)
{
// Only two input ports are decoded
if ((offset & 0xfe) == (m_iosel->read() & 0x3f) << 2)
{
if (BIT(offset, 0))
{
// 74LS240 buffer (IC7)
u32 ctrl = m_sasi->ctrl_r();
return (ctrl & nscsi_device::S_INP ? 0x01 : 0x00)
| (ctrl & nscsi_device::S_BSY ? 0x04 : 0x00)
| (ctrl & nscsi_device::S_REQ ? 0x10 : 0x00)
| (ctrl & nscsi_device::S_CTL ? 0x80 : 0x00);
}
else
{
// INDAT: 74LS240 buffer (IC13)
if (!machine().side_effects_disabled() && (m_sasi->ctrl_r() && nscsi_device::S_REQ))
m_sasi->ctrl_w(7, nscsi_device::S_ACK, nscsi_device::S_ACK);
return m_sasi->data_r();
}
}
else
return 0xff;
}
void asc_sasi_device::s100_sout_w(offs_t offset, u8 data)
{
if ((offset & 0xfc) == (m_iosel->read() & 0x3f) << 2)
{
switch (offset & 0x03)
{
case 0:
// LATENA: 74LS373 latch (IC8) outputs to 74LS240 buffer (IC9)
if (!machine().side_effects_disabled() && (m_sasi->ctrl_r() && nscsi_device::S_REQ))
m_sasi->ctrl_w(7, nscsi_device::S_ACK, nscsi_device::S_ACK);
m_data_latch = data;
if (!(m_sasi->ctrl_r() && nscsi_device::S_INP))
m_sasi->data_w(7, data);
break;
case 1:
sasi_sel_pulse();
break;
case 2:
// MEMCON: clock DO5 into flip-flop (IC10a)
m_boot = BIT(data, 5);
break;
case 3:
sasi_rst_pulse();
break;
}
}
}
static INPUT_PORTS_START(ascsasi)
PORT_START("MEMSEL")
PORT_DIPNAME(0x01, 0x01, "Bootstrap PROM")
PORT_DIPSETTING(0x00, DEF_STR(Off))
PORT_DIPSETTING(0x01, DEF_STR(On))
PORT_DIPNAME(0x3e, 0x38, "PROM Address Decode") PORT_DIPLOCATION("SW1:2,3,4,5,6")
PORT_DIPSETTING(0x00, "0000-07FF")
PORT_DIPSETTING(0x02, "0800-0FFF")
PORT_DIPSETTING(0x04, "1000-17FF")
PORT_DIPSETTING(0x06, "1800-1FFF")
PORT_DIPSETTING(0x08, "2000-27FF")
PORT_DIPSETTING(0x0a, "2800-2FFF")
PORT_DIPSETTING(0x0c, "3000-37FF")
PORT_DIPSETTING(0x0e, "3800-3FFF")
PORT_DIPSETTING(0x10, "4000-47FF")
PORT_DIPSETTING(0x12, "4800-4FFF")
PORT_DIPSETTING(0x14, "5000-57FF")
PORT_DIPSETTING(0x16, "5800-5FFF")
PORT_DIPSETTING(0x18, "6000-67FF")
PORT_DIPSETTING(0x1a, "6800-6FFF")
PORT_DIPSETTING(0x1c, "7000-77FF")
PORT_DIPSETTING(0x1e, "7800-7FFF")
PORT_DIPSETTING(0x20, "8000-87FF")
PORT_DIPSETTING(0x22, "8800-8FFF")
PORT_DIPSETTING(0x24, "9000-97FF")
PORT_DIPSETTING(0x26, "9800-9FFF")
PORT_DIPSETTING(0x28, "A000-A7FF")
PORT_DIPSETTING(0x2a, "A800-AFFF")
PORT_DIPSETTING(0x2c, "B000-B7FF")
PORT_DIPSETTING(0x2e, "B800-BFFF")
PORT_DIPSETTING(0x30, "C000-C7FF")
PORT_DIPSETTING(0x32, "C800-CFFF")
PORT_DIPSETTING(0x34, "D000-D7FF")
PORT_DIPSETTING(0x36, "D800-DFFF")
PORT_DIPSETTING(0x38, "E000-E7FF")
PORT_DIPSETTING(0x3a, "E800-EFFF")
PORT_DIPSETTING(0x3c, "F000-F7FF")
PORT_DIPSETTING(0x3e, "F800-FFFF")
PORT_DIPNAME(0x40, 0x40, "PHANTOM Signal") PORT_DIPLOCATION("SW1:7") // not emulated
PORT_DIPSETTING(0x40, DEF_STR(Off))
PORT_DIPSETTING(0x00, DEF_STR(On))
PORT_DIPNAME(0x80, 0x80, "Memory Wait State") PORT_DIPLOCATION("SW1:8") // not emulated
PORT_DIPSETTING(0x80, DEF_STR(Off))
PORT_DIPSETTING(0x00, DEF_STR(On))
PORT_START("IOSEL")
PORT_DIPNAME(0x3f, 0x28, "I/O Address Decode") PORT_DIPLOCATION("SW2:1,2,3,4,5,6")
PORT_DIPSETTING(0x00, "00-03")
PORT_DIPSETTING(0x01, "04-07")
PORT_DIPSETTING(0x02, "08-0B")
PORT_DIPSETTING(0x03, "0C-0F")
PORT_DIPSETTING(0x04, "10-13")
PORT_DIPSETTING(0x05, "14-17")
PORT_DIPSETTING(0x06, "18-1B")
PORT_DIPSETTING(0x07, "1C-1F")
PORT_DIPSETTING(0x08, "20-23")
PORT_DIPSETTING(0x09, "24-27")
PORT_DIPSETTING(0x0a, "28-2B")
PORT_DIPSETTING(0x0b, "2C-2F")
PORT_DIPSETTING(0x0c, "30-33")
PORT_DIPSETTING(0x0d, "34-37")
PORT_DIPSETTING(0x0e, "38-3B")
PORT_DIPSETTING(0x0f, "3C-3F")
PORT_DIPSETTING(0x10, "40-43")
PORT_DIPSETTING(0x11, "44-47")
PORT_DIPSETTING(0x12, "48-4B")
PORT_DIPSETTING(0x13, "4C-4F")
PORT_DIPSETTING(0x14, "50-53")
PORT_DIPSETTING(0x15, "54-57")
PORT_DIPSETTING(0x16, "58-5B")
PORT_DIPSETTING(0x17, "5C-5F")
PORT_DIPSETTING(0x18, "60-63")
PORT_DIPSETTING(0x19, "64-67")
PORT_DIPSETTING(0x1a, "68-6B")
PORT_DIPSETTING(0x1b, "6C-6F")
PORT_DIPSETTING(0x1c, "70-73")
PORT_DIPSETTING(0x1d, "74-77")
PORT_DIPSETTING(0x1e, "78-7B")
PORT_DIPSETTING(0x1f, "7C-7F")
PORT_DIPSETTING(0x20, "80-83")
PORT_DIPSETTING(0x21, "84-87")
PORT_DIPSETTING(0x22, "88-8B")
PORT_DIPSETTING(0x23, "8C-8F")
PORT_DIPSETTING(0x24, "90-93")
PORT_DIPSETTING(0x25, "94-97")
PORT_DIPSETTING(0x26, "98-9B")
PORT_DIPSETTING(0x27, "9C-9F")
PORT_DIPSETTING(0x28, "A0-A3")
PORT_DIPSETTING(0x29, "A4-A7")
PORT_DIPSETTING(0x2a, "A8-AB")
PORT_DIPSETTING(0x2b, "AC-AF")
PORT_DIPSETTING(0x2c, "B0-B3")
PORT_DIPSETTING(0x2d, "B4-B7")
PORT_DIPSETTING(0x2e, "B8-BB")
PORT_DIPSETTING(0x2f, "BC-BF")
PORT_DIPSETTING(0x30, "C0-C3")
PORT_DIPSETTING(0x31, "C4-C7")
PORT_DIPSETTING(0x32, "C8-CB")
PORT_DIPSETTING(0x33, "CC-CF")
PORT_DIPSETTING(0x34, "D0-D3")
PORT_DIPSETTING(0x35, "D4-D7")
PORT_DIPSETTING(0x36, "D8-DB")
PORT_DIPSETTING(0x37, "DC-DF")
PORT_DIPSETTING(0x38, "E0-E3")
PORT_DIPSETTING(0x39, "E4-E7")
PORT_DIPSETTING(0x3a, "E8-EB")
PORT_DIPSETTING(0x3b, "EC-EF")
PORT_DIPSETTING(0x3c, "F0-F3")
PORT_DIPSETTING(0x3d, "F4-F7")
PORT_DIPSETTING(0x3e, "F8-FB")
PORT_DIPSETTING(0x3f, "FC-FF")
PORT_DIPNAME(0x40, 0x40, DEF_STR(Unused)) PORT_DIPLOCATION("SW2:7")
PORT_DIPSETTING(0x40, DEF_STR(Off))
PORT_DIPSETTING(0x00, DEF_STR(On))
PORT_DIPNAME(0x80, 0x80, DEF_STR(Unused)) PORT_DIPLOCATION("SW2:8")
PORT_DIPSETTING(0x80, DEF_STR(Off))
PORT_DIPSETTING(0x00, DEF_STR(On))
INPUT_PORTS_END
ioport_constructor asc_sasi_device::device_input_ports() const
{
return INPUT_PORTS_NAME(ascsasi);
}
void asc_sasi_device::device_add_mconfig(machine_config &config)
{
NSCSI_BUS(config, m_sasi);
NSCSI_CONNECTOR(config, "sasi:0", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "sasi:1", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "sasi:2", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "sasi:3", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "sasi:4", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "sasi:5", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "sasi:6", default_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "sasi:7", default_scsi_devices, "sasicb", true)
.option_add_internal("sasicb", NSCSI_CB)
.machine_config([this] (device_t *device) {
downcast<nscsi_callback_device &>(*device).io_callback().set(*this, FUNC(asc_sasi_device::iio_w));
downcast<nscsi_callback_device &>(*device).req_callback().set(*this, FUNC(asc_sasi_device::req_w));
});
}
ROM_START(ascsasi)
ROM_REGION(0x800, "bootstrap", 0)
ROM_LOAD("asc_sasi.bin", 0x000, 0x800, CRC(aac84077) SHA1(e94b39875e29daff199d120c4e79dfb1adbedab2)) // MODEL 1 REV. 2
ROM_END
const tiny_rom_entry *asc_sasi_device::device_rom_region() const
{
return ROM_NAME(ascsasi);
}

View File

@ -0,0 +1,18 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/**********************************************************************
ASC Associates SASI Host Computer Adapter
**********************************************************************/
#ifndef MAME_BUS_S100_ASCSASI_H
#define MAME_BUS_S100_ASCSASI_H
#pragma once
#include "bus/s100/s100.h"
DECLARE_DEVICE_TYPE(S100_ASC_SASI, device_s100_card_interface)
#endif // MAME_BUS_S100_ASCSASI_H

View File

@ -48,6 +48,7 @@ at least some models of the Poly-88 are known to have used.)
#include "emu.h"
#include "includes/poly88.h"
#include "bus/s100/ascsasi.h"
#include "bus/s100/poly16k.h"
#include "bus/s100/polyfdc.h"
#include "bus/s100/polyvti.h"
@ -107,6 +108,7 @@ static void poly88_s100_devices(device_slot_interface &device)
device.option_add("8kscbb", S100_8K_SC_BB);
device.option_add("poly16k", S100_POLY_16K);
device.option_add("polyfdc", S100_POLY_FDC);
device.option_add("ascsasi", S100_ASC_SASI);
}
DEVICE_INPUT_DEFAULTS_START(poly88_vti_1800)