mirror of
https://github.com/holub/mame
synced 2025-05-25 07:15:25 +03:00
New modern object-oriented bus-signals-available SCSI implementation [O. Galibert]
This commit is contained in:
parent
dba51086f5
commit
d37f1bb316
6
.gitattributes
vendored
6
.gitattributes
vendored
@ -921,6 +921,12 @@ src/emu/machine/ncr539x.c svneol=native#text/plain
|
||||
src/emu/machine/ncr539x.h svneol=native#text/plain
|
||||
src/emu/machine/nmc9306.c svneol=native#text/plain
|
||||
src/emu/machine/nmc9306.h svneol=native#text/plain
|
||||
src/emu/machine/nscsi_bus.c svneol=native#text/plain
|
||||
src/emu/machine/nscsi_bus.h svneol=native#text/plain
|
||||
src/emu/machine/nscsi_cd.c svneol=native#text/plain
|
||||
src/emu/machine/nscsi_cd.h svneol=native#text/plain
|
||||
src/emu/machine/nscsi_hd.c svneol=native#text/plain
|
||||
src/emu/machine/nscsi_hd.h svneol=native#text/plain
|
||||
src/emu/machine/nvram.c svneol=native#text/plain
|
||||
src/emu/machine/nvram.h svneol=native#text/plain
|
||||
src/emu/machine/pc16552d.c svneol=native#text/plain
|
||||
|
@ -220,6 +220,9 @@ EMUMACHINEOBJS = \
|
||||
$(EMUMACHINE)/msm6242.o \
|
||||
$(EMUMACHINE)/ncr539x.o \
|
||||
$(EMUMACHINE)/nmc9306.o \
|
||||
$(EMUMACHINE)/nscsi_bus.o \
|
||||
$(EMUMACHINE)/nscsi_cd.o \
|
||||
$(EMUMACHINE)/nscsi_hd.o \
|
||||
$(EMUMACHINE)/nvram.o \
|
||||
$(EMUMACHINE)/pc16552d.o \
|
||||
$(EMUMACHINE)/pci.o \
|
||||
|
656
src/emu/machine/nscsi_bus.c
Normal file
656
src/emu/machine/nscsi_bus.c
Normal file
@ -0,0 +1,656 @@
|
||||
#include "nscsi_bus.h"
|
||||
|
||||
const device_type NSCSI_BUS = &device_creator<nscsi_bus_device>;
|
||||
const device_type NSCSI_CONNECTOR = &device_creator<nscsi_connector>;
|
||||
|
||||
nscsi_bus_device::nscsi_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
device_t(mconfig, NSCSI_BUS, "SCSI Bus", tag, owner, clock)
|
||||
{
|
||||
devcnt = 0;
|
||||
memset(dev, 0, sizeof(dev));
|
||||
}
|
||||
|
||||
void nscsi_bus_device::device_start()
|
||||
{
|
||||
data = 0;
|
||||
ctrl = 0;
|
||||
}
|
||||
|
||||
void nscsi_bus_device::device_reset()
|
||||
{
|
||||
}
|
||||
|
||||
void nscsi_bus_device::regen_data()
|
||||
{
|
||||
data = 0;
|
||||
for(int i=0; i<devcnt; i++)
|
||||
data |= dev[i].data;
|
||||
}
|
||||
|
||||
void nscsi_bus_device::regen_ctrl(int refid)
|
||||
{
|
||||
static const char *phase[8] = {
|
||||
"dout", "din ", "cmd ", "stat", "4 ", "5 ", "mout", "min "
|
||||
};
|
||||
|
||||
UINT32 octrl = ctrl;
|
||||
ctrl = 0;
|
||||
for(int i=0; i<devcnt; i++)
|
||||
ctrl |= dev[i].ctrl;
|
||||
|
||||
if(0) {
|
||||
logerror("%s: ctrl %c%c%c%c%c%c%c%c%c %s %04x -",
|
||||
tag(),
|
||||
ctrl & nscsi_device::S_RST ? 'R' : '.',
|
||||
ctrl & nscsi_device::S_ATN ? 'A' : '.',
|
||||
ctrl & nscsi_device::S_ACK ? 'K' : '.',
|
||||
ctrl & nscsi_device::S_REQ ? 'Q' : '.',
|
||||
ctrl & nscsi_device::S_SEL ? 'S' : '.',
|
||||
ctrl & nscsi_device::S_BSY ? 'B' : '.',
|
||||
ctrl & nscsi_device::S_MSG ? 'M' : '.',
|
||||
ctrl & nscsi_device::S_CTL ? 'C' : '.',
|
||||
ctrl & nscsi_device::S_INP ? 'I' : '.',
|
||||
phase[ctrl & 7],
|
||||
data);
|
||||
for(int i=0; i<devcnt; i++)
|
||||
if(dev[i].ctrl) {
|
||||
logerror(" %d=", i);
|
||||
logerror("%s%s%s%s%s%s%s%s%s",
|
||||
dev[i].ctrl & nscsi_device::S_RST ? "R" : "",
|
||||
dev[i].ctrl & nscsi_device::S_ATN ? "A" : "",
|
||||
dev[i].ctrl & nscsi_device::S_ACK ? "K" : "",
|
||||
dev[i].ctrl & nscsi_device::S_REQ ? "Q" : "",
|
||||
dev[i].ctrl & nscsi_device::S_MSG ? "M" : "",
|
||||
dev[i].ctrl & nscsi_device::S_INP ? "I" : "",
|
||||
dev[i].ctrl & nscsi_device::S_CTL ? "C" : "",
|
||||
dev[i].ctrl & nscsi_device::S_SEL ? "S" : "",
|
||||
dev[i].ctrl & nscsi_device::S_BSY ? "B" : "");
|
||||
}
|
||||
logerror("\n");
|
||||
}
|
||||
|
||||
octrl = octrl ^ ctrl;
|
||||
if(octrl)
|
||||
for(int i=0; i<devcnt; i++)
|
||||
if(i != refid && (dev[i].wait_ctrl & octrl))
|
||||
dev[i].dev->scsi_ctrl_changed();
|
||||
}
|
||||
|
||||
UINT32 nscsi_bus_device::data_r() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
UINT32 nscsi_bus_device::ctrl_r() const
|
||||
{
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
void nscsi_bus_device::ctrl_w(int refid, UINT32 lines, UINT32 mask)
|
||||
{
|
||||
UINT32 c = dev[refid].ctrl;
|
||||
dev[refid].ctrl = (c & ~mask) | (lines & mask);
|
||||
regen_ctrl(refid);
|
||||
}
|
||||
|
||||
void nscsi_bus_device::data_w(int refid, UINT32 lines)
|
||||
{
|
||||
dev[refid].data = lines;
|
||||
regen_data();
|
||||
}
|
||||
|
||||
void nscsi_bus_device::ctrl_wait(int refid, UINT32 lines, UINT32 mask)
|
||||
{
|
||||
UINT32 w = dev[refid].wait_ctrl;
|
||||
dev[refid].wait_ctrl = (w & ~mask) | (lines & mask);
|
||||
}
|
||||
|
||||
void nscsi_bus_device::device_config_complete()
|
||||
{
|
||||
char id[3];
|
||||
for(int i=0; i<16; i++) {
|
||||
sprintf(id, "%d", i);
|
||||
nscsi_connector *conn = downcast<nscsi_connector *>(subdevice(id));
|
||||
if(conn) {
|
||||
nscsi_device *sdev = conn->get_device();
|
||||
if(sdev) {
|
||||
int rid = devcnt++;
|
||||
dev[rid].dev = sdev;
|
||||
sdev->connect_to_bus(this, rid, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nscsi_connector::nscsi_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
device_t(mconfig, NSCSI_CONNECTOR, "NSCSI device connector abstraction", tag, owner, clock),
|
||||
device_slot_interface(mconfig, *this)
|
||||
{
|
||||
fixed_subtag = 0;
|
||||
}
|
||||
|
||||
nscsi_connector::~nscsi_connector()
|
||||
{
|
||||
}
|
||||
|
||||
void nscsi_connector::device_start()
|
||||
{
|
||||
}
|
||||
|
||||
nscsi_device *nscsi_connector::get_device()
|
||||
{
|
||||
return dynamic_cast<nscsi_device *>(fixed_subtag ? subdevice(fixed_subtag) : get_card_device());
|
||||
}
|
||||
|
||||
void nscsi_connector::set_fixed_device(const char *subtag)
|
||||
{
|
||||
fixed_subtag = subtag;
|
||||
}
|
||||
|
||||
|
||||
nscsi_device::nscsi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
|
||||
device_t(mconfig, type, name, tag, owner, clock),
|
||||
device_slot_card_interface(mconfig, *this)
|
||||
{
|
||||
scsi_id = scsi_refid = -1;
|
||||
scsi_bus = 0;
|
||||
}
|
||||
|
||||
void nscsi_device::connect_to_bus(nscsi_bus_device *bus, int refid, int default_scsi_id)
|
||||
{
|
||||
scsi_bus = bus;
|
||||
scsi_refid = refid;
|
||||
scsi_id = default_scsi_id;
|
||||
}
|
||||
|
||||
void nscsi_device::scsi_ctrl_changed()
|
||||
{
|
||||
}
|
||||
|
||||
nscsi_full_device::nscsi_full_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) :
|
||||
nscsi_device(mconfig, type, name, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
void nscsi_full_device::device_start()
|
||||
{
|
||||
scsi_timer = timer_alloc(SCSI_TIMER);
|
||||
}
|
||||
|
||||
void nscsi_full_device::device_reset()
|
||||
{
|
||||
scsi_state = scsi_substate = IDLE;
|
||||
buf_control_rpos = buf_control_wpos = 0;
|
||||
scsi_identify = 0;
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
|
||||
scsi_bus->ctrl_wait(scsi_refid, S_SEL|S_BSY|S_RST, S_ALL);
|
||||
}
|
||||
|
||||
void nscsi_full_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
if(id != SCSI_TIMER)
|
||||
return;
|
||||
|
||||
step(true);
|
||||
|
||||
}
|
||||
|
||||
void nscsi_full_device::scsi_ctrl_changed()
|
||||
{
|
||||
step(false);
|
||||
}
|
||||
|
||||
void nscsi_full_device::step(bool timeout)
|
||||
{
|
||||
UINT32 ctrl = scsi_bus->ctrl_r();
|
||||
UINT32 data = scsi_bus->data_r();
|
||||
if(ctrl & S_RST) {
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
|
||||
scsi_state = IDLE;
|
||||
logerror("%s: scsi bus reset\n", tag());
|
||||
return;
|
||||
}
|
||||
|
||||
if(0)
|
||||
logerror("%s: state=%d.%d %s\n",
|
||||
tag(), scsi_state & STATE_MASK, (scsi_state & SUB_MASK) >> SUB_SHIFT,
|
||||
timeout ? "timeout" : "change");
|
||||
|
||||
switch(scsi_state & SUB_MASK ? scsi_state & SUB_MASK : scsi_state & STATE_MASK) {
|
||||
case IDLE:
|
||||
if(((ctrl & (S_SEL|S_BSY)) == S_SEL) && (scsi_id != -1) && ((data & (1 << scsi_id)) != 0)) {
|
||||
for(scsi_initiator_id = 0; scsi_initiator_id != 16 && (scsi_initiator_id == scsi_id || (data & (1 << scsi_initiator_id))); scsi_initiator_id++);
|
||||
if(scsi_initiator_id == 16)
|
||||
scsi_initiator_id = -1;
|
||||
scsi_state = TARGET_SELECT_WAIT_BUS_SETTLE;
|
||||
scsi_timer->adjust(scsi_bus_settle_delay());
|
||||
}
|
||||
break;
|
||||
|
||||
case TARGET_SELECT_WAIT_BUS_SETTLE:
|
||||
if((ctrl & (S_SEL|S_BSY)) == S_SEL) {
|
||||
scsi_state = TARGET_SELECT_WAIT_SEL_0;
|
||||
scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY);
|
||||
} else
|
||||
scsi_state = IDLE;
|
||||
break;
|
||||
|
||||
case TARGET_SELECT_WAIT_SEL_0:
|
||||
if(ctrl & S_SEL)
|
||||
break;
|
||||
buf_control_push()->action = BC_MSG_OR_COMMAND;
|
||||
scsi_state = TARGET_NEXT_CONTROL;
|
||||
step(false);
|
||||
break;
|
||||
|
||||
case RECV_BYTE_T_WAIT_ACK_1 << SUB_SHIFT:
|
||||
if(ctrl & S_ACK) {
|
||||
received(scsi_bus->data_r());
|
||||
scsi_state = (scsi_state & STATE_MASK) | (RECV_BYTE_T_WAIT_ACK_0 << SUB_SHIFT);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_REQ);
|
||||
}
|
||||
break;
|
||||
|
||||
case RECV_BYTE_T_WAIT_ACK_0 << SUB_SHIFT:
|
||||
if(!(ctrl & S_ACK)) {
|
||||
scsi_state &= STATE_MASK;
|
||||
scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK);
|
||||
step(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case SEND_BYTE_T_WAIT_ACK_1 << SUB_SHIFT:
|
||||
if(ctrl & S_ACK) {
|
||||
scsi_state = (scsi_state & STATE_MASK) | (SEND_BYTE_T_WAIT_ACK_0 << SUB_SHIFT);
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_REQ);
|
||||
}
|
||||
break;
|
||||
|
||||
case SEND_BYTE_T_WAIT_ACK_0 << SUB_SHIFT:
|
||||
if(!(ctrl & S_ACK)) {
|
||||
scsi_state &= STATE_MASK;
|
||||
scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK);
|
||||
step(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case TARGET_NEXT_CONTROL: {
|
||||
control *ctl = buf_control_pop();
|
||||
switch(ctl->action) {
|
||||
case BC_MSG_OR_COMMAND:
|
||||
if(ctrl & S_ATN) {
|
||||
scsi_state = TARGET_WAIT_MSG_BYTE;
|
||||
scsi_bus->ctrl_w(scsi_refid, S_PHASE_MSG_OUT, S_PHASE_MASK);
|
||||
} else {
|
||||
scsi_state = TARGET_WAIT_CMD_BYTE;
|
||||
scsi_bus->ctrl_w(scsi_refid, S_PHASE_COMMAND, S_PHASE_MASK);
|
||||
}
|
||||
scsi_cmdsize = 0;
|
||||
target_recv_byte();
|
||||
break;
|
||||
|
||||
case BC_STATUS:
|
||||
scsi_bus->ctrl_w(scsi_refid, S_PHASE_STATUS, S_PHASE_MASK);
|
||||
target_send_byte(ctl->param1);
|
||||
break;
|
||||
|
||||
case BC_DATA_IN:
|
||||
scsi_bus->ctrl_w(scsi_refid, S_PHASE_DATA_IN, S_PHASE_MASK);
|
||||
data_buffer_id = ctl->param1;
|
||||
data_buffer_size = ctl->param2;
|
||||
data_buffer_pos = 0;
|
||||
scsi_state = TARGET_WAIT_DATA_IN_BYTE;
|
||||
target_send_buffer_byte();
|
||||
break;
|
||||
|
||||
case BC_MESSAGE_1:
|
||||
scsi_bus->ctrl_w(scsi_refid, S_PHASE_MSG_IN, S_PHASE_MASK);
|
||||
target_send_byte(ctl->param1);
|
||||
break;
|
||||
|
||||
case BC_BUS_FREE:
|
||||
scsi_bus->data_w(scsi_refid, 0);
|
||||
scsi_bus->ctrl_wait(scsi_refid, S_BSY|S_SEL|S_RST, S_ALL);
|
||||
scsi_bus->ctrl_w(scsi_refid, 0, S_ALL);
|
||||
scsi_state = IDLE;
|
||||
break;
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case TARGET_WAIT_DATA_IN_BYTE:
|
||||
if(data_buffer_pos == data_buffer_size-1)
|
||||
scsi_state = TARGET_NEXT_CONTROL;
|
||||
target_send_buffer_byte();
|
||||
break;
|
||||
|
||||
case TARGET_WAIT_MSG_BYTE:
|
||||
if(ctrl & S_SEL)
|
||||
return;
|
||||
if(!(ctrl & S_ATN)) {
|
||||
scsi_message();
|
||||
scsi_cmdsize = 0;
|
||||
scsi_state = TARGET_WAIT_CMD_BYTE;
|
||||
scsi_bus->ctrl_w(scsi_refid, S_PHASE_COMMAND, S_PHASE_MASK);
|
||||
}
|
||||
target_recv_byte();
|
||||
break;
|
||||
|
||||
case TARGET_WAIT_CMD_BYTE:
|
||||
if(ctrl & S_SEL)
|
||||
return;
|
||||
if(ctrl & S_ATN) {
|
||||
logerror("%s: Parity error? Say what?\n", tag());
|
||||
scsi_state = IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
if(command_done()) {
|
||||
scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK);
|
||||
scsi_command();
|
||||
scsi_state = TARGET_NEXT_CONTROL;
|
||||
step(false);
|
||||
} else
|
||||
target_recv_byte();
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("%s: step() unexpected state %d.%d\n",
|
||||
tag(),
|
||||
scsi_state & STATE_MASK, (scsi_state & SUB_MASK) >> SUB_SHIFT);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
void nscsi_full_device::target_recv_byte()
|
||||
{
|
||||
scsi_bus->ctrl_wait(scsi_refid, S_ACK, S_ACK);
|
||||
scsi_state = (scsi_state & STATE_MASK) | (RECV_BYTE_T_WAIT_ACK_1 << SUB_SHIFT);
|
||||
scsi_bus->ctrl_w(scsi_refid, S_REQ, S_REQ);
|
||||
step(false);
|
||||
}
|
||||
|
||||
void nscsi_full_device::target_send_byte(UINT8 val)
|
||||
{
|
||||
scsi_bus->ctrl_wait(scsi_refid, S_ACK, S_ACK);
|
||||
scsi_state = (scsi_state & STATE_MASK) | (SEND_BYTE_T_WAIT_ACK_1 << SUB_SHIFT);
|
||||
scsi_bus->data_w(scsi_refid, val);
|
||||
scsi_bus->ctrl_w(scsi_refid, S_REQ, S_REQ);
|
||||
step(false);
|
||||
}
|
||||
|
||||
void nscsi_full_device::received(UINT8 val)
|
||||
{
|
||||
scsi_cmdbuf[scsi_cmdsize++] = val;
|
||||
}
|
||||
|
||||
UINT8 nscsi_full_device::scsi_get_data(int id, int pos)
|
||||
{
|
||||
switch(id) {
|
||||
case SBUF_MAIN:
|
||||
return scsi_cmdbuf[pos];
|
||||
case SBUF_SENSE:
|
||||
return scsi_sense_buffer[pos];
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void nscsi_full_device::target_send_buffer_byte()
|
||||
{
|
||||
target_send_byte(scsi_get_data(data_buffer_id, data_buffer_pos++));
|
||||
}
|
||||
|
||||
bool nscsi_full_device::command_done()
|
||||
{
|
||||
if(!scsi_cmdsize)
|
||||
return false;
|
||||
UINT8 h = scsi_cmdbuf[0];
|
||||
switch(h >> 5) {
|
||||
case 0: return scsi_cmdsize == 6;
|
||||
case 1: return scsi_cmdsize == 10;
|
||||
case 2: return scsi_cmdsize == 10;
|
||||
case 3: return true;
|
||||
case 4: return true;
|
||||
case 5: return scsi_cmdsize == 12;
|
||||
case 6: return true;
|
||||
case 7: return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nscsi_full_device::control *nscsi_full_device::buf_control_push()
|
||||
{
|
||||
if(buf_control_wpos == int(sizeof(buf_control)/sizeof(buf_control[0])))
|
||||
throw emu_fatalerror("%s: buf_control overflow\n", tag());
|
||||
|
||||
control *c = buf_control + buf_control_wpos;
|
||||
buf_control_wpos++;
|
||||
return c;
|
||||
}
|
||||
|
||||
nscsi_full_device::control *nscsi_full_device::buf_control_pop()
|
||||
{
|
||||
if(buf_control_rpos == buf_control_wpos)
|
||||
throw emu_fatalerror("%s: buf_control underflow\n", tag());
|
||||
|
||||
control *c = buf_control + buf_control_rpos;
|
||||
buf_control_rpos++;
|
||||
if(buf_control_rpos == buf_control_wpos)
|
||||
buf_control_rpos = buf_control_wpos = 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
void nscsi_full_device::scsi_status_complete(UINT8 st)
|
||||
{
|
||||
control *c;
|
||||
c = buf_control_push();
|
||||
c->action = BC_STATUS;
|
||||
c->param1 = st;
|
||||
c = buf_control_push();
|
||||
c->action = BC_MESSAGE_1;
|
||||
c->param1 = SM_COMMAND_COMPLETE;
|
||||
c = buf_control_push();
|
||||
c->action = BC_BUS_FREE;
|
||||
}
|
||||
|
||||
void nscsi_full_device::scsi_data_in(int buf, int size)
|
||||
{
|
||||
control *c;
|
||||
c = buf_control_push();
|
||||
c->action = BC_DATA_IN;
|
||||
c->param1 = buf;
|
||||
c->param2 = size;
|
||||
}
|
||||
|
||||
void nscsi_full_device::scsi_data_out(int buf, int size)
|
||||
{
|
||||
control *c;
|
||||
c = buf_control_push();
|
||||
c->action = BC_DATA_OUT;
|
||||
c->param1 = buf;
|
||||
c->param2 = size;
|
||||
}
|
||||
|
||||
void nscsi_full_device::sense(bool deferred, UINT8 key)
|
||||
{
|
||||
memset(scsi_sense_buffer, 0, sizeof(scsi_sense_buffer));
|
||||
scsi_sense_buffer[0] = deferred ? 0x71 : 0x70;
|
||||
scsi_sense_buffer[2] = key;
|
||||
}
|
||||
|
||||
void nscsi_full_device::scsi_unknown_command()
|
||||
{
|
||||
logerror("%s: Unknown command", tag());
|
||||
for(int i=0; i != scsi_cmdsize; i++)
|
||||
logerror(" %02x", scsi_cmdbuf[i]);
|
||||
logerror("\n");
|
||||
|
||||
scsi_status_complete(SS_CHECK_CONDITION);
|
||||
sense(false, 5);
|
||||
}
|
||||
|
||||
void nscsi_full_device::scsi_command()
|
||||
{
|
||||
switch(scsi_cmdbuf[0]) {
|
||||
case SC_REQUEST_SENSE:
|
||||
logerror("%s: command REQUEST SENSE\n", tag());
|
||||
scsi_data_in(SBUF_SENSE, 8);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
default:
|
||||
scsi_unknown_command();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void nscsi_full_device::scsi_message()
|
||||
{
|
||||
if(scsi_cmdbuf[0] & 0x80) {
|
||||
scsi_identify = scsi_cmdbuf[0];
|
||||
return;
|
||||
}
|
||||
|
||||
logerror("%s: Unknown message", tag());
|
||||
for(int i=0; i != scsi_cmdsize; i++)
|
||||
logerror(" %02x", scsi_cmdbuf[i]);
|
||||
logerror("\n");
|
||||
}
|
||||
|
||||
int nscsi_full_device::get_lun(int def)
|
||||
{
|
||||
if(scsi_identify & 0x80)
|
||||
return scsi_identify & 0x7f;
|
||||
return def;
|
||||
}
|
||||
|
||||
void nscsi_full_device::bad_lun()
|
||||
{
|
||||
scsi_status_complete(SS_CHECK_CONDITION);
|
||||
sense(false, 2);
|
||||
}
|
||||
|
||||
// Arbitration delay (2.4us)
|
||||
attotime nscsi_full_device::scsi_arbitation_delay()
|
||||
{
|
||||
return attotime::from_nsec(2400);
|
||||
}
|
||||
|
||||
// Assertion period (90ns)
|
||||
attotime nscsi_full_device::scsi_assertion_period()
|
||||
{
|
||||
return attotime::from_nsec(90);
|
||||
}
|
||||
|
||||
// Bus clear delay (800ns)
|
||||
attotime nscsi_full_device::scsi_bus_clear_delay()
|
||||
{
|
||||
return attotime::from_nsec(800);
|
||||
}
|
||||
|
||||
// Bus free delay (800ns)
|
||||
attotime nscsi_full_device::scsi_bus_free_delay()
|
||||
{
|
||||
return attotime::from_nsec(800);
|
||||
}
|
||||
|
||||
// Bus set delay (1.8us)
|
||||
attotime nscsi_full_device::scsi_bus_set_delay()
|
||||
{
|
||||
return attotime::from_nsec(1800);
|
||||
}
|
||||
|
||||
// Bus settle delay (400ns)
|
||||
attotime nscsi_full_device::scsi_bus_settle_delay()
|
||||
{
|
||||
return attotime::from_nsec(400);
|
||||
}
|
||||
|
||||
// Cable skew delay (10ns)
|
||||
attotime nscsi_full_device::scsi_cable_skew_delay()
|
||||
{
|
||||
return attotime::from_nsec(10);
|
||||
}
|
||||
|
||||
// Data release delay (400ns)
|
||||
attotime nscsi_full_device::scsi_data_release_delay()
|
||||
{
|
||||
return attotime::from_nsec(40);
|
||||
}
|
||||
|
||||
// Deskew delay (45ns)
|
||||
attotime nscsi_full_device::scsi_deskew_delay()
|
||||
{
|
||||
return attotime::from_nsec(45);
|
||||
}
|
||||
|
||||
// Disconnection delay (200us)
|
||||
attotime nscsi_full_device::scsi_disconnection_delay()
|
||||
{
|
||||
return attotime::from_usec(200);
|
||||
}
|
||||
|
||||
// Hold time (45ns)
|
||||
attotime nscsi_full_device::scsi_hold_time()
|
||||
{
|
||||
return attotime::from_nsec(45);
|
||||
}
|
||||
|
||||
// Negation period (90ns)
|
||||
attotime nscsi_full_device::scsi_negation_period()
|
||||
{
|
||||
return attotime::from_nsec(90);
|
||||
}
|
||||
|
||||
// Reset hold time (25us)
|
||||
attotime nscsi_full_device::scsi_reset_hold_time()
|
||||
{
|
||||
return attotime::from_usec(25);
|
||||
}
|
||||
|
||||
// Selection abort time (200us)
|
||||
attotime nscsi_full_device::scsi_selection_abort_time()
|
||||
{
|
||||
return attotime::from_usec(200);
|
||||
}
|
||||
|
||||
// Selection timeout delay (250ms)
|
||||
attotime nscsi_full_device::scsi_selection_timeout_delay()
|
||||
{
|
||||
return attotime::from_msec(250);
|
||||
}
|
||||
|
||||
// Fast assertion period (30ns)
|
||||
attotime nscsi_full_device::scsi_fast_assertion_period()
|
||||
{
|
||||
return attotime::from_nsec(30);
|
||||
}
|
||||
|
||||
// Fast cable skew delay (5ns)
|
||||
attotime nscsi_full_device::scsi_fast_cable_skew_delay()
|
||||
{
|
||||
return attotime::from_nsec(5);
|
||||
}
|
||||
|
||||
// Fast deskew delay (20ns)
|
||||
attotime nscsi_full_device::scsi_fast_deskew_delay()
|
||||
{
|
||||
return attotime::from_nsec(20);
|
||||
}
|
||||
|
||||
// Fast hold time (10ns)
|
||||
attotime nscsi_full_device::scsi_fast_hold_time()
|
||||
{
|
||||
return attotime::from_nsec(10);
|
||||
}
|
||||
|
||||
// Fast negation period (30ns)
|
||||
attotime nscsi_full_device::scsi_fast_negation_period()
|
||||
{
|
||||
return attotime::from_nsec(30);
|
||||
}
|
||||
|
353
src/emu/machine/nscsi_bus.h
Normal file
353
src/emu/machine/nscsi_bus.h
Normal file
@ -0,0 +1,353 @@
|
||||
#ifndef __NSCSI_BUS_H__
|
||||
#define __NSCSI_BUS_H__
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#define MCFG_NSCSI_BUS_ADD(_tag) \
|
||||
MCFG_DEVICE_ADD(_tag, NSCSI_BUS, 0)
|
||||
|
||||
#define MCFG_NSCSI_DEVICE_ADD(_tag, _subtag, _type, _clock) \
|
||||
MCFG_DEVICE_ADD(_tag, NSCSI_CONNECTOR, 0) \
|
||||
downcast<nscsi_connector *>(device)->set_fixed_device(_subtag); \
|
||||
MCFG_DEVICE_ADD(_tag ":" _subtag, _type, _clock)
|
||||
|
||||
#define MCFG_NSCSI_FULL_DEVICE_ADD(_tag, _subtag, _type, _clock) \
|
||||
MCFG_NSCSI_DEVICE_ADD(_tag, _subtag, _type, _clock)
|
||||
|
||||
#define MCFG_NSCSI_ADD(_tag, _slot_intf, _def_slot, _def_inp) \
|
||||
MCFG_DEVICE_ADD(_tag, NSCSI_CONNECTOR, 0) \
|
||||
MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _def_inp)
|
||||
|
||||
class nscsi_device;
|
||||
|
||||
class nscsi_bus_device : public device_t
|
||||
{
|
||||
public:
|
||||
nscsi_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
void ctrl_w(int refid, UINT32 lines, UINT32 mask);
|
||||
void data_w(int refid, UINT32 lines);
|
||||
void ctrl_wait(int refid, UINT32 lines, UINT32 mask);
|
||||
|
||||
UINT32 ctrl_r() const;
|
||||
UINT32 data_r() const;
|
||||
|
||||
protected:
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
virtual void device_config_complete();
|
||||
|
||||
private:
|
||||
struct dev_t {
|
||||
nscsi_device *dev;
|
||||
UINT32 ctrl, wait_ctrl;
|
||||
UINT32 data;
|
||||
};
|
||||
|
||||
dev_t dev[16];
|
||||
int devcnt;
|
||||
|
||||
UINT32 data, ctrl;
|
||||
|
||||
void regen_data();
|
||||
void regen_ctrl(int refid);
|
||||
};
|
||||
|
||||
class nscsi_connector: public device_t,
|
||||
public device_slot_interface
|
||||
{
|
||||
public:
|
||||
nscsi_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
virtual ~nscsi_connector();
|
||||
|
||||
nscsi_device *get_device();
|
||||
void set_fixed_device(const char *subtag);
|
||||
|
||||
protected:
|
||||
virtual void device_start();
|
||||
|
||||
private:
|
||||
const char *fixed_subtag;
|
||||
};
|
||||
|
||||
class nscsi_device : public device_t,
|
||||
public device_slot_card_interface
|
||||
{
|
||||
public:
|
||||
// Here because the biggest users are the devices, not the bus
|
||||
enum {
|
||||
S_INP = 0x0001,
|
||||
S_CTL = 0x0002,
|
||||
S_MSG = 0x0004,
|
||||
S_BSY = 0x0008,
|
||||
S_SEL = 0x0010,
|
||||
S_REQ = 0x0020,
|
||||
S_ACK = 0x0040,
|
||||
S_ATN = 0x0080,
|
||||
S_RST = 0x0100,
|
||||
S_ALL = 0x01ff,
|
||||
|
||||
S_PHASE_DATA_OUT = 0,
|
||||
S_PHASE_DATA_IN = S_INP,
|
||||
S_PHASE_COMMAND = S_CTL,
|
||||
S_PHASE_STATUS = S_CTL|S_INP,
|
||||
S_PHASE_MSG_OUT = S_MSG|S_CTL,
|
||||
S_PHASE_MSG_IN = S_MSG|S_CTL|S_INP,
|
||||
S_PHASE_MASK = S_MSG|S_CTL|S_INP,
|
||||
};
|
||||
|
||||
nscsi_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
void connect_to_bus(nscsi_bus_device *bus, int refid, int default_scsi_id);
|
||||
virtual void scsi_ctrl_changed();
|
||||
protected:
|
||||
int scsi_id;
|
||||
int scsi_refid;
|
||||
nscsi_bus_device *scsi_bus;
|
||||
};
|
||||
|
||||
class nscsi_full_device : public nscsi_device
|
||||
{
|
||||
public:
|
||||
nscsi_full_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
virtual void scsi_ctrl_changed();
|
||||
protected:
|
||||
enum { SCSI_TIMER = 100 };
|
||||
|
||||
// SCSI status returns
|
||||
enum {
|
||||
SS_GOOD = 0x00,
|
||||
SS_CHECK_CONDITION = 0x02,
|
||||
SS_CONDITION_MET = 0x04,
|
||||
SS_BUSY = 0x08,
|
||||
SS_INT_GOOD = 0x10,
|
||||
SS_INT_CONDITION_MET = 0x14,
|
||||
SS_RESV_CONFLICT = 0x18,
|
||||
SS_TERMINATED = 0x22,
|
||||
SS_QUEUE_FULL = 0x28,
|
||||
};
|
||||
|
||||
// SCSI commands
|
||||
enum {
|
||||
SC_TEST_UNIT_READY = 0x00,
|
||||
SC_REZERO = 0x01,
|
||||
SC_REQUEST_SENSE = 0x03,
|
||||
SC_FORMAT_UNIT = 0x04,
|
||||
SC_REASSIGN_BLOCKS = 0x07,
|
||||
SC_READ = 0x08,
|
||||
SC_WRITE = 0x0a,
|
||||
SC_SEEK = 0x0b,
|
||||
SC_INQUIRY = 0x12,
|
||||
SC_MODE_SELECT_6 = 0x15,
|
||||
SC_RESERVE_6 = 0x16,
|
||||
SC_RELEASE_6 = 0x17,
|
||||
SC_MODE_SENSE_6 = 0x1a,
|
||||
SC_START_STOP_UNIT = 0x1b,
|
||||
SC_RECIEVE_DIAG_RES = 0x1c,
|
||||
SC_SEND_DIAGNOSTICS = 0x1d,
|
||||
SC_READ_CAPACITY = 0x25,
|
||||
SC_READ_EXTENDED = 0x28,
|
||||
SC_WRITE_EXTENDED = 0x2a,
|
||||
SC_SEEK_EXTENDED = 0x2b,
|
||||
SC_WRITE_VERIFY = 0x2e,
|
||||
SC_VERIFY = 0x2f,
|
||||
SC_SYNC_CACHE = 0x35,
|
||||
SC_READ_DEFECT_DATA = 0x37,
|
||||
SC_READ_DATA_BUFFER = 0x3c,
|
||||
SC_READ_LONG = 0x3e,
|
||||
SC_WRITE_LONG = 0x3f,
|
||||
SC_CHANGE_DEFINITION = 0x40,
|
||||
SC_LOG_SELECT = 0x4c,
|
||||
SC_LOG_SENSE = 0x4d,
|
||||
SC_MODE_SELECT_10 = 0x55,
|
||||
SC_RESERVE_10 = 0x56,
|
||||
SC_RELEASE_10 = 0x57,
|
||||
SC_MODE_SENSE_10 = 0x5a,
|
||||
};
|
||||
|
||||
// SCSI Messages
|
||||
enum {
|
||||
SM_COMMAND_COMPLETE = 0x00,
|
||||
SM_EXTENDED_MSG = 0x01,
|
||||
SM_SAVE_DATA_PTR = 0x02,
|
||||
SM_RESTORE_PTR = 0x03,
|
||||
SM_DISCONNECT = 0x04,
|
||||
SM_INITIATOR_ERROR = 0x05,
|
||||
SM_ABORT = 0x06,
|
||||
SM_MSG_REJECT = 0x07,
|
||||
SM_NOP = 0x08,
|
||||
SM_MSG_PARITY = 0x09,
|
||||
SM_LCMD_COMPLETE = 0x0a,
|
||||
SM_LCMD_COMPLETE_F = 0x0b,
|
||||
SM_BUS_DEVICE_RESET = 0x0c,
|
||||
SM_ABORT_TAG = 0x0d,
|
||||
SM_CLEAR_QUEUE = 0x0e,
|
||||
SM_INIT_RECOVERY = 0x0f,
|
||||
SM_RELEASE_RECOVERY = 0x10,
|
||||
SM_TERMINATE_IO = 0x11,
|
||||
SM_SIMPLE_QUEUE = 0x20,
|
||||
SM_HEAD_QUEUE = 0x21,
|
||||
SM_ORDERED_QUEUE = 0x22,
|
||||
SM_IGNORE_WIDE_RES = 0x23,
|
||||
};
|
||||
|
||||
enum {
|
||||
SBUF_MAIN,
|
||||
SBUF_SENSE,
|
||||
};
|
||||
|
||||
UINT8 scsi_cmdbuf[4096], scsi_sense_buffer[8];
|
||||
int scsi_cmdsize;
|
||||
UINT8 scsi_identify;
|
||||
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
|
||||
virtual void scsi_message();
|
||||
virtual void scsi_command();
|
||||
|
||||
void scsi_unknown_command();
|
||||
void scsi_status_complete(UINT8 st);
|
||||
void scsi_data_in(int buf, int size);
|
||||
void scsi_data_out(int buf, int size);
|
||||
|
||||
void sense(bool deferred, UINT8 key);
|
||||
int get_lun(int def = 0);
|
||||
void bad_lun();
|
||||
|
||||
virtual UINT8 scsi_get_data(int buf, int offset);
|
||||
|
||||
// Default delays:
|
||||
|
||||
// Arbitration delay (2.4us)
|
||||
virtual attotime scsi_arbitation_delay();
|
||||
|
||||
// Assertion period (90ns)
|
||||
virtual attotime scsi_assertion_period();
|
||||
|
||||
// Bus clear delay (800ns)
|
||||
virtual attotime scsi_bus_clear_delay();
|
||||
|
||||
// Bus free delay (800ns)
|
||||
virtual attotime scsi_bus_free_delay();
|
||||
|
||||
// Bus set delay (1.8us)
|
||||
virtual attotime scsi_bus_set_delay();
|
||||
|
||||
// Bus settle delay (400ns)
|
||||
virtual attotime scsi_bus_settle_delay();
|
||||
|
||||
// Cable skew delay (10ns)
|
||||
virtual attotime scsi_cable_skew_delay();
|
||||
|
||||
// Data release delay (400ns)
|
||||
virtual attotime scsi_data_release_delay();
|
||||
|
||||
// Deskew delay (45ns)
|
||||
virtual attotime scsi_deskew_delay();
|
||||
|
||||
// Disconnection delay (200us)
|
||||
virtual attotime scsi_disconnection_delay();
|
||||
|
||||
// Hold time (45ns)
|
||||
virtual attotime scsi_hold_time();
|
||||
|
||||
// Negation period (90ns)
|
||||
virtual attotime scsi_negation_period();
|
||||
|
||||
// Reset hold time (25us)
|
||||
virtual attotime scsi_reset_hold_time();
|
||||
|
||||
// Selection abort time (200us)
|
||||
virtual attotime scsi_selection_abort_time();
|
||||
|
||||
// Selection timeout delay (250ms)
|
||||
virtual attotime scsi_selection_timeout_delay();
|
||||
|
||||
// Fast assertion period (30ns)
|
||||
virtual attotime scsi_fast_assertion_period();
|
||||
|
||||
// Fast cable skew delay (5ns)
|
||||
virtual attotime scsi_fast_cable_skew_delay();
|
||||
|
||||
// Fast deskew delay (20ns)
|
||||
virtual attotime scsi_fast_deskew_delay();
|
||||
|
||||
// Fast hold time (10ns)
|
||||
virtual attotime scsi_fast_hold_time();
|
||||
|
||||
// Fast negation period (30ns)
|
||||
virtual attotime scsi_fast_negation_period();
|
||||
|
||||
private:
|
||||
enum {
|
||||
IDLE,
|
||||
};
|
||||
|
||||
enum {
|
||||
TARGET_SELECT_WAIT_BUS_SETTLE = 1,
|
||||
TARGET_SELECT_WAIT_SEL_0,
|
||||
|
||||
TARGET_NEXT_CONTROL,
|
||||
TARGET_WAIT_MSG_BYTE,
|
||||
TARGET_WAIT_CMD_BYTE,
|
||||
TARGET_WAIT_DATA_IN_BYTE,
|
||||
};
|
||||
|
||||
enum {
|
||||
RECV_BYTE_T_WAIT_ACK_0 = 1,
|
||||
RECV_BYTE_T_WAIT_ACK_1,
|
||||
SEND_BYTE_T_WAIT_ACK_0,
|
||||
SEND_BYTE_T_WAIT_ACK_1,
|
||||
};
|
||||
|
||||
enum {
|
||||
STATE_MASK = 0x00ff,
|
||||
SUB_SHIFT = 8,
|
||||
SUB_MASK = 0xff00,
|
||||
};
|
||||
|
||||
enum {
|
||||
BC_MSG_OR_COMMAND,
|
||||
BC_STATUS,
|
||||
BC_MESSAGE_1,
|
||||
BC_MESSAGE_2,
|
||||
BC_DATA_IN,
|
||||
BC_DATA_OUT,
|
||||
BC_BUS_FREE,
|
||||
};
|
||||
|
||||
struct control {
|
||||
int action;
|
||||
int param1, param2;
|
||||
};
|
||||
|
||||
emu_timer *scsi_timer;
|
||||
|
||||
int scsi_state, scsi_substate;
|
||||
int scsi_initiator_id;
|
||||
int data_buffer_id, data_buffer_size, data_buffer_pos;
|
||||
|
||||
control buf_control[32];
|
||||
int buf_control_rpos;
|
||||
int buf_control_wpos;
|
||||
|
||||
control *buf_control_push();
|
||||
control *buf_control_pop();
|
||||
|
||||
void step(bool timeout);
|
||||
void target_recv_byte();
|
||||
void target_send_byte(UINT8 val);
|
||||
void received(UINT8 val);
|
||||
void target_send_buffer_byte();
|
||||
bool command_done();
|
||||
};
|
||||
|
||||
|
||||
extern const device_type NSCSI_BUS;
|
||||
extern const device_type NSCSI_CONNECTOR;
|
||||
|
||||
#endif
|
||||
|
146
src/emu/machine/nscsi_cd.c
Normal file
146
src/emu/machine/nscsi_cd.c
Normal file
@ -0,0 +1,146 @@
|
||||
#include "machine/nscsi_cd.h"
|
||||
#include "imagedev/chd_cd.h"
|
||||
|
||||
const device_type NSCSI_CDROM = &device_creator<nscsi_cdrom_device>;
|
||||
|
||||
nscsi_cdrom_device::nscsi_cdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
nscsi_full_device(mconfig, NSCSI_CDROM, "SCSI CDROM", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
void nscsi_cdrom_device::device_start()
|
||||
{
|
||||
nscsi_full_device::device_start();
|
||||
bytes_per_sector = 2048;
|
||||
}
|
||||
|
||||
void nscsi_cdrom_device::device_reset()
|
||||
{
|
||||
nscsi_full_device::device_reset();
|
||||
cdrom = subdevice<cdrom_image_device>("image")->get_cdrom_file();
|
||||
lba = 0;
|
||||
blocks = 0;
|
||||
cur_lba = -1;
|
||||
}
|
||||
|
||||
cdrom_interface nscsi_cdrom_device::cd_intf = { 0, 0 };
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT(scsi_cdrom)
|
||||
MCFG_CDROM_ADD("image", nscsi_cdrom_device::cd_intf)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
machine_config_constructor nscsi_cdrom_device::device_mconfig_additions() const
|
||||
{
|
||||
return MACHINE_CONFIG_NAME(scsi_cdrom);
|
||||
}
|
||||
|
||||
UINT8 nscsi_cdrom_device::scsi_get_data(int id, int pos)
|
||||
{
|
||||
if(id != 2)
|
||||
return nscsi_full_device::scsi_get_data(id, pos);
|
||||
int clba = lba + pos / bytes_per_sector;
|
||||
if(clba != cur_lba) {
|
||||
cur_lba = clba;
|
||||
if(!cdrom_read_data(cdrom, cur_lba, block, CD_TRACK_MODE1)) {
|
||||
logerror("%s: CD READ ERROR !\n", tag());
|
||||
memset(block, 0, sizeof(block));
|
||||
}
|
||||
}
|
||||
return block[pos & (bytes_per_sector - 1)];
|
||||
}
|
||||
|
||||
void nscsi_cdrom_device::scsi_command()
|
||||
{
|
||||
switch(scsi_cmdbuf[0]) {
|
||||
case SC_TEST_UNIT_READY:
|
||||
logerror("%s: command TEST UNIT READY\n", tag());
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
case SC_READ:
|
||||
lba = ((scsi_cmdbuf[1] & 0x1f)<<16) | (scsi_cmdbuf[2]<<8) | scsi_cmdbuf[3];
|
||||
blocks = scsi_cmdbuf[4];
|
||||
if(!blocks)
|
||||
blocks = 256;
|
||||
|
||||
logerror("%s: command READ start=%08x blocks=%04x\n",
|
||||
tag(), lba, blocks);
|
||||
|
||||
scsi_data_in(2, blocks*bytes_per_sector);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
case SC_INQUIRY: {
|
||||
int lun = get_lun(scsi_cmdbuf[1] >> 5);
|
||||
logerror("%s: command INQUIRY lun=%d EVPD=%d page=%d alloc=%02x link=%02x\n",
|
||||
tag(),
|
||||
lun, scsi_cmdbuf[1] & 1, scsi_cmdbuf[2], scsi_cmdbuf[4], scsi_cmdbuf[5]);
|
||||
if(lun) {
|
||||
bad_lun();
|
||||
return;
|
||||
}
|
||||
|
||||
int page = scsi_cmdbuf[2];
|
||||
int size = scsi_cmdbuf[4];
|
||||
switch(page) {
|
||||
case 0:
|
||||
memset(scsi_cmdbuf, 0, 148);
|
||||
scsi_cmdbuf[0] = 0x05; // device is present, device is CD/DVD (MMC-3)
|
||||
scsi_cmdbuf[1] = 0x80; // media is removable
|
||||
scsi_cmdbuf[2] = 0x05; // device complies with SPC-3 standard
|
||||
scsi_cmdbuf[3] = 0x02; // response data format = SPC-3 standard
|
||||
// some Konami games freak out if this isn't "Sony", so we'll lie
|
||||
// this is the actual drive on my Nagano '98 board
|
||||
strcpy((char *)&scsi_cmdbuf[8], "Sony");
|
||||
strcpy((char *)&scsi_cmdbuf[16], "CDU-76S");
|
||||
strcpy((char *)&scsi_cmdbuf[32], "1.0");
|
||||
if(size > 148)
|
||||
size = 148;
|
||||
scsi_data_in(SBUF_MAIN, size);
|
||||
break;
|
||||
}
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
}
|
||||
|
||||
case SC_START_STOP_UNIT:
|
||||
logerror("%s: command START STOP UNIT\n", tag());
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
case SC_READ_CAPACITY: {
|
||||
logerror("%s: command READ CAPACITY\n", tag());
|
||||
|
||||
UINT32 temp = cdrom_get_track_start(cdrom, 0xaa);
|
||||
temp--; // return the last used block on the disc
|
||||
|
||||
scsi_cmdbuf[0] = (temp>>24) & 0xff;
|
||||
scsi_cmdbuf[1] = (temp>>16) & 0xff;
|
||||
scsi_cmdbuf[2] = (temp>>8) & 0xff;
|
||||
scsi_cmdbuf[3] = (temp & 0xff);
|
||||
scsi_cmdbuf[4] = 0;
|
||||
scsi_cmdbuf[5] = 0;
|
||||
scsi_cmdbuf[6] = (bytes_per_sector>>8)&0xff;
|
||||
scsi_cmdbuf[7] = (bytes_per_sector & 0xff);
|
||||
|
||||
scsi_data_in(SBUF_MAIN, 8);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
}
|
||||
|
||||
case SC_READ_EXTENDED:
|
||||
lba = (scsi_cmdbuf[2]<<24) | (scsi_cmdbuf[3]<<16) | (scsi_cmdbuf[4]<<8) | scsi_cmdbuf[5];
|
||||
blocks = (scsi_cmdbuf[7] << 8) | scsi_cmdbuf[8];
|
||||
|
||||
logerror("%s: command READ EXTENDED start=%08x blocks=%04x\n",
|
||||
tag(), lba, blocks);
|
||||
|
||||
scsi_data_in(2, blocks*bytes_per_sector);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
default:
|
||||
nscsi_full_device::scsi_command();
|
||||
break;
|
||||
}
|
||||
}
|
34
src/emu/machine/nscsi_cd.h
Normal file
34
src/emu/machine/nscsi_cd.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef __NSCSI_CD_H__
|
||||
#define __NSCSI_CD_H__
|
||||
|
||||
#include "machine/nscsi_bus.h"
|
||||
#include "cdrom.h"
|
||||
|
||||
#define MCFG_NSCSI_CDROM_ADD(_tag, _subtag) \
|
||||
MCFG_NSCSI_FULL_DEVICE_ADD(_tag, _subtag, NSCSI_CDROM, 0)
|
||||
|
||||
class nscsi_cdrom_device : public nscsi_full_device
|
||||
{
|
||||
public:
|
||||
nscsi_cdrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
virtual machine_config_constructor device_mconfig_additions() const;
|
||||
|
||||
static struct cdrom_interface cd_intf;
|
||||
|
||||
protected:
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
virtual void scsi_command();
|
||||
virtual UINT8 scsi_get_data(int id, int pos);
|
||||
|
||||
private:
|
||||
UINT8 block[2048];
|
||||
cdrom_file *cdrom;
|
||||
int bytes_per_sector;
|
||||
int lba, cur_lba, blocks;
|
||||
};
|
||||
|
||||
extern const device_type NSCSI_CDROM;
|
||||
|
||||
#endif
|
155
src/emu/machine/nscsi_hd.c
Normal file
155
src/emu/machine/nscsi_hd.c
Normal file
@ -0,0 +1,155 @@
|
||||
#include "machine/nscsi_hd.h"
|
||||
#include "imagedev/harddriv.h"
|
||||
|
||||
const device_type NSCSI_HARDDISK = &device_creator<nscsi_harddisk_device>;
|
||||
|
||||
nscsi_harddisk_device::nscsi_harddisk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
nscsi_full_device(mconfig, NSCSI_HARDDISK, "SCSI HARDDISK", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
void nscsi_harddisk_device::device_start()
|
||||
{
|
||||
nscsi_full_device::device_start();
|
||||
}
|
||||
|
||||
void nscsi_harddisk_device::device_reset()
|
||||
{
|
||||
nscsi_full_device::device_reset();
|
||||
harddisk_image_device *hd = subdevice<harddisk_image_device>("image");
|
||||
harddisk = hd->get_hard_disk_file();
|
||||
if(!harddisk) {
|
||||
scsi_id = -1;
|
||||
bytes_per_sector = 0;
|
||||
} else {
|
||||
const hard_disk_info *hdinfo = hard_disk_get_info(harddisk);
|
||||
bytes_per_sector = hdinfo->sectorbytes;
|
||||
}
|
||||
}
|
||||
|
||||
harddisk_interface nscsi_harddisk_device::hd_intf = { 0, 0 };
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT(scsi_harddisk)
|
||||
MCFG_HARDDISK_CONFIG_ADD("image", nscsi_harddisk_device::hd_intf)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
machine_config_constructor nscsi_harddisk_device::device_mconfig_additions() const
|
||||
{
|
||||
return MACHINE_CONFIG_NAME(scsi_harddisk);
|
||||
}
|
||||
|
||||
UINT8 nscsi_harddisk_device::scsi_get_data(int id, int pos)
|
||||
{
|
||||
if(id != 2)
|
||||
return nscsi_full_device::scsi_get_data(id, pos);
|
||||
int clba = lba + pos / bytes_per_sector;
|
||||
if(clba != cur_lba) {
|
||||
cur_lba = clba;
|
||||
if(!hard_disk_read(harddisk, cur_lba, block)) {
|
||||
logerror("%s: HD READ ERROR !\n", tag());
|
||||
memset(block, 0, sizeof(block));
|
||||
}
|
||||
}
|
||||
return block[pos & (bytes_per_sector - 1)];
|
||||
}
|
||||
|
||||
void nscsi_harddisk_device::scsi_command()
|
||||
{
|
||||
switch(scsi_cmdbuf[0]) {
|
||||
case SC_TEST_UNIT_READY:
|
||||
logerror("%s: command TEST UNIT READY\n", tag());
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
case SC_READ:
|
||||
lba = ((scsi_cmdbuf[1] & 0x1f)<<16) | (scsi_cmdbuf[2]<<8) | scsi_cmdbuf[3];
|
||||
blocks = scsi_cmdbuf[4];
|
||||
if(!blocks)
|
||||
blocks = 256;
|
||||
|
||||
logerror("%s: command READ start=%08x blocks=%04x\n",
|
||||
tag(), lba, blocks);
|
||||
|
||||
scsi_data_in(2, blocks*bytes_per_sector);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
case SC_INQUIRY: {
|
||||
int lun = get_lun(scsi_cmdbuf[1] >> 5);
|
||||
logerror("%s: INQUIRY lun=%d EVPD=%d page=%d alloc=%02x link=%02x\n",
|
||||
tag(),
|
||||
lun, scsi_cmdbuf[1] & 1, scsi_cmdbuf[2], scsi_cmdbuf[4], scsi_cmdbuf[5]);
|
||||
if(lun) {
|
||||
bad_lun();
|
||||
return;
|
||||
}
|
||||
|
||||
int page = scsi_cmdbuf[2];
|
||||
int size = scsi_cmdbuf[4];
|
||||
switch(page) {
|
||||
case 0:
|
||||
memset(scsi_cmdbuf, 0, 148);
|
||||
scsi_cmdbuf[0] = 0x00; // device is direct-access (e.g. hard disk)
|
||||
scsi_cmdbuf[1] = 0x00; // media is not removable
|
||||
scsi_cmdbuf[2] = 0x05; // device complies with SPC-3 standard
|
||||
scsi_cmdbuf[3] = 0x02; // response data format = SPC-3 standard
|
||||
// Apple HD SC setup utility needs to see this
|
||||
strcpy((char *)&scsi_cmdbuf[8], " SEAGATE");
|
||||
strcpy((char *)&scsi_cmdbuf[16], " ST225N");
|
||||
strcpy((char *)&scsi_cmdbuf[32], "1.0");
|
||||
if(size > 148)
|
||||
size = 148;
|
||||
scsi_data_in(0, size);
|
||||
break;
|
||||
}
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
}
|
||||
|
||||
case SC_START_STOP_UNIT:
|
||||
logerror("%s: command START STOP UNIT\n", tag());
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
case SC_READ_CAPACITY: {
|
||||
logerror("%s: command READ CAPACITY\n", tag());
|
||||
|
||||
hard_disk_info *info;
|
||||
UINT32 temp;
|
||||
|
||||
info = hard_disk_get_info(harddisk);
|
||||
|
||||
// get # of sectors
|
||||
temp = info->cylinders * info->heads * info->sectors;
|
||||
temp--;
|
||||
|
||||
scsi_cmdbuf[0] = (temp>>24) & 0xff;
|
||||
scsi_cmdbuf[1] = (temp>>16) & 0xff;
|
||||
scsi_cmdbuf[2] = (temp>>8) & 0xff;
|
||||
scsi_cmdbuf[3] = (temp & 0xff);
|
||||
scsi_cmdbuf[4] = (info->sectorbytes>>24)&0xff;
|
||||
scsi_cmdbuf[5] = (info->sectorbytes>>16)&0xff;
|
||||
scsi_cmdbuf[6] = (info->sectorbytes>>8)&0xff;
|
||||
scsi_cmdbuf[7] = (info->sectorbytes & 0xff);
|
||||
|
||||
scsi_data_in(0, 8);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
}
|
||||
|
||||
case SC_READ_EXTENDED:
|
||||
lba = (scsi_cmdbuf[2]<<24) | (scsi_cmdbuf[3]<<16) | (scsi_cmdbuf[4]<<8) | scsi_cmdbuf[5];
|
||||
blocks = (scsi_cmdbuf[7] << 8) | scsi_cmdbuf[8];
|
||||
|
||||
logerror("%s: command READ EXTENDED start=%08x blocks=%04x\n",
|
||||
tag(), lba, blocks);
|
||||
|
||||
scsi_data_in(2, blocks*bytes_per_sector);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
default:
|
||||
nscsi_full_device::scsi_command();
|
||||
break;
|
||||
}
|
||||
}
|
34
src/emu/machine/nscsi_hd.h
Normal file
34
src/emu/machine/nscsi_hd.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef __NSCSI_HD_H__
|
||||
#define __NSCSI_HD_H__
|
||||
|
||||
#include "machine/nscsi_bus.h"
|
||||
#include "harddisk.h"
|
||||
|
||||
#define MCFG_NSCSI_HARDDISK_ADD(_tag, _subtag) \
|
||||
MCFG_NSCSI_FULL_DEVICE_ADD(_tag, _subtag, NSCSI_HARDDISK, 0)
|
||||
|
||||
class nscsi_harddisk_device : public nscsi_full_device
|
||||
{
|
||||
public:
|
||||
nscsi_harddisk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
virtual machine_config_constructor device_mconfig_additions() const;
|
||||
|
||||
static struct harddisk_interface hd_intf;
|
||||
protected:
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
virtual void scsi_command();
|
||||
virtual UINT8 scsi_get_data(int id, int pos);
|
||||
|
||||
private:
|
||||
UINT8 block[512];
|
||||
hard_disk_file *harddisk;
|
||||
int lba, cur_lba, blocks;
|
||||
int bytes_per_sector;
|
||||
};
|
||||
|
||||
extern const device_type NSCSI_HARDDISK;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user