diff --git a/src/devices/machine/nscsi_bus.cpp b/src/devices/machine/nscsi_bus.cpp index c408a6a6839..efc89a60f40 100644 --- a/src/devices/machine/nscsi_bus.cpp +++ b/src/devices/machine/nscsi_bus.cpp @@ -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 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) diff --git a/src/devices/machine/nscsi_cd.cpp b/src/devices/machine/nscsi_cd.cpp index 2d45481f740..13cbcca6629 100644 --- a/src/devices/machine/nscsi_cd.cpp +++ b/src/devices/machine/nscsi_cd.cpp @@ -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; } diff --git a/src/devices/machine/nscsi_cd.h b/src/devices/machine/nscsi_cd.h index f3ce871c70a..3a5f67b7170 100644 --- a/src/devices/machine/nscsi_cd.h +++ b/src/devices/machine/nscsi_cd.h @@ -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 diff --git a/src/devices/machine/wd33c9x.cpp b/src/devices/machine/wd33c9x.cpp index 53bb4aba64b..acabe75286e 100644 --- a/src/devices/machine/wd33c9x.cpp +++ b/src/devices/machine/wd33c9x.cpp @@ -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; } } diff --git a/src/devices/machine/wd33c9x.h b/src/devices/machine/wd33c9x.h index bda117dbdc5..f31ca6db607 100644 --- a/src/devices/machine/wd33c9x.h +++ b/src/devices/machine/wd33c9x.h @@ -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();