mirror of
https://github.com/holub/mame
synced 2025-04-20 15:32:45 +03:00
wd33c9x: Fix non-dma data retrieval [O. Galibert]
nscsi_cd: Add the read TOC command, fix inquiry [O. Galibert]
This commit is contained in:
parent
14a623f407
commit
c40a9eb525
@ -3,13 +3,15 @@
|
||||
#include "emu.h"
|
||||
#include "nscsi_bus.h"
|
||||
|
||||
#define LOG_GENERAL (1U << 0)
|
||||
#define LOG_STATE (1U << 1)
|
||||
#define LOG_CONTROL (1U << 2)
|
||||
#define LOG_DATA (1U << 3)
|
||||
#define LOG_GENERAL (1U << 0)
|
||||
#define LOG_UNSUPPORTED (1U << 1)
|
||||
#define LOG_STATE (1U << 2)
|
||||
#define LOG_CONTROL (1U << 3)
|
||||
#define LOG_DATA (1U << 4)
|
||||
#define LOG_DATA_SENT (1U << 5)
|
||||
|
||||
//#define VERBOSE (LOG_GENERAL | LOG_STATE | LOG_CONTROL | LOG_DATA)
|
||||
#define VERBOSE 0
|
||||
#define VERBOSE (LOG_UNSUPPORTED | LOG_DATA_SENT)
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
@ -562,6 +564,17 @@ void nscsi_full_device::scsi_status_complete(uint8_t st)
|
||||
|
||||
void nscsi_full_device::scsi_data_in(int buf, int size)
|
||||
{
|
||||
if(VERBOSE & LOG_DATA_SENT) {
|
||||
std::string dt = "";
|
||||
int sz = size;
|
||||
if(sz > 50)
|
||||
sz = 50;
|
||||
for(int i=0; i<size; i++)
|
||||
dt += util::string_format(" %02x", scsi_cmdbuf[i]);
|
||||
if(size > sz)
|
||||
dt += " ...";
|
||||
LOGMASKED(LOG_DATA_SENT, "Sending data%s\n", dt);
|
||||
}
|
||||
control *c;
|
||||
c = buf_control_push();
|
||||
c->action = BC_DATA_IN;
|
||||
@ -590,10 +603,10 @@ void nscsi_full_device::sense(bool deferred, uint8_t key, uint8_t asc, uint8_t a
|
||||
|
||||
void nscsi_full_device::scsi_unknown_command()
|
||||
{
|
||||
LOG("Unhandled command %s", command_names[scsi_cmdbuf[0]]);
|
||||
std::string txt = util::string_format("Unhandled command %s (%d):", command_names[scsi_cmdbuf[0]], scsi_cmdsize);
|
||||
for(int i=0; i != scsi_cmdsize; i++)
|
||||
logerror(" %02x", scsi_cmdbuf[i]);
|
||||
logerror("\n");
|
||||
txt += util::string_format(" %02x", scsi_cmdbuf[i]);
|
||||
LOGMASKED(LOG_UNSUPPORTED, "%s\n", txt);
|
||||
|
||||
scsi_status_complete(SS_CHECK_CONDITION);
|
||||
sense(false, SK_ILLEGAL_REQUEST);
|
||||
@ -620,10 +633,10 @@ void nscsi_full_device::scsi_message()
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("Unknown message");
|
||||
std::string txt = "Unknown message";
|
||||
for(int i=0; i != scsi_cmdsize; i++)
|
||||
logerror(" %02x", scsi_cmdbuf[i]);
|
||||
logerror("\n");
|
||||
txt += util::string_format(" %02x", scsi_cmdbuf[i]);
|
||||
LOGMASKED(LOG_UNSUPPORTED, "%s\n", txt);
|
||||
}
|
||||
|
||||
int nscsi_full_device::get_lun(int def)
|
||||
|
@ -81,6 +81,15 @@ void nscsi_cdrom_device::device_add_mconfig(machine_config &config)
|
||||
CDROM(config, image).set_interface("cdrom");
|
||||
}
|
||||
|
||||
int nscsi_cdrom_device::to_msf(int frame)
|
||||
{
|
||||
int m = frame / (75 * 60);
|
||||
int s = (frame / 75) % 60;
|
||||
int f = frame % 75;
|
||||
|
||||
return (m << 16) | (s << 8) | f;
|
||||
}
|
||||
|
||||
void nscsi_cdrom_device::set_block_size(u32 block_size)
|
||||
{
|
||||
assert_always(bytes_per_sector % block_size == 0, "block size must be a factor of sector size");
|
||||
@ -216,6 +225,10 @@ void nscsi_cdrom_device::scsi_command()
|
||||
strncpy((char *)&scsi_cmdbuf[8], manufacturer, 8);
|
||||
strncpy((char *)&scsi_cmdbuf[16], product, 16);
|
||||
strncpy((char *)&scsi_cmdbuf[32], revision, 4);
|
||||
for(int i = 8; i < 36; i++)
|
||||
if(scsi_cmdbuf[i] == 0)
|
||||
scsi_cmdbuf[i] = 0x20;
|
||||
|
||||
if(size > 36)
|
||||
size = 36;
|
||||
scsi_data_in(SBUF_MAIN, size);
|
||||
@ -250,7 +263,7 @@ void nscsi_cdrom_device::scsi_command()
|
||||
LOG("command READ CAPACITY\n");
|
||||
|
||||
// get the last used block on the disc
|
||||
const uint32_t temp = cdrom_get_track_start(cdrom, 0xaa) * (bytes_per_sector / bytes_per_block) - 1;
|
||||
const u32 temp = cdrom_get_track_start(cdrom, 0xaa) * (bytes_per_sector / bytes_per_block) - 1;
|
||||
|
||||
scsi_cmdbuf[0] = (temp>>24) & 0xff;
|
||||
scsi_cmdbuf[1] = (temp>>16) & 0xff;
|
||||
@ -267,15 +280,14 @@ void nscsi_cdrom_device::scsi_command()
|
||||
}
|
||||
|
||||
case SC_READ_10:
|
||||
if(!cdrom) {
|
||||
return_no_cd();
|
||||
break;
|
||||
}
|
||||
|
||||
lba = (scsi_cmdbuf[2]<<24) | (scsi_cmdbuf[3]<<16) | (scsi_cmdbuf[4]<<8) | scsi_cmdbuf[5];
|
||||
blocks = (scsi_cmdbuf[7] << 8) | scsi_cmdbuf[8];
|
||||
|
||||
LOG("command READ EXTENDED start=%08x blocks=%04x\n", lba, blocks);
|
||||
if(!cdrom) {
|
||||
return_no_cd();
|
||||
break;
|
||||
}
|
||||
|
||||
scsi_data_in(2, blocks*bytes_per_block);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
@ -297,7 +309,7 @@ void nscsi_cdrom_device::scsi_command()
|
||||
scsi_cmdbuf[pos++] = 0x80; // WP, cache
|
||||
|
||||
// get the last used block on the disc
|
||||
const uint32_t temp = cdrom_get_track_start(cdrom, 0xaa) * (bytes_per_sector / bytes_per_block) - 1;
|
||||
const u32 temp = cdrom_get_track_start(cdrom, 0xaa) * (bytes_per_sector / bytes_per_block) - 1;
|
||||
scsi_cmdbuf[pos++] = 0x08; // Block descriptor length
|
||||
|
||||
scsi_cmdbuf[pos++] = 0x00; // density code
|
||||
@ -359,9 +371,143 @@ void nscsi_cdrom_device::scsi_command()
|
||||
scsi_status_complete(SS_GOOD);
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("unhandled command %02x\n", scsi_cmdbuf[0]);
|
||||
case SC_READ_TOC_PMA_ATIP: {
|
||||
/*
|
||||
Track numbers are problematic here: 0 = lead-in, 0xaa = lead-out.
|
||||
That makes sense in terms of how real-world CDs are referred to, but
|
||||
our internal routines for tracks use "0" as track 1. That probably
|
||||
should be fixed...
|
||||
*/
|
||||
static const char *const format_names[16] = {
|
||||
"TOC",
|
||||
"Session info",
|
||||
"Full TOC",
|
||||
"PMA",
|
||||
"ATIP"
|
||||
"Reserved 5",
|
||||
"Reserved 6",
|
||||
"Reserved 7",
|
||||
"Reserved 8",
|
||||
"Reserved 9",
|
||||
"Reserved 10",
|
||||
"Reserved 11",
|
||||
"Reserved 12",
|
||||
"Reserved 13",
|
||||
"Reserved 14",
|
||||
"Reserved 15"
|
||||
};
|
||||
|
||||
bool msf = (scsi_cmdbuf[1] & 0x2) != 0;
|
||||
u16 size = (scsi_cmdbuf[7] << 7) | scsi_cmdbuf[8];
|
||||
u8 format = scsi_cmdbuf[2] & 15;
|
||||
|
||||
/// SFF8020 legacy format field (see T10/1836-D Revision 2g page 643)
|
||||
if(!format)
|
||||
format = (scsi_cmdbuf[9] >> 6) & 3;
|
||||
|
||||
LOG("command READ TOC PMA ATIP, format %s msf=%d size=%d\n", format_names[format], msf, size);
|
||||
|
||||
int pos = 0;
|
||||
switch (format) {
|
||||
case 0: {
|
||||
int start_track = scsi_cmdbuf[6];
|
||||
int end_track = cdrom_get_last_track(cdrom);
|
||||
|
||||
int tracks;
|
||||
if(start_track == 0)
|
||||
tracks = end_track + 1;
|
||||
else if(start_track <= end_track)
|
||||
tracks = (end_track - start_track) + 2;
|
||||
else if(start_track <= 0xaa)
|
||||
tracks = 1;
|
||||
else
|
||||
tracks = 0;
|
||||
|
||||
int len = 2 + (tracks * 8);
|
||||
|
||||
// the returned TOC DATA LENGTH must be the full amount,
|
||||
// regardless of how much we're able to pass back due to size
|
||||
scsi_cmdbuf[pos++] = (len>>8) & 0xff;
|
||||
scsi_cmdbuf[pos++] = (len & 0xff);
|
||||
scsi_cmdbuf[pos++] = 1;
|
||||
scsi_cmdbuf[pos++] = cdrom_get_last_track(cdrom);
|
||||
|
||||
if (start_track == 0)
|
||||
start_track = 1;
|
||||
|
||||
for(int i = 0; i < tracks; i++) {
|
||||
int track = start_track + i;
|
||||
int cdrom_track = track - 1;
|
||||
if(i == tracks-1) {
|
||||
track = 0xaa;
|
||||
cdrom_track = 0xaa;
|
||||
}
|
||||
|
||||
scsi_cmdbuf[pos++] = 0;
|
||||
scsi_cmdbuf[pos++] = cdrom_get_adr_control(cdrom, cdrom_track);
|
||||
scsi_cmdbuf[pos++] = track;
|
||||
scsi_cmdbuf[pos++] = 0;
|
||||
|
||||
u32 tstart = cdrom_get_track_start(cdrom, cdrom_track);
|
||||
|
||||
if(msf)
|
||||
tstart = to_msf(tstart+150);
|
||||
|
||||
scsi_cmdbuf[pos++] = (tstart>>24) & 0xff;
|
||||
scsi_cmdbuf[pos++] = (tstart>>16) & 0xff;
|
||||
scsi_cmdbuf[pos++] = (tstart>>8) & 0xff;
|
||||
scsi_cmdbuf[pos++] = (tstart & 0xff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
int len = 2 + (8 * 1);
|
||||
|
||||
int pos = 0;
|
||||
scsi_cmdbuf[pos++] = (len>>8) & 0xff;
|
||||
scsi_cmdbuf[pos++] = (len & 0xff);
|
||||
scsi_cmdbuf[pos++] = 1;
|
||||
scsi_cmdbuf[pos++] = 1;
|
||||
|
||||
scsi_cmdbuf[pos++] = 0;
|
||||
scsi_cmdbuf[pos++] = cdrom_get_adr_control(cdrom, 0);
|
||||
scsi_cmdbuf[pos++] = 1;
|
||||
scsi_cmdbuf[pos++] = 0;
|
||||
|
||||
u32 tstart = cdrom_get_track_start(cdrom, 0);
|
||||
|
||||
if (msf)
|
||||
tstart = to_msf(tstart+150);
|
||||
|
||||
scsi_cmdbuf[pos++] = (tstart>>24) & 0xff;
|
||||
scsi_cmdbuf[pos++] = (tstart>>16) & 0xff;
|
||||
scsi_cmdbuf[pos++] = (tstart>>8) & 0xff;
|
||||
scsi_cmdbuf[pos++] = (tstart & 0xff);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG("Unhandled format %d\n", format_names[format]);
|
||||
break;
|
||||
}
|
||||
|
||||
if(pos) {
|
||||
if(pos > size)
|
||||
pos = size;
|
||||
|
||||
scsi_data_in(0, pos);
|
||||
scsi_status_complete(SS_GOOD);
|
||||
} else {
|
||||
// report unit attention condition
|
||||
scsi_status_complete(SS_CHECK_CONDITION);
|
||||
sense(false, SK_ILLEGAL_REQUEST);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
nscsi_full_device::scsi_command();
|
||||
break;
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ private:
|
||||
uint8_t compliance;
|
||||
|
||||
void return_no_cd();
|
||||
static int to_msf(int frame);
|
||||
};
|
||||
|
||||
class nscsi_dec_rrd45_device : public nscsi_cdrom_device
|
||||
|
@ -29,7 +29,7 @@
|
||||
#define LOG_REGS (LOG_READS | LOG_WRITES)
|
||||
#define LOG_ALL (LOG_REGS | LOG_COMMANDS | LOG_ERRORS | LOG_MISC | LOG_LINES | LOG_STATE | LOG_STEP)
|
||||
|
||||
#define VERBOSE (LOG_COMMANDS | LOG_ERRORS | LOG_STATE | LOG_REGS | LOG_STEP)
|
||||
#define VERBOSE (LOG_COMMANDS | LOG_ERRORS)
|
||||
#include "logmacro.h"
|
||||
|
||||
enum register_addresses_e : uint8_t {
|
||||
@ -362,6 +362,7 @@ wd33c9x_base_device::wd33c9x_base_device(const machine_config &mconfig, device_t
|
||||
, m_addr{ 0 }
|
||||
, m_regs{ 0 }
|
||||
, m_command_length{ 0 }
|
||||
, m_last_message{ 0 }
|
||||
, m_scsi_state{ IDLE }
|
||||
, m_mode{ MODE_D }
|
||||
, m_xfr_phase{ 0 }
|
||||
@ -392,6 +393,7 @@ void wd33c9x_base_device::device_start()
|
||||
save_item(NAME(m_addr));
|
||||
save_item(NAME(m_regs));
|
||||
save_item(NAME(m_command_length));
|
||||
save_item(NAME(m_last_message));
|
||||
save_item(NAME(m_mode));
|
||||
save_item(NAME(m_scsi_state));
|
||||
save_item(NAME(m_xfr_phase));
|
||||
@ -420,6 +422,7 @@ void wd33c9x_base_device::device_reset()
|
||||
m_regs[reg] = (QUEUE_TAG <= reg && reg <= INVALID_1E) ? 0xff : 0;
|
||||
}
|
||||
m_command_length = 0;
|
||||
m_last_message = 0;
|
||||
set_scsi_state(IDLE);
|
||||
m_mode = MODE_D;
|
||||
m_xfr_phase = 0;
|
||||
@ -510,7 +513,6 @@ READ8_MEMBER(wd33c9x_base_device::indir_r)
|
||||
|
||||
WRITE8_MEMBER(wd33c9x_base_device::indir_w)
|
||||
{
|
||||
logerror("REG %d %02x\n", offset, data);
|
||||
switch (offset) {
|
||||
case 0:
|
||||
indir_addr_w(space, 0, data, mem_mask);
|
||||
@ -563,7 +565,7 @@ READ8_MEMBER(wd33c9x_base_device::indir_reg_r)
|
||||
|
||||
uint8_t ret;
|
||||
switch (m_addr) {
|
||||
case DATA:
|
||||
case DATA: {
|
||||
if (!(m_regs[AUXILIARY_STATUS] & AUXILIARY_STATUS_DBR)) {
|
||||
// The processor, except in one case, should only
|
||||
// access the Data Register when the DBR bit in the
|
||||
@ -574,10 +576,14 @@ READ8_MEMBER(wd33c9x_base_device::indir_reg_r)
|
||||
// Data Register.
|
||||
fatalerror("%s: The host should never access the data register without DBR set.\n", shortname());
|
||||
}
|
||||
bool was_full = data_fifo_full();
|
||||
ret = data_fifo_pop();
|
||||
logerror("data = %02x\n", ret);
|
||||
m_regs[AUXILIARY_STATUS] &= ~AUXILIARY_STATUS_DBR;
|
||||
if (data_fifo_empty())
|
||||
m_regs[AUXILIARY_STATUS] &= ~AUXILIARY_STATUS_DBR;
|
||||
if (was_full)
|
||||
step(false);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (m_addr == OWN_ID) {
|
||||
@ -592,12 +598,6 @@ READ8_MEMBER(wd33c9x_base_device::indir_reg_r)
|
||||
update_irq();
|
||||
}
|
||||
|
||||
logerror("reg %02x = %02x\n", m_addr, ret);
|
||||
|
||||
if(m_addr == 1) {
|
||||
ret |= 8;
|
||||
machine().debug_break();
|
||||
}
|
||||
// No address increment on accesses to Command, Data, and Auxiliary Status Registers
|
||||
if (m_addr != COMMAND && m_addr != AUXILIARY_STATUS) {
|
||||
m_addr = (m_addr + 1) & REGS_MASK;
|
||||
@ -666,8 +666,6 @@ WRITE8_MEMBER(wd33c9x_base_device::indir_reg_w)
|
||||
else {
|
||||
m_regs[m_addr] = data;
|
||||
}
|
||||
if(m_addr == 1)
|
||||
machine().debug_break();
|
||||
m_addr = (m_addr + 1) & REGS_MASK;
|
||||
break;
|
||||
}
|
||||
@ -908,6 +906,9 @@ void wd33c9x_base_device::step(bool timeout)
|
||||
if (m_regs[CONTROL] & CONTROL_EDI) {
|
||||
set_scsi_state(FINISHED);
|
||||
irq_fifo_push(SCSI_STATUS_SELECT_TRANSFER_SUCCESS);
|
||||
} else {
|
||||
// Makes very little sense, but the previous code did it and warzard seems to need it - XXX
|
||||
m_regs[CONTROL] |= CONTROL_EDI;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -915,8 +916,7 @@ void wd33c9x_base_device::step(bool timeout)
|
||||
fatalerror("%s: Unhandled command phase during Select-and-Transfer disconnect.\n", shortname());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
set_scsi_state(FINISHED);
|
||||
irq_fifo_push(SCSI_STATUS_DISCONNECT);
|
||||
}
|
||||
@ -1103,8 +1103,7 @@ void wd33c9x_base_device::step(bool timeout)
|
||||
break;
|
||||
|
||||
case S_PHASE_MSG_IN:
|
||||
logerror("Got msg %02x\n", data);
|
||||
data_fifo_push(data);
|
||||
m_last_message = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1334,9 +1333,8 @@ void wd33c9x_base_device::step(bool timeout)
|
||||
|
||||
case INIT_XFR_RECV_BYTE_ACK:
|
||||
if (sat && m_xfr_phase == S_PHASE_MSG_IN) {
|
||||
const uint8_t msg = data_fifo_pop();
|
||||
if (m_regs[COMMAND_PHASE] <= COMMAND_PHASE_CP_BYTES_C) {
|
||||
switch (msg) {
|
||||
switch (m_last_message) {
|
||||
case SM_SAVE_DATA_PTR:
|
||||
set_scsi_state(FINISHED);
|
||||
irq_fifo_push(SCSI_STATUS_SAVE_DATA_POINTERS);
|
||||
@ -1348,18 +1346,18 @@ void wd33c9x_base_device::step(bool timeout)
|
||||
break;
|
||||
|
||||
default:
|
||||
fatalerror("%s: Unhandled MSG_IN.\n", shortname());
|
||||
fatalerror("%s: Unhandled MSG_IN %02x.\n", shortname(), m_last_message);
|
||||
break;
|
||||
}
|
||||
} else if (m_regs[COMMAND_PHASE] < COMMAND_PHASE_COMMAND_COMPLETE) {
|
||||
switch (msg) {
|
||||
switch (m_last_message) {
|
||||
case SM_COMMAND_COMPLETE:
|
||||
set_scsi_state(FINISHED);
|
||||
irq_fifo_push(SCSI_STATUS_SELECT_TRANSFER_SUCCESS);
|
||||
m_regs[COMMAND_PHASE] = COMMAND_PHASE_COMMAND_COMPLETE;
|
||||
break;
|
||||
default:
|
||||
fatalerror("%s: Unhandled MSG_IN.\n", shortname());
|
||||
fatalerror("%s: Unhandled MSG_IN %02x.\n", shortname(), m_last_message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ private:
|
||||
uint8_t m_addr;
|
||||
uint8_t m_regs[NUM_REGS];
|
||||
uint8_t m_command_length;
|
||||
uint8_t m_last_message;
|
||||
|
||||
void start_command();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user