mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
ncr5385: initial nscsi implementation
This commit is contained in:
parent
d1fefb196a
commit
47f8f4b286
@ -1,119 +1,783 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Ryan Holtz
|
||||
/***********************************************************************
|
||||
|
||||
NCR 5385E SCSI Controller
|
||||
|
||||
TOOD:
|
||||
- Everything.
|
||||
|
||||
***********************************************************************/
|
||||
/*
|
||||
* NCR 5385 SCSI Protocol Controller
|
||||
*
|
||||
* Sources:
|
||||
* - NCR 5385 SCSI Protocol Controller, 1983, NCR Corporation, Dayton, Ohio, USA
|
||||
* - NCR SCSI Engineering Notebook, 1984, NCR Microelectronics
|
||||
*
|
||||
* TODO:
|
||||
* - single byte transfer
|
||||
* - target mode send/receive
|
||||
* - disconnect/reselection
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "ncr5385.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(NCR5385, ncr5385_device, "ncr5385", "NCR 5385E SCSI Controller")
|
||||
#define LOG_GENERAL (1U << 0)
|
||||
#define LOG_REGW (1U << 1)
|
||||
#define LOG_REGR (1U << 2)
|
||||
#define LOG_STATE (1U << 3)
|
||||
#define LOG_DMA (1U << 4)
|
||||
#define LOG_COMMAND (1U << 5)
|
||||
|
||||
ncr5385_device::ncr5385_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, NCR5385, tag, owner, clock)
|
||||
//#define VERBOSE (LOG_GENERAL|LOG_REGW|LOG_REGR|LOG_STATE|LOG_DMA|LOG_COMMAND)
|
||||
#include "logmacro.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(NCR5385, ncr5385_device, "ncr5385", "NCR 5385 SCSI Protocol Controller")
|
||||
|
||||
// FIXME: would be better to reuse from nscsi_full_device
|
||||
static unsigned const SCSI_ARB_DELAY = 2'400;
|
||||
static unsigned const SCSI_BUS_CLEAR = 800;
|
||||
static unsigned const SCSI_BUS_FREE = 800;
|
||||
static unsigned const SCSI_BUS_SETTLE = 400;
|
||||
static unsigned const SCSI_BUS_SKEW = 10;
|
||||
static unsigned const SCSI_RST_HOLD = 25'000;
|
||||
|
||||
ncr5385_device::ncr5385_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
|
||||
: nscsi_device(mconfig, NCR5385, tag, owner, clock)
|
||||
, nscsi_slot_card_interface(mconfig, *this, DEVICE_SELF)
|
||||
, m_int(*this)
|
||||
, m_dreq(*this)
|
||||
, m_int_state(false)
|
||||
, m_dreq_state(false)
|
||||
{
|
||||
}
|
||||
|
||||
enum state : u32
|
||||
{
|
||||
IDLE,
|
||||
DIAGNOSTIC,
|
||||
|
||||
ARB_BUS_FREE,
|
||||
ARB_START,
|
||||
ARB_EVALUATE,
|
||||
SEL_START,
|
||||
SEL_DELAY,
|
||||
SEL_WAIT_BSY,
|
||||
SEL_COMPLETE,
|
||||
SEL_WAIT_REQ,
|
||||
|
||||
XFI_START,
|
||||
XFI_IN_REQ,
|
||||
XFI_IN_DRQ,
|
||||
XFI_IN_ACK,
|
||||
XFI_OUT_REQ,
|
||||
XFI_OUT_DRQ,
|
||||
XFI_OUT_ACK,
|
||||
XFI_OUT_PAD,
|
||||
};
|
||||
|
||||
enum mode : u8
|
||||
{
|
||||
DISCONNECTED,
|
||||
INITIATOR,
|
||||
TARGET,
|
||||
};
|
||||
|
||||
enum diag_mask : u8
|
||||
{
|
||||
DIAG_SELF = 0x07, // self-diagnostic status
|
||||
DIAG_CMD = 0x38, // diagnostic command status
|
||||
DIAG_DONE = 0x80, // self-diagnostic complete
|
||||
|
||||
DIAG_CMD_GP = 0x18, // diagnostic good parity
|
||||
DIAG_CMD_BP = 0x20, // diagnostic bad parity
|
||||
};
|
||||
|
||||
enum int_mask : u8
|
||||
{
|
||||
INT_FUNC_COMPLETE = 0x01,
|
||||
INT_BUS_SERVICE = 0x02,
|
||||
INT_DISCONNECTED = 0x04,
|
||||
INT_SELECTED = 0x08,
|
||||
INT_RESELECTED = 0x10,
|
||||
INT_INVALID_CMD = 0x40,
|
||||
};
|
||||
|
||||
enum aux_status_mask : u8
|
||||
{
|
||||
AUX_STATUS_TC_ZERO = 0x02,
|
||||
AUX_STATUS_PAUSED = 0x04,
|
||||
AUX_STATUS_IO = 0x08,
|
||||
AUX_STATUS_CD = 0x10,
|
||||
AUX_STATUS_MSG = 0x20,
|
||||
AUX_STATUS_PARITY_ERR = 0x40,
|
||||
AUX_STATUS_DATA_FULL = 0x80,
|
||||
};
|
||||
|
||||
enum cmd_mask : u8
|
||||
{
|
||||
CMD_INT = 0x08, // interrupting
|
||||
CMD_SBX = 0x40, // single byte transfer
|
||||
CMD_DMA = 0x80, // DMA mode
|
||||
};
|
||||
|
||||
void ncr5385_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_dat));
|
||||
save_item(NAME(m_cmd));
|
||||
save_item(NAME(m_ctl));
|
||||
save_item(NAME(m_dst_id));
|
||||
save_item(NAME(m_aux_status));
|
||||
save_item(NAME(m_own_id));
|
||||
save_item(NAME(m_int_status));
|
||||
save_item(NAME(m_src_id));
|
||||
save_item(NAME(m_dia_status));
|
||||
save_item(NAME(m_cnt));
|
||||
|
||||
save_item(NAME(m_state));
|
||||
save_item(NAME(m_xfi_phase));
|
||||
save_item(NAME(m_mode));
|
||||
|
||||
save_item(NAME(m_int_state));
|
||||
save_item(NAME(m_dreq_state));
|
||||
|
||||
m_state_timer = timer_alloc(timer_expired_delegate(FUNC(ncr5385_device::state_timer), this));
|
||||
|
||||
m_dia_status = DIAG_DONE;
|
||||
}
|
||||
|
||||
void ncr5385_device::device_reset()
|
||||
{
|
||||
m_state = STATE_IDLE;
|
||||
m_int_reg = 0;
|
||||
m_ctrl_reg = 0;
|
||||
m_aux_status_reg = AUX_STATUS_TC_ZERO;
|
||||
m_diag_status_reg = DIAG_COMPLETE;
|
||||
m_cmd = 0;
|
||||
m_ctl = 0;
|
||||
m_dst_id = 0;
|
||||
m_aux_status = AUX_STATUS_TC_ZERO;
|
||||
m_int_status = 0;
|
||||
m_src_id = 0;
|
||||
m_dia_status &= (DIAG_DONE | DIAG_SELF);
|
||||
m_cnt = 0;
|
||||
|
||||
m_state = IDLE;
|
||||
m_mode = DISCONNECTED;
|
||||
|
||||
// monitor all control lines
|
||||
scsi_bus->ctrl_wait(scsi_refid, S_ALL, S_ALL);
|
||||
|
||||
update_int();
|
||||
}
|
||||
|
||||
void ncr5385_device::write(offs_t offset, uint8_t data)
|
||||
void ncr5385_device::scsi_ctrl_changed()
|
||||
{
|
||||
switch (offset)
|
||||
u32 const ctrl = scsi_bus->ctrl_r();
|
||||
|
||||
static char const *const nscsi_phase[] = { "DATA OUT", "DATA IN", "COMMAND", "STATUS", "*", "*", "MESSAGE OUT", "MESSAGE IN" };
|
||||
|
||||
if (ctrl & S_RST)
|
||||
LOGMASKED(LOG_STATE, "scsi_ctrl_changed 0x%03x BUS RESET\n", ctrl);
|
||||
else if ((ctrl & S_BSY) && !(ctrl & S_SEL))
|
||||
LOGMASKED(LOG_STATE, "scsi_ctrl_changed 0x%03x phase %s%s%s\n", ctrl, nscsi_phase[ctrl & S_PHASE_MASK],
|
||||
ctrl & S_REQ ? " REQ" : "", ctrl & S_ACK ? " ACK" : "");
|
||||
else if (ctrl & S_BSY)
|
||||
LOGMASKED(LOG_STATE, "scsi_ctrl_changed 0x%03x arbitration/selection\n", ctrl);
|
||||
else
|
||||
{
|
||||
case 0x0: // Data Register
|
||||
switch (m_state)
|
||||
{
|
||||
case STATE_DIAGNOSTIC_GOOD_PARITY:
|
||||
m_aux_status_reg &= ~AUX_STATUS_PARITY_ERR;
|
||||
m_aux_status_reg |= AUX_STATUS_DATA_FULL;
|
||||
m_int_reg = INT_FUNC_COMPLETE;
|
||||
m_diag_status_reg = DIAG_COMPLETE | DIAG_TURN_GOOD_PARITY;
|
||||
m_state = STATE_IDLE;
|
||||
m_int(1);
|
||||
logerror("%s: ncr5385_w: data=%02x (diagnostic w/ good parity)\n", machine().describe_context(), data);
|
||||
break;
|
||||
case STATE_DIAGNOSTIC_BAD_PARITY:
|
||||
m_aux_status_reg |= AUX_STATUS_PARITY_ERR | AUX_STATUS_DATA_FULL;
|
||||
m_int_reg = INT_FUNC_COMPLETE;
|
||||
m_diag_status_reg = DIAG_COMPLETE | DIAG_TURN_BAD_PARITY;
|
||||
m_state = STATE_IDLE;
|
||||
m_int(1);
|
||||
logerror("%s: ncr5385_w: data=%02x (diagnostic w/ bad parity)\n", machine().describe_context(), data);
|
||||
break;
|
||||
default:
|
||||
logerror("%s: ncr5385_w: data=%02x\n", machine().describe_context(), data);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x1: // Command Register
|
||||
switch (data & 0x3f)
|
||||
{
|
||||
case 0x00: // Chip Reset
|
||||
logerror("%s: ncr5385_w: command: reset\n", machine().describe_context());
|
||||
m_state = STATE_IDLE;
|
||||
m_int_reg = 0;
|
||||
m_aux_status_reg = AUX_STATUS_TC_ZERO;
|
||||
m_diag_status_reg = DIAG_COMPLETE;
|
||||
m_int(0);
|
||||
break;
|
||||
case 0x0b: // Diagnostic
|
||||
logerror("%s: ncr5385_w: command: diagnostic (%s parity)\n", machine().describe_context(), BIT(data, 6) ? "bad" : "good");
|
||||
if (BIT(data, 6))
|
||||
m_state = STATE_DIAGNOSTIC_BAD_PARITY;
|
||||
else
|
||||
m_state = STATE_DIAGNOSTIC_GOOD_PARITY;
|
||||
break;
|
||||
default:
|
||||
logerror("%s: ncr5385_w: command: %02x\n", machine().describe_context(), data);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x2: // Control Register
|
||||
m_ctrl_reg = data & 0x07;
|
||||
logerror("%s: ncr5385_w: control: parity_en=%d, reselect_en=%d, select_en=%d\n", machine().describe_context(), BIT(data, CTRL_PARITY_BIT), BIT(data, CTRL_RESELECT_BIT), BIT(data, CTRL_SELECT_BIT));
|
||||
break;
|
||||
default:
|
||||
logerror("%s: ncr5385_w: %x=%02x\n", machine().describe_context(), offset, data);
|
||||
break;
|
||||
LOGMASKED(LOG_STATE, "scsi_ctrl_changed 0x%03x BUS FREE\n", ctrl);
|
||||
|
||||
if (m_mode == INITIATOR)
|
||||
{
|
||||
m_mode = DISCONNECTED;
|
||||
m_int_status |= INT_DISCONNECTED;
|
||||
update_int();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ncr5385_device::read(offs_t offset)
|
||||
void ncr5385_device::map(address_map &map)
|
||||
{
|
||||
switch (offset)
|
||||
map(0x0, 0x0).rw(FUNC(ncr5385_device::dat_r), FUNC(ncr5385_device::dat_w));
|
||||
map(0x1, 0x1).rw(FUNC(ncr5385_device::cmd_r), FUNC(ncr5385_device::cmd_w));
|
||||
map(0x2, 0x2).rw(FUNC(ncr5385_device::ctl_r), FUNC(ncr5385_device::ctl_w));
|
||||
map(0x3, 0x3).rw(FUNC(ncr5385_device::dst_id_r), FUNC(ncr5385_device::dst_id_w));
|
||||
map(0x4, 0x4).r(FUNC(ncr5385_device::aux_status_r));
|
||||
map(0x5, 0x5).r(FUNC(ncr5385_device::own_id_r));
|
||||
map(0x6, 0x6).r(FUNC(ncr5385_device::int_status_r));
|
||||
map(0x7, 0x7).r(FUNC(ncr5385_device::src_id_r));
|
||||
map(0x9, 0x9).r(FUNC(ncr5385_device::dia_status_r));
|
||||
map(0xc, 0xc).rw(FUNC(ncr5385_device::cnt_r<2>), FUNC(ncr5385_device::cnt_w<2>));
|
||||
map(0xd, 0xd).rw(FUNC(ncr5385_device::cnt_r<1>), FUNC(ncr5385_device::cnt_w<1>));
|
||||
map(0xe, 0xe).rw(FUNC(ncr5385_device::cnt_r<0>), FUNC(ncr5385_device::cnt_w<0>));
|
||||
map(0xf, 0xf).rw(FUNC(ncr5385_device::tst_r), FUNC(ncr5385_device::tst_w));
|
||||
}
|
||||
|
||||
u8 ncr5385_device::dat_r()
|
||||
{
|
||||
if (m_aux_status & AUX_STATUS_DATA_FULL)
|
||||
m_aux_status &= ~AUX_STATUS_DATA_FULL;
|
||||
else
|
||||
logerror("data register empty (%s)\n", machine().describe_context());
|
||||
|
||||
return m_dat;
|
||||
}
|
||||
|
||||
u8 ncr5385_device::cmd_r()
|
||||
{
|
||||
return m_cmd;
|
||||
}
|
||||
|
||||
u8 ncr5385_device::ctl_r()
|
||||
{
|
||||
return m_ctl;
|
||||
}
|
||||
|
||||
u8 ncr5385_device::dst_id_r()
|
||||
{
|
||||
return m_dst_id;
|
||||
}
|
||||
|
||||
u8 ncr5385_device::aux_status_r()
|
||||
{
|
||||
u8 data = m_aux_status;
|
||||
|
||||
if (!m_int_status)
|
||||
{
|
||||
case 0x2:
|
||||
logerror("%s: ncr5385_r: control (%02x)\n", machine().describe_context(), m_ctrl_reg);
|
||||
return m_ctrl_reg;
|
||||
case 0x4:
|
||||
logerror("%s: ncr5385_r: aux status (%02x)\n", machine().describe_context(), m_aux_status_reg);
|
||||
return m_aux_status_reg;
|
||||
case 0x6:
|
||||
logerror("%s: ncr5385_r: interrupt (%02x)\n", machine().describe_context(), m_int_reg);
|
||||
m_int(1);
|
||||
return m_int_reg;
|
||||
case 0x9:
|
||||
logerror("%s: ncr5385_r: diagnostic status (%02x)\n", machine().describe_context(), m_diag_status_reg);
|
||||
return m_diag_status_reg;
|
||||
default:
|
||||
logerror("%s: ncr5385_r: %x (%02x)\n", machine().describe_context(), offset, 0);
|
||||
return 0;
|
||||
// return current phase
|
||||
u32 const ctrl = scsi_bus->ctrl_r();
|
||||
if (ctrl & S_MSG)
|
||||
data |= AUX_STATUS_MSG;
|
||||
if (ctrl & S_CTL)
|
||||
data |= AUX_STATUS_CD;
|
||||
if (ctrl & S_INP)
|
||||
data |= AUX_STATUS_IO;
|
||||
}
|
||||
LOGMASKED(LOG_REGR, "aux_status_r 0x%02x (%s)\n", data, machine().describe_context());
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
u8 ncr5385_device::own_id_r()
|
||||
{
|
||||
return m_own_id;
|
||||
}
|
||||
|
||||
u8 ncr5385_device::int_status_r()
|
||||
{
|
||||
u8 const data = m_int_status;
|
||||
LOGMASKED(LOG_REGR, "int_status_r 0x%02x (%s)\n", data, machine().describe_context());
|
||||
m_aux_status &= ~AUX_STATUS_PARITY_ERR;
|
||||
m_int_status = 0;
|
||||
update_int();
|
||||
|
||||
if (m_state != IDLE)
|
||||
m_state_timer->adjust(attotime::zero);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
u8 ncr5385_device::src_id_r()
|
||||
{
|
||||
return m_src_id;
|
||||
}
|
||||
|
||||
u8 ncr5385_device::dia_status_r()
|
||||
{
|
||||
return m_dia_status;
|
||||
}
|
||||
|
||||
template <unsigned N> u8 ncr5385_device::cnt_r()
|
||||
{
|
||||
return u8(m_cnt >> (N * 8));
|
||||
}
|
||||
|
||||
u8 ncr5385_device::tst_r()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ncr5385_device::dat_w(u8 data)
|
||||
{
|
||||
LOGMASKED(LOG_REGW, "dat_w 0x%02x (%s)\n", data, machine().describe_context());
|
||||
|
||||
if (!(m_aux_status & AUX_STATUS_DATA_FULL))
|
||||
{
|
||||
m_dat = data;
|
||||
m_aux_status |= AUX_STATUS_DATA_FULL;
|
||||
|
||||
if (m_state != IDLE)
|
||||
m_state_timer->adjust(attotime::zero);
|
||||
}
|
||||
else
|
||||
logerror("data register full\n");
|
||||
}
|
||||
|
||||
void ncr5385_device::cmd_w(u8 data)
|
||||
{
|
||||
LOGMASKED(LOG_REGW, "cmd_w 0x%02x (%s)\n", data, machine().describe_context());
|
||||
if (!(data & 0x18))
|
||||
{
|
||||
// immediate commands
|
||||
|
||||
switch (data & 0x1f)
|
||||
{
|
||||
case 0x00:
|
||||
LOGMASKED(LOG_COMMAND, "reset\n");
|
||||
reset();
|
||||
break;
|
||||
case 0x01: // disconnect
|
||||
LOGMASKED(LOG_COMMAND, "disconnect\n");
|
||||
m_mode = DISCONNECTED;
|
||||
break;
|
||||
case 0x02: // pause
|
||||
LOGMASKED(LOG_COMMAND, "pause\n");
|
||||
break;
|
||||
case 0x03: // set atn
|
||||
LOGMASKED(LOG_COMMAND, "set atn\n");
|
||||
scsi_bus->ctrl_w(scsi_refid, S_ATN, S_ATN);
|
||||
break;
|
||||
case 0x04: // message accepted
|
||||
LOGMASKED(LOG_COMMAND, "message accepted\n");
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
|
||||
break;
|
||||
case 0x05: // chip disabled
|
||||
LOGMASKED(LOG_COMMAND, "chip disabled\n");
|
||||
break;
|
||||
case 0x06: case 0x07:
|
||||
// reserved
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// interrupting commands
|
||||
m_aux_status &= ~AUX_STATUS_DATA_FULL;
|
||||
m_cmd = data;
|
||||
|
||||
switch (data & 0x1f)
|
||||
{
|
||||
case 0x08: // select w/atn
|
||||
LOGMASKED(LOG_COMMAND, "select %d w/atn (timeout %d)\n", m_dst_id, attotime::from_ticks(m_cnt * 1024, clock()).to_string());
|
||||
m_state = ARB_BUS_FREE;
|
||||
m_state_timer->adjust(attotime::zero);
|
||||
break;
|
||||
case 0x09: // select w/o atn
|
||||
LOGMASKED(LOG_COMMAND, "select %d w/o atn (timeout %d)\n", m_dst_id, attotime::from_ticks(m_cnt * 1024, clock()).to_string());
|
||||
m_state = ARB_BUS_FREE;
|
||||
m_state_timer->adjust(attotime::zero);
|
||||
break;
|
||||
case 0x0a: // reselect
|
||||
LOGMASKED(LOG_COMMAND, "reselect\n");
|
||||
break;
|
||||
case 0x0b: // diagnostic
|
||||
LOGMASKED(LOG_COMMAND, "diagnostic (%s parity)\n", BIT(data, 6) ? "bad" : "good");
|
||||
m_state = DIAGNOSTIC;
|
||||
break;
|
||||
case 0x0c: // receive command
|
||||
LOGMASKED(LOG_COMMAND, "receive command\n");
|
||||
break;
|
||||
case 0x0d: // receive data
|
||||
LOGMASKED(LOG_COMMAND, "receive data\n");
|
||||
break;
|
||||
case 0x0e: // receive message out
|
||||
LOGMASKED(LOG_COMMAND, "receive message out\n");
|
||||
break;
|
||||
case 0x0f: // receive unspecified info out
|
||||
LOGMASKED(LOG_COMMAND, "receive unspecified info out\n");
|
||||
break;
|
||||
case 0x10: // send status
|
||||
LOGMASKED(LOG_COMMAND, "send status\n");
|
||||
break;
|
||||
case 0x11: // send data
|
||||
LOGMASKED(LOG_COMMAND, "send data\n");
|
||||
break;
|
||||
case 0x12: // send message in
|
||||
LOGMASKED(LOG_COMMAND, "send message in\n");
|
||||
break;
|
||||
case 0x13: // send unspecified info in
|
||||
LOGMASKED(LOG_COMMAND, "send unspecified info in\n");
|
||||
break;
|
||||
case 0x14: // transfer info
|
||||
LOGMASKED(LOG_COMMAND, "transfer info (count=%d)\n", m_cnt);
|
||||
m_state = XFI_START;
|
||||
m_state_timer->adjust(attotime::zero);
|
||||
break;
|
||||
case 0x15: // transfer pad
|
||||
LOGMASKED(LOG_COMMAND, "transfer pad (count=%d)\n", m_cnt);
|
||||
m_state = XFI_START;
|
||||
m_state_timer->adjust(attotime::zero);
|
||||
break;
|
||||
case 0x16: case 0x17:
|
||||
case 0x18: case 0x19: case 0x1a: case 0x1b:
|
||||
case 0x1c: case 0x1d: case 0x1e: case 0x1f:
|
||||
// reserved
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ncr5385_device::ctl_w(u8 data)
|
||||
{
|
||||
LOGMASKED(LOG_REGW, "ctl_w 0x%02x (%s)\n", data, machine().describe_context());
|
||||
|
||||
m_ctl = data & 7;
|
||||
}
|
||||
|
||||
void ncr5385_device::dst_id_w(u8 data)
|
||||
{
|
||||
LOGMASKED(LOG_REGW, "dst_id_w 0x%02x (%s)\n", data, machine().describe_context());
|
||||
m_dst_id = (data & 7);
|
||||
}
|
||||
|
||||
template <unsigned N> void ncr5385_device::cnt_w(u8 data)
|
||||
{
|
||||
m_cnt = (m_cnt & ~(u32(0xff) << (N * 8))) | (u32(data) << (N * 8));
|
||||
}
|
||||
|
||||
void ncr5385_device::tst_w(u8 data)
|
||||
{
|
||||
LOGMASKED(LOG_REGW, "tst_w 0x%02x (%s)\n", data, machine().describe_context());
|
||||
}
|
||||
|
||||
u8 ncr5385_device::dma_r()
|
||||
{
|
||||
u8 const data = m_dat;
|
||||
m_aux_status &= ~AUX_STATUS_DATA_FULL;
|
||||
|
||||
set_dreq(false);
|
||||
m_state_timer->adjust(attotime::zero);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void ncr5385_device::dma_w(u8 data)
|
||||
{
|
||||
m_dat = data;
|
||||
m_aux_status |= AUX_STATUS_DATA_FULL;
|
||||
|
||||
set_dreq(false);
|
||||
m_state_timer->adjust(attotime::zero);
|
||||
}
|
||||
|
||||
void ncr5385_device::state_timer(s32 param)
|
||||
{
|
||||
// step state machine
|
||||
int const delay = state_step();
|
||||
|
||||
// check for data stall
|
||||
if (delay < 0)
|
||||
return;
|
||||
|
||||
// repeat until idle
|
||||
if (m_state != IDLE)
|
||||
m_state_timer->adjust(attotime::from_nsec(delay));
|
||||
}
|
||||
|
||||
int ncr5385_device::state_step()
|
||||
{
|
||||
u32 const ctrl = scsi_bus->ctrl_r();
|
||||
int delay = 0;
|
||||
|
||||
u8 const oid = 1 << m_own_id;
|
||||
u8 const tid = 1 << m_dst_id;
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case DIAGNOSTIC:
|
||||
m_dia_status &= DIAG_DONE | DIAG_SELF;
|
||||
if (BIT(m_cmd, 6))
|
||||
{
|
||||
m_aux_status |= AUX_STATUS_PARITY_ERR;
|
||||
m_dia_status |= DIAG_CMD_BP;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_aux_status &= ~AUX_STATUS_PARITY_ERR;
|
||||
m_dia_status |= DIAG_CMD_GP;
|
||||
}
|
||||
|
||||
m_int_status |= INT_FUNC_COMPLETE;
|
||||
m_state = IDLE;
|
||||
|
||||
update_int();
|
||||
break;
|
||||
|
||||
case ARB_BUS_FREE:
|
||||
LOGMASKED(LOG_STATE, "arbitration: waiting for bus free\n");
|
||||
if (!(ctrl & (S_SEL | S_BSY | S_RST)))
|
||||
{
|
||||
m_state = ARB_START;
|
||||
delay = SCSI_BUS_FREE;
|
||||
}
|
||||
break;
|
||||
case ARB_START:
|
||||
LOGMASKED(LOG_STATE, "arbitration: started\n");
|
||||
m_state = ARB_EVALUATE;
|
||||
delay = SCSI_ARB_DELAY;
|
||||
|
||||
// assert own ID and BSY
|
||||
scsi_bus->data_w(scsi_refid, oid);
|
||||
scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY);
|
||||
break;
|
||||
case ARB_EVALUATE:
|
||||
// check if SEL asserted, or if there's a higher ID on the bus
|
||||
if ((ctrl & S_SEL) || (scsi_bus->data_r() & ~((oid - 1) | oid)))
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "arbitration: lost\n");
|
||||
m_state = ARB_BUS_FREE;
|
||||
|
||||
// clear data and BSY
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_BSY);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "arbitration: won\n");
|
||||
m_state = SEL_START;
|
||||
delay = SCSI_BUS_CLEAR + SCSI_BUS_SETTLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEL_START:
|
||||
LOGMASKED(LOG_STATE, "selection: SEL asserted\n");
|
||||
m_state = SEL_DELAY;
|
||||
delay = SCSI_BUS_SKEW * 2;
|
||||
|
||||
// assert own and target ID and SEL
|
||||
scsi_bus->data_w(scsi_refid, oid | tid);
|
||||
scsi_bus->ctrl_w(scsi_refid, S_SEL, S_SEL);
|
||||
break;
|
||||
case SEL_DELAY:
|
||||
LOGMASKED(LOG_STATE, "selection: BSY cleared\n");
|
||||
m_state = SEL_WAIT_BSY;
|
||||
delay = SCSI_BUS_SETTLE;
|
||||
|
||||
// clear BSY, optionally assert ATN
|
||||
if (!BIT(m_cmd, 0))
|
||||
scsi_bus->ctrl_w(scsi_refid, S_ATN, S_BSY | S_ATN);
|
||||
else
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_BSY);
|
||||
break;
|
||||
case SEL_WAIT_BSY:
|
||||
if (ctrl & S_BSY)
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "selection: BSY asserted by target\n");
|
||||
m_state = SEL_COMPLETE;
|
||||
delay = SCSI_BUS_SKEW * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "selection: timed out\n");
|
||||
m_int_status |= INT_DISCONNECTED;
|
||||
m_state = IDLE;
|
||||
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_ATN | S_SEL);
|
||||
|
||||
update_int();
|
||||
}
|
||||
break;
|
||||
case SEL_COMPLETE:
|
||||
LOGMASKED(LOG_STATE, "selection: complete\n");
|
||||
m_int_status |= INT_FUNC_COMPLETE;
|
||||
m_mode = INITIATOR;
|
||||
m_state = SEL_WAIT_REQ;
|
||||
delay = -1;
|
||||
|
||||
update_int();
|
||||
|
||||
// clear data and SEL
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_SEL);
|
||||
break;
|
||||
case SEL_WAIT_REQ:
|
||||
if (ctrl & S_REQ)
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "selection: REQ asserted by target\n");
|
||||
m_int_status |= INT_BUS_SERVICE;
|
||||
m_state = IDLE;
|
||||
|
||||
update_int();
|
||||
}
|
||||
else
|
||||
delay = -1;
|
||||
break;
|
||||
|
||||
case XFI_START:
|
||||
m_xfi_phase = ctrl & S_PHASE_MASK;
|
||||
m_state = (ctrl & S_INP) ? XFI_IN_REQ : XFI_OUT_REQ;
|
||||
break;
|
||||
|
||||
case XFI_IN_REQ:
|
||||
// TODO: single byte transfer, disconnect
|
||||
if (ctrl & S_REQ)
|
||||
{
|
||||
if (m_cnt && (ctrl & S_PHASE_MASK) == m_xfi_phase)
|
||||
{
|
||||
m_state = XFI_IN_DRQ;
|
||||
|
||||
// no data transferred and no dma used by transfer pad command
|
||||
if (!BIT(m_cmd, 0))
|
||||
{
|
||||
m_aux_status |= AUX_STATUS_DATA_FULL;
|
||||
m_dat = scsi_bus->data_r();
|
||||
|
||||
if (m_cmd & CMD_DMA)
|
||||
set_dreq(true);
|
||||
|
||||
delay = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "xfi_in: %s\n", m_cnt ? "phase change" : "transfer complete");
|
||||
|
||||
m_int_status |= INT_BUS_SERVICE;
|
||||
m_state = IDLE;
|
||||
|
||||
update_int();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XFI_IN_DRQ:
|
||||
m_state = XFI_IN_ACK;
|
||||
|
||||
LOGMASKED(LOG_STATE, "xfi_in: data 0x%02x\n", m_dat);
|
||||
|
||||
// assert ACK
|
||||
scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
|
||||
break;
|
||||
case XFI_IN_ACK:
|
||||
if (!(ctrl & S_REQ))
|
||||
{
|
||||
m_state = XFI_IN_REQ;
|
||||
|
||||
if ((m_cmd & CMD_DMA) && !(m_cmd & CMD_SBX))
|
||||
{
|
||||
m_cnt--;
|
||||
|
||||
LOGMASKED(LOG_DMA, "xfi_in: %d remaining\n", m_cnt);
|
||||
|
||||
if (!m_cnt)
|
||||
m_aux_status |= AUX_STATUS_TC_ZERO;
|
||||
}
|
||||
|
||||
// clear ACK except after last byte of message input phase
|
||||
if ((m_cnt == 0) && (ctrl & S_PHASE_MASK) == S_PHASE_MSG_IN)
|
||||
{
|
||||
m_int_status |= INT_FUNC_COMPLETE;
|
||||
m_state = IDLE;
|
||||
|
||||
update_int();
|
||||
}
|
||||
else
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
|
||||
}
|
||||
break;
|
||||
|
||||
case XFI_OUT_REQ:
|
||||
if (ctrl & S_REQ)
|
||||
{
|
||||
// TODO: single byte transfer, disconnect
|
||||
if (m_cnt && (ctrl & S_PHASE_MASK) == m_xfi_phase)
|
||||
{
|
||||
m_state = XFI_OUT_DRQ;
|
||||
|
||||
if (m_cmd & CMD_DMA)
|
||||
set_dreq(true);
|
||||
|
||||
delay = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "xfi_out: %s\n", m_cnt ? "phase change" : "transfer complete");
|
||||
m_int_status |= INT_BUS_SERVICE;
|
||||
m_state = IDLE;
|
||||
|
||||
update_int();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XFI_OUT_DRQ:
|
||||
m_state = XFI_OUT_ACK;
|
||||
m_aux_status &= ~AUX_STATUS_DATA_FULL;
|
||||
|
||||
LOGMASKED(LOG_STATE, "xfi_out: data 0x%02x\n", m_dat);
|
||||
|
||||
// assert data and ACK
|
||||
scsi_bus->data_w(scsi_refid, m_dat);
|
||||
if ((m_cnt == 1) && (ctrl & S_PHASE_MASK) == S_PHASE_MSG_OUT)
|
||||
scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK | S_ATN);
|
||||
else
|
||||
scsi_bus->ctrl_w(scsi_refid, S_ACK, S_ACK);
|
||||
break;
|
||||
case XFI_OUT_ACK:
|
||||
if (!(ctrl & S_REQ))
|
||||
{
|
||||
m_state = BIT(m_cmd, 0) ? XFI_OUT_PAD : XFI_OUT_REQ;
|
||||
|
||||
if ((m_cmd & CMD_DMA) && !(m_cmd & CMD_SBX))
|
||||
{
|
||||
m_cnt--;
|
||||
|
||||
LOGMASKED(LOG_DMA, "xfi_out: %d remaining\n", m_cnt);
|
||||
|
||||
if (!m_cnt)
|
||||
m_aux_status |= AUX_STATUS_TC_ZERO;
|
||||
}
|
||||
|
||||
// clear data and ACK
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_ACK);
|
||||
}
|
||||
break;
|
||||
case XFI_OUT_PAD:
|
||||
if (ctrl & S_REQ)
|
||||
{
|
||||
// TODO: single byte transfer, disconnect
|
||||
if (m_cnt && (ctrl & S_PHASE_MASK) == m_xfi_phase)
|
||||
m_state = XFI_OUT_DRQ;
|
||||
else
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "xfi_out: %s\n", m_cnt ? "phase change" : "transfer complete");
|
||||
m_int_status |= INT_BUS_SERVICE;
|
||||
m_state = IDLE;
|
||||
|
||||
update_int();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
void ncr5385_device::set_dreq(bool dreq)
|
||||
{
|
||||
if (m_dreq_state != dreq)
|
||||
{
|
||||
LOGMASKED(LOG_DMA, "set_dreq %d\n", dreq);
|
||||
|
||||
m_dreq_state = dreq;
|
||||
m_dreq(m_dreq_state);
|
||||
}
|
||||
}
|
||||
|
||||
void ncr5385_device::update_int()
|
||||
{
|
||||
bool const int_state = m_int_status & 0x5f;
|
||||
|
||||
if (m_int_state != int_state)
|
||||
{
|
||||
LOG("update_int %d\n", int_state);
|
||||
|
||||
m_aux_status &= ~(AUX_STATUS_MSG | AUX_STATUS_CD | AUX_STATUS_IO);
|
||||
if (int_state)
|
||||
{
|
||||
m_cmd = 0;
|
||||
|
||||
// latch current phase
|
||||
u32 const ctrl = scsi_bus->ctrl_r();
|
||||
if (ctrl & S_MSG)
|
||||
m_aux_status |= AUX_STATUS_MSG;
|
||||
if (ctrl & S_CTL)
|
||||
m_aux_status |= AUX_STATUS_CD;
|
||||
if (ctrl & S_INP)
|
||||
m_aux_status |= AUX_STATUS_IO;
|
||||
}
|
||||
|
||||
m_int_state = int_state;
|
||||
m_int(m_int_state);
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,6 @@
|
||||
|
||||
NCR 5385 SCSI Controller emulation
|
||||
|
||||
TODO:
|
||||
- Everything. Currently, just enough is implemented to make the
|
||||
Philips VP415 CPU / Datagrabber board satisfied that the
|
||||
controller has passed its internal diagnostics.
|
||||
|
||||
************************************************************************
|
||||
_____ _____
|
||||
D2 1 |* \_/ | 48 VCC
|
||||
@ -43,91 +38,87 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "machine/nscsi_bus.h"
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> ncr5385_device
|
||||
|
||||
class ncr5385_device : public device_t
|
||||
class ncr5385_device
|
||||
: public nscsi_device
|
||||
, public nscsi_slot_card_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
ncr5385_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
auto irq() { return m_int.bind(); }
|
||||
auto dreq() { return m_dreq.bind(); }
|
||||
|
||||
void write(offs_t offset, uint8_t data);
|
||||
uint8_t read(offs_t offset);
|
||||
void set_own_id(unsigned id) { m_own_id = id; }
|
||||
|
||||
ncr5385_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||
|
||||
void map(address_map &map);
|
||||
|
||||
u8 dma_r();
|
||||
void dma_w(u8 data);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
// device_t implementation
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
// ncsci_device implementation
|
||||
virtual void scsi_ctrl_changed() override;
|
||||
|
||||
// read handlers
|
||||
u8 dat_r();
|
||||
u8 cmd_r();
|
||||
u8 ctl_r();
|
||||
u8 dst_id_r();
|
||||
u8 aux_status_r();
|
||||
u8 own_id_r();
|
||||
u8 int_status_r();
|
||||
u8 src_id_r();
|
||||
u8 dia_status_r();
|
||||
template <unsigned N> u8 cnt_r();
|
||||
u8 tst_r();
|
||||
|
||||
// write handlers
|
||||
void dat_w(u8 data);
|
||||
void cmd_w(u8 data);
|
||||
void ctl_w(u8 data);
|
||||
void dst_id_w(u8 data);
|
||||
template <unsigned N> void cnt_w(u8 data);
|
||||
void tst_w(u8 data);
|
||||
|
||||
// state machine, interrupts and dma
|
||||
void state_timer(s32 param);
|
||||
int state_step();
|
||||
void update_int();
|
||||
void set_dreq(bool dreq);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
STATE_IDLE,
|
||||
STATE_DIAGNOSTIC_GOOD_PARITY,
|
||||
STATE_DIAGNOSTIC_BAD_PARITY,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DIAG_TURN_MISCOMPARE_INITIAL = 0x08,
|
||||
DIAG_TURN_MISCOMPARE_FINAL = 0x10,
|
||||
DIAG_TURN_GOOD_PARITY = 0x18,
|
||||
DIAG_TURN_BAD_PARITY = 0x20,
|
||||
DIAG_COMPLETE = 0x80,
|
||||
|
||||
DIAG_COMPLETE_BIT = 7,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
INT_FUNC_COMPLETE = 0x01,
|
||||
INT_INVALID_CMD = 0x40,
|
||||
|
||||
INT_FUNC_COMPLETE_BIT = 0,
|
||||
INT_INVALID_CMD_BIT = 6,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
AUX_STATUS_TC_ZERO = 0x02,
|
||||
AUX_STATUS_PAUSED = 0x04,
|
||||
AUX_STATUS_PARITY_ERR = 0x40,
|
||||
AUX_STATUS_DATA_FULL = 0x80,
|
||||
|
||||
AUX_STATUS_TC_ZERO_BIT = 1,
|
||||
AUX_STATUS_PAUSED_BIT = 2,
|
||||
AUX_STATUS_PARITY_ERR_BIT = 6,
|
||||
AUX_STATUS_DATA_FULL_BIT = 7,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CTRL_SELECT = 0x01,
|
||||
CTRL_RESELECT = 0x02,
|
||||
CTRL_PARITY = 0x04,
|
||||
|
||||
CTRL_SELECT_BIT = 0,
|
||||
CTRL_RESELECT_BIT = 1,
|
||||
CTRL_PARITY_BIT = 2,
|
||||
};
|
||||
|
||||
devcb_write_line m_int;
|
||||
devcb_write_line m_dreq;
|
||||
|
||||
uint32_t m_state;
|
||||
uint8_t m_ctrl_reg;
|
||||
uint8_t m_int_reg;
|
||||
uint8_t m_aux_status_reg;
|
||||
uint8_t m_diag_status_reg;
|
||||
emu_timer *m_state_timer;
|
||||
|
||||
// registers
|
||||
u8 m_dat;
|
||||
u8 m_cmd;
|
||||
u8 m_ctl;
|
||||
u8 m_dst_id;
|
||||
u8 m_aux_status;
|
||||
u8 m_own_id;
|
||||
u8 m_int_status;
|
||||
u8 m_src_id;
|
||||
u8 m_dia_status;
|
||||
u32 m_cnt;
|
||||
|
||||
// other state
|
||||
u32 m_state;
|
||||
u8 m_xfi_phase;
|
||||
u8 m_mode;
|
||||
|
||||
bool m_int_state;
|
||||
bool m_dreq_state;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(NCR5385, ncr5385_device)
|
||||
|
||||
#endif // MAME_MACHINE_NCR5385_H
|
||||
|
@ -421,7 +421,7 @@ void vp415_state::z80_program_map(address_map &map)
|
||||
void vp415_state::z80_io_map(address_map &map)
|
||||
{
|
||||
map.global_mask(0xff);
|
||||
map(0x00, 0x0f).rw(SCSI_TAG, FUNC(ncr5385_device::read), FUNC(ncr5385_device::write));
|
||||
map(0x00, 0x0f).m(SCSI_TAG, FUNC(ncr5385_device::map));
|
||||
// 0x20, 0x21: Connected to A0 + D0..D7 of SLAVE i8041
|
||||
map(0x34, 0x34).w(FUNC(vp415_state::sel34_w));
|
||||
map(0x37, 0x37).r(FUNC(vp415_state::sel37_r));
|
||||
|
@ -51,6 +51,8 @@
|
||||
#include "machine/mos6551.h" // debug tty
|
||||
#include "machine/mc146818.h"
|
||||
#include "machine/mc68681.h"
|
||||
#include "machine/nscsi_bus.h"
|
||||
#include "bus/nscsi/hd.h"
|
||||
#include "machine/ncr5385.h"
|
||||
#include "tek410x_kbd.h"
|
||||
#include "sound/sn76496.h"
|
||||
@ -72,6 +74,8 @@ public:
|
||||
m_duart(*this, "duart"),
|
||||
m_keyboard(*this, "keyboard"),
|
||||
m_snsnd(*this, "snsnd"),
|
||||
m_rtc(*this, "rtc"),
|
||||
m_scsi(*this, "scsi:7:ncr5385"),
|
||||
m_prom(*this, "maincpu"),
|
||||
m_mainram(*this, "mainram"),
|
||||
m_vram(*this, "vram"),
|
||||
@ -115,6 +119,8 @@ private:
|
||||
required_device<mc68681_device> m_duart;
|
||||
required_device<tek410x_keyboard_device> m_keyboard;
|
||||
required_device<sn76496_device> m_snsnd;
|
||||
required_device<mc146818_device> m_rtc;
|
||||
required_device<ncr5385_device> m_scsi;
|
||||
required_region_ptr<u16> m_prom;
|
||||
required_shared_ptr<u16> m_mainram;
|
||||
required_shared_ptr<u16> m_vram;
|
||||
@ -326,8 +332,8 @@ void tek440x_state::physical_map(address_map &map)
|
||||
// 7b6000-7b7fff: Mouse
|
||||
map(0x7b8000, 0x7b8003).mirror(0x100).rw("timer", FUNC(am9513_device::read16), FUNC(am9513_device::write16));
|
||||
// 7ba000-7bbfff: MC146818 RTC
|
||||
// 7bc000-7bdfff: SCSI bus address registers
|
||||
map(0x7be000, 0x7be01f).mirror(0x1fe0).rw("scsic", FUNC(ncr5385_device::read), FUNC(ncr5385_device::write)).umask16(0xff00).cswidth(16);
|
||||
map(0x7bc000, 0x7bc000).lw8([this](u8 data) { m_scsi->set_own_id(data & 7); }, "scsi_addr"); // 7bc000-7bdfff: SCSI bus address registers
|
||||
map(0x7be000, 0x7be01f).m(m_scsi, FUNC(ncr5385_device::map)).umask16(0xff00); //.mirror(0x1fe0) .cswidth(16);
|
||||
}
|
||||
|
||||
void tek440x_state::fdccpu_map(address_map &map)
|
||||
@ -351,6 +357,11 @@ INPUT_PORTS_END
|
||||
*
|
||||
*************************************/
|
||||
|
||||
static void scsi_devices(device_slot_interface &device)
|
||||
{
|
||||
device.option_add("harddisk", NSCSI_HARDDISK);
|
||||
}
|
||||
|
||||
void tek440x_state::tek4404(machine_config &config)
|
||||
{
|
||||
/* basic machine hardware */
|
||||
@ -391,9 +402,23 @@ void tek440x_state::tek4404(machine_config &config)
|
||||
|
||||
AM9513(config, "timer", 40_MHz_XTAL / 4 / 10); // from CPU E output
|
||||
|
||||
//MC146818(config, "calendar", 32.768_MHz_XTAL);
|
||||
MC146818(config, m_rtc, 32.768_MHz_XTAL);
|
||||
|
||||
NCR5385(config, "scsic", 40_MHz_XTAL / 4).irq().set_inputline(m_maincpu, M68K_IRQ_3);
|
||||
NSCSI_BUS(config, "scsi");
|
||||
NSCSI_CONNECTOR(config, "scsi:0", scsi_devices, "harddisk");
|
||||
NSCSI_CONNECTOR(config, "scsi:1", scsi_devices, nullptr);
|
||||
NSCSI_CONNECTOR(config, "scsi:2", scsi_devices, nullptr);
|
||||
NSCSI_CONNECTOR(config, "scsi:3", scsi_devices, nullptr);
|
||||
NSCSI_CONNECTOR(config, "scsi:4", scsi_devices, nullptr);
|
||||
NSCSI_CONNECTOR(config, "scsi:5", scsi_devices, nullptr);
|
||||
NSCSI_CONNECTOR(config, "scsi:6", scsi_devices, nullptr);
|
||||
NSCSI_CONNECTOR(config, "scsi:7").option_set("ncr5385", NCR5385).clock(40_MHz_XTAL / 4).machine_config(
|
||||
[this](device_t *device)
|
||||
{
|
||||
ncr5385_device &adapter = downcast<ncr5385_device &>(*device);
|
||||
|
||||
adapter.irq().set_inputline(m_maincpu, M68K_IRQ_3);
|
||||
});
|
||||
|
||||
rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, nullptr));
|
||||
rs232.rxd_handler().set("aica", FUNC(mos6551_device::write_rxd));
|
||||
|
Loading…
Reference in New Issue
Block a user