-t10sbc.cpp: Added support for Format Parameters and Geometry Parameters pages. [Ryan Holtz]

-hpc3.cpp: Added support for single-byte SCSI DRQ functionality. [Ryan Holtz]
This commit is contained in:
mooglyguy 2018-11-10 21:23:54 +01:00
parent 9a06a7d23a
commit 9a5a4d491f
5 changed files with 462 additions and 178 deletions

View File

@ -163,22 +163,119 @@ void t10sbc::ReadData( uint8_t *data, int dataLength )
break;
case T10SPC_CMD_MODE_SENSE_6:
{
const uint8_t page = command[2] & 0x3f;
const uint8_t subpage = command[3];
switch (page)
{
case 0x03:
{
// Format Parameters
if (subpage != 0)
{
m_device->logerror("T10SBC: Unsupported MODE SENSE subpage for Format Parameters page: %02x\n", subpage);
break;
}
const size_t fullSize = sizeof(format_page_t) + 12;
if (dataLength < fullSize)
{
m_device->logerror("T10SBC: Insufficient MODE SENSE buffer room for Format Parameters page: Need %d, given %d\n", fullSize, dataLength);
break;
}
m_device->logerror("T10SBC: MODE SENSE (6), Format Parameters page\n");
memset(data, 0, (uint8_t)fullSize);
data[0] = fullSize;
data[3] = 8;
ReadCapacity(&data[4]);
format_page_t format;
GetFormatPage(&format);
memcpy(&data[12], &format, sizeof(format_page_t));
break;
}
case 0x04:
{
// Rigid Drive Geometry Parameters
if (subpage != 0)
{
m_device->logerror("T10SBC: Unsupported MODE SENSE subpage for Geometry Parameters page: %02x\n", subpage);
break;
}
const size_t fullSize = sizeof(geometry_page_t) + 12;
if (dataLength < fullSize)
{
m_device->logerror("T10SBC: Insufficient MODE SENSE buffer room for Geometry Parameters page: Need %d, given %d\n", fullSize, dataLength);
break;
}
m_device->logerror("T10SBC: MODE SENSE (6), Geometry Parameters page\n");
memset(data, 0, fullSize);
data[0] = (uint8_t)fullSize;
data[3] = 8;
ReadCapacity(&data[4]);
geometry_page_t geometry;
GetGeometryPage(&geometry);
memcpy(&data[12], &geometry, sizeof(geometry_page_t));
break;
}
case 0x30:
// special Apple ID page. this is a vendor-specific page,
// so unless collisions occur there should be no need
// to change it.
if ((command[2] & 0x3f) == 0x30)
{
memset(data, 0, 40);
data[0] = 0x14;
strcpy((char *)&data[14], "APPLE COMPUTER, INC.");
break;
case 0x3f:
if (subpage == 0)
{
const size_t fullSize = sizeof(format_page_t) + sizeof(geometry_page_t) + 12;
if (dataLength < fullSize)
{
m_device->logerror("T10SBC: Insufficient MODE SENSE buffer room for Return All Pages: Need %d, given %d\n", fullSize, dataLength);
break;
}
m_device->logerror("T10SBC: MODE SENSE (6), Return All Pages\n");
memset(data, 0, (uint8_t)fullSize);
data[0] = (uint8_t)fullSize;
data[3] = (uint8_t)8;
ReadCapacity(&data[4]);
format_page_t format;
GetFormatPage(&format);
memcpy(&data[12], &format, sizeof(format_page_t));
geometry_page_t geometry;
GetGeometryPage(&geometry);
memcpy(&data[12 + sizeof(format_page_t)], &geometry, sizeof(geometry_page_t));
}
else
{
m_device->logerror("T10SBC: Unsupported MODE SENSE subpage for Return All Pages: %02x\n", subpage);
}
break;
default:
m_device->logerror("T10SBC: Unknown MODE SENSE page: %02x\n", page);
break;
}
break;
}
case T10SBC_CMD_READ_6:
case T10SBC_CMD_READ_10:
case T10SBC_CMD_READ_12:
if ((m_disk) && (m_blocks))
{
m_device->logerror("T10SBC: Reading %d bytes from HD\n", dataLength);
while (dataLength > 0)
{
if (!hard_disk_read(m_disk, m_lba, data))
@ -194,27 +291,8 @@ void t10sbc::ReadData( uint8_t *data, int dataLength )
break;
case T10SBC_CMD_READ_CAPACITY: // READ CAPACITY
{
hard_disk_info *info;
uint32_t temp;
info = hard_disk_get_info(m_disk);
m_device->logerror("T10SBC: READ CAPACITY\n");
// get # of sectors
temp = info->cylinders * info->heads * info->sectors;
temp--;
data[0] = (temp>>24) & 0xff;
data[1] = (temp>>16) & 0xff;
data[2] = (temp>>8) & 0xff;
data[3] = (temp & 0xff);
data[4] = (info->sectorbytes>>24)&0xff;
data[5] = (info->sectorbytes>>16)&0xff;
data[6] = (info->sectorbytes>>8)&0xff;
data[7] = (info->sectorbytes & 0xff);
}
ReadCapacity(&data[0]);
break;
default:
@ -239,6 +317,7 @@ void t10sbc::WriteData( uint8_t *data, int dataLength )
case T10SBC_CMD_WRITE_10:
if ((m_disk) && (m_blocks))
{
m_device->logerror("T10SBC: Writing %d bytes to HD\n", dataLength);
while (dataLength > 0)
{
if (!hard_disk_write(m_disk, m_lba, data))
@ -268,3 +347,49 @@ void t10sbc::SetDevice( void *_disk )
{
m_disk = (hard_disk_file *)_disk;
}
void t10sbc::GetFormatPage( format_page_t *page )
{
hard_disk_info *info = hard_disk_get_info(m_disk);
memset(page, 0, sizeof(format_page_t));
page->m_page_code = 0x03;
page->m_page_length = 0x16;
page->m_sectors_per_track_msb = (uint8_t)(info->sectors >> 8);
page->m_sectors_per_track_lsb = (uint8_t)info->sectors;
page->m_bytes_per_sector_msb = (uint8_t)(info->sectorbytes >> 8);
page->m_bytes_per_sector_lsb = (uint8_t)info->sectorbytes;
page->m_format = 0x80; // SSEC, Soft-Sectored
}
void t10sbc::GetGeometryPage( geometry_page_t *page )
{
hard_disk_info *info = hard_disk_get_info(m_disk);
memset(page, 0, sizeof(geometry_page_t));
page->m_page_code = 0x04;
page->m_page_length = 0x16;
page->m_num_cylinders_msb = (uint8_t)(info->cylinders >> 16);
page->m_num_cylinders_2nd = (uint8_t)(info->cylinders >> 8);
page->m_num_cylinders_lsb = (uint8_t)info->cylinders;
page->m_num_heads = (uint8_t)info->heads;
page->m_rot_rate_msb = (uint8_t)(3600 >> 8);
page->m_rot_rate_lsb = (uint8_t)3600;
}
void t10sbc::ReadCapacity( uint8_t *data )
{
hard_disk_info *info = hard_disk_get_info(m_disk);
// get # of sectors
uint32_t temp = info->cylinders * info->heads * info->sectors - 1;
data[0] = (temp>>24) & 0xff;
data[1] = (temp>>16) & 0xff;
data[2] = (temp>>8) & 0xff;
data[3] = (temp & 0xff);
data[4] = (info->sectorbytes>>24)&0xff;
data[5] = (info->sectorbytes>>16)&0xff;
data[6] = (info->sectorbytes>>8)&0xff;
data[7] = (info->sectorbytes & 0xff);
}

View File

@ -32,6 +32,63 @@ protected:
virtual void t10_start(device_t &device) override;
virtual void t10_reset() override;
struct format_page_t
{
uint8_t m_page_code;
uint8_t m_page_length;
uint8_t m_tracks_per_zone_msb;
uint8_t m_tracks_per_zone_lsb;
uint8_t m_alt_sectors_per_zone_msb;
uint8_t m_alt_sectors_per_zone_lsb;
uint8_t m_alt_tracks_per_zone_msb;
uint8_t m_alt_tracks_per_zone_lsb;
uint8_t m_alt_tracks_per_volume_msb;
uint8_t m_alt_tracks_per_volume_lsb;
uint8_t m_sectors_per_track_msb;
uint8_t m_sectors_per_track_lsb;
uint8_t m_bytes_per_sector_msb;
uint8_t m_bytes_per_sector_lsb;
uint8_t m_interleave_msb;
uint8_t m_interleave_lsb;
uint8_t m_track_skew_msb;
uint8_t m_track_skew_lsb;
uint8_t m_cylinder_skew_msb;
uint8_t m_cylinder_skew_lsb;
uint8_t m_format;
uint8_t m_reserved[3];
};
struct geometry_page_t
{
uint8_t m_page_code;
uint8_t m_page_length;
uint8_t m_num_cylinders_msb;
uint8_t m_num_cylinders_2nd;
uint8_t m_num_cylinders_lsb;
uint8_t m_num_heads;
uint8_t m_start_cylinder_msb;
uint8_t m_start_cylinder_2nd;
uint8_t m_start_cylinder_lsb;
uint8_t m_start_cylinder_rwc_msb;
uint8_t m_start_cylinder_rwc_2nd;
uint8_t m_start_cylinder_rwc_lsb;
uint8_t m_step_rate_msb;
uint8_t m_step_rate_lsb;
uint8_t m_lz_cylinder_msb;
uint8_t m_lz_cylinder_2nd;
uint8_t m_lz_cylinder_lsb;
uint8_t m_rot_pos_locking;
uint8_t m_rot_offset;
uint8_t m_reserved0;
uint8_t m_rot_rate_msb;
uint8_t m_rot_rate_lsb;
uint8_t m_reserved1[2];
};
virtual void GetFormatPage( format_page_t *page );
virtual void GetGeometryPage( geometry_page_t *page );
virtual void ReadCapacity( uint8_t *data );
harddisk_image_device *m_image;
uint32_t m_lba;

View File

@ -323,7 +323,8 @@ void ip22_state::ip22_base(machine_config &config)
WD33C93(config, m_scsi_ctrl);
m_scsi_ctrl->set_scsi_port("scsi");
m_scsi_ctrl->irq_cb().set(m_hpc3, FUNC(hpc3_device::scsi_irq));
m_scsi_ctrl->irq_cb().set(m_hpc3, FUNC(hpc3_device::scsi0_irq));
//m_scsi_ctrl->drq_cb().set(m_hpc3, FUNC(hpc3_device::scsi0_drq));
SGI_HAL2(config, m_hal2);
SGI_IOC2_GUINNESS(config, m_ioc2, m_maincpu);
@ -368,7 +369,8 @@ void ip24_state::ip244415(machine_config &config)
WD33C93(config, m_scsi_ctrl2);
m_scsi_ctrl2->set_scsi_port("scsi2");
m_scsi_ctrl2->irq_cb().set(m_hpc3, FUNC(hpc3_device::scsi_irq));
m_scsi_ctrl->irq_cb().set(m_hpc3, FUNC(hpc3_device::scsi1_irq));
//m_scsi_ctrl->drq_cb().set(m_hpc3, FUNC(hpc3_device::scsi1_drq));
SGI_HPC3(config, m_hpc3, m_maincpu, m_scsi_ctrl, m_scsi_ctrl2, m_ioc2, m_ldac, m_rdac);
}

View File

@ -12,11 +12,12 @@
#define LOG_UNKNOWN (1 << 0)
#define LOG_PBUS_DMA (1 << 1)
#define LOG_SCSI (1 << 2)
#define LOG_ETHERNET (1 << 3)
#define LOG_PBUS4 (1 << 4)
#define LOG_CHAIN (1 << 5)
#define LOG_SCSI_DMA (1 << 3)
#define LOG_ETHERNET (1 << 4)
#define LOG_PBUS4 (1 << 5)
#define LOG_CHAIN (1 << 6)
#define VERBOSE (LOG_PBUS_DMA | LOG_PBUS4 | LOG_UNKNOWN | LOG_ETHERNET)
#define VERBOSE (LOG_SCSI_DMA)
#include "logmacro.h"
DEFINE_DEVICE_TYPE(SGI_HPC3, hpc3_device, "hpc3", "SGI HPC3")
@ -37,15 +38,21 @@ void hpc3_device::device_start()
{
save_item(NAME(m_enetr_nbdp));
save_item(NAME(m_enetr_cbp));
save_item(NAME(m_scsi0_desc));
save_item(NAME(m_scsi0_addr));
save_item(NAME(m_scsi0_flags));
save_item(NAME(m_scsi0_byte_count));
save_item(NAME(m_scsi0_next_addr));
save_item(NAME(m_scsi0_dma_ctrl));
save_item(NAME(m_pio_config));
for (uint32_t i = 0; i < 2; i++)
{
save_item(NAME(m_scsi_dma[i].m_desc), i);
save_item(NAME(m_scsi_dma[i].m_addr), i);
save_item(NAME(m_scsi_dma[i].m_ctrl), i);
save_item(NAME(m_scsi_dma[i].m_length), i);
save_item(NAME(m_scsi_dma[i].m_next), i);
save_item(NAME(m_scsi_dma[i].m_irq), i);
save_item(NAME(m_scsi_dma[i].m_big_endian), i);
save_item(NAME(m_scsi_dma[i].m_to_device), i);
save_item(NAME(m_scsi_dma[i].m_active), i);
}
for (uint32_t i = 0; i < 8; i++)
{
save_item(NAME(m_pbus_dma[i].m_active), i);
@ -67,12 +74,7 @@ void hpc3_device::device_reset()
m_enetr_nbdp = 0x80000000;
m_enetr_cbp = 0x80000000;
m_scsi0_desc = 0;
m_scsi0_addr = 0;
m_scsi0_flags = 0;
m_scsi0_byte_count = 0;
m_scsi0_next_addr = 0;
m_scsi0_dma_ctrl = 0;
memset(m_scsi_dma, 0, sizeof(scsi_dma_t) * 2);
for (uint32_t i = 0; i < 8; i++)
{
@ -88,6 +90,8 @@ void hpc3_device::device_reset()
m_pbus_dma[i].m_active = false;
m_pbus_dma[i].m_timer->adjust(attotime::never);
}
m_cpu_space = &m_maincpu->space(AS_PROGRAM);
}
void hpc3_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
@ -117,8 +121,7 @@ void hpc3_device::do_pbus_dma(uint32_t channel)
if (dma.m_active && (channel == 1 || channel == 2))
{
address_space &space = m_maincpu->space(AS_PROGRAM);
uint16_t temp16 = space.read_dword(dma.m_cur_ptr) >> 16;
uint16_t temp16 = m_cpu_space->read_dword(dma.m_cur_ptr) >> 16;
int16_t stemp16 = (int16_t)((temp16 >> 8) | (temp16 << 8));
if (channel == 1)
@ -135,10 +138,10 @@ void hpc3_device::do_pbus_dma(uint32_t channel)
{
dma.m_desc_ptr = dma.m_next_ptr;
LOGMASKED(LOG_PBUS_DMA, "Channel %d Next PBUS_DMA_DescPtr = %08x\n", channel, dma.m_desc_ptr); fflush(stdout);
dma.m_cur_ptr = space.read_dword(dma.m_desc_ptr);
dma.m_desc_flags = space.read_dword(dma.m_desc_ptr + 4);
dma.m_cur_ptr = m_cpu_space->read_dword(dma.m_desc_ptr);
dma.m_desc_flags = m_cpu_space->read_dword(dma.m_desc_ptr + 4);
dma.m_bytes_left = dma.m_desc_flags & 0x7fffffff;
dma.m_next_ptr = space.read_dword(dma.m_desc_ptr + 8);
dma.m_next_ptr = m_cpu_space->read_dword(dma.m_desc_ptr + 8);
LOGMASKED(LOG_PBUS_DMA, "Channel %d Next PBUS_DMA_CurPtr = %08x\n", channel, dma.m_cur_ptr); fflush(stdout);
LOGMASKED(LOG_PBUS_DMA, "Channel %d Next PBUS_DMA_BytesLeft = %08x\n", channel, dma.m_bytes_left); fflush(stdout);
LOGMASKED(LOG_PBUS_DMA, "Channel %d Next PBUS_DMA_NextPtr = %08x\n", channel, dma.m_next_ptr); fflush(stdout);
@ -163,11 +166,11 @@ READ32_MEMBER(hpc3_device::hd_enet_r)
switch (offset)
{
case 0x0004/4:
LOGMASKED(LOG_SCSI, "%s: HPC3 SCSI0 Desc Address Read: %08x & %08x\n", machine().describe_context(), m_scsi0_desc, mem_mask);
return m_scsi0_desc;
LOGMASKED(LOG_SCSI, "%s: HPC3 SCSI0 Desc Address Read: %08x & %08x\n", machine().describe_context(), m_scsi_dma[0].m_desc, mem_mask);
return m_scsi_dma[0].m_desc;
case 0x1004/4:
LOGMASKED(LOG_SCSI, "%s: HPC3 SCSI0 DMA Control Read: %08x & %08x\n", machine().describe_context(), m_scsi0_dma_ctrl, mem_mask);
return m_scsi0_dma_ctrl;
LOGMASKED(LOG_SCSI, "%s: HPC3 SCSI0 DMA Control Read: %08x & %08x\n", machine().describe_context(), m_scsi_dma[0].m_ctrl, mem_mask);
return m_scsi_dma[0].m_ctrl;
case 0x4000/4:
LOGMASKED(LOG_ETHERNET, "%s: HPC3 Ethernet CBP Read: %08x & %08x\n", machine().describe_context(), m_enetr_nbdp, mem_mask);
return m_enetr_cbp;
@ -186,11 +189,16 @@ WRITE32_MEMBER(hpc3_device::hd_enet_w)
{
case 0x0004/4:
LOGMASKED(LOG_SCSI, "%s: HPC3 SCSI0 Desc Address Write: %08x\n", machine().describe_context(), data);
m_scsi0_desc = data;
m_scsi_dma[0].m_desc = data;
fetch_chain(0);
break;
case 0x1004/4:
LOGMASKED(LOG_SCSI, "%s: HPC3 SCSI0 DMA Control Write: %08x\n", machine().describe_context(), data);
m_scsi0_dma_ctrl = data;
m_scsi_dma[0].m_ctrl = data;
m_scsi_dma[0].m_to_device = (m_scsi_dma[0].m_ctrl & HPC3_DMACTRL_DIR);
m_scsi_dma[0].m_big_endian = (m_scsi_dma[0].m_ctrl & HPC3_DMACTRL_ENDIAN);
m_scsi_dma[0].m_active = (m_scsi_dma[0].m_ctrl & HPC3_DMACTRL_ENABLE);
m_scsi_dma[0].m_irq = (m_scsi_dma[0].m_ctrl & HPC3_DMACTRL_IRQ);
break;
case 0x4000/4:
LOGMASKED(LOG_ETHERNET, "%s: HPC3 Ethernet CBP Write: %08x\n", machine().describe_context(), data);
@ -529,120 +537,171 @@ WRITE32_MEMBER(hpc3_device::unkpbus0_w)
LOGMASKED(LOG_UNKNOWN, "%s: Unknown PBUS Write: %08x = %08x & %08x\n", machine().describe_context(), 0x1fbc8000 + offset*4, data, mem_mask);
}
void hpc3_device::dump_chain(address_space &space, uint32_t ch_base)
void hpc3_device::dump_chain(uint32_t base)
{
LOGMASKED(LOG_CHAIN, "node: %08x %08x %08x (len = %x)\n", space.read_dword(ch_base), space.read_dword(ch_base+4), space.read_dword(ch_base+8), space.read_dword(ch_base+4) & 0x3fff);
const uint32_t addr = m_cpu_space->read_dword(base);
const uint32_t ctrl = m_cpu_space->read_dword(base+4);
const uint32_t next = m_cpu_space->read_dword(base+8);
if ((space.read_dword(ch_base+8) != 0) && !(space.read_dword(ch_base+4) & 0x80000000))
LOGMASKED(LOG_CHAIN, "Chain Node:\n");
LOGMASKED(LOG_CHAIN, " Addr: %08x\n", addr);
LOGMASKED(LOG_CHAIN, " Ctrl: %08x\n", ctrl);
LOGMASKED(LOG_CHAIN, " Next: %08x\n", next);
if (next != 0 && !BIT(ctrl, 31))
{
dump_chain(space, space.read_dword(ch_base+8));
dump_chain(next);
}
}
void hpc3_device::fetch_chain(address_space &space)
void hpc3_device::fetch_chain(int channel)
{
m_scsi0_addr = space.read_dword(m_scsi0_desc);
m_scsi0_flags = space.read_dword(m_scsi0_desc+4);
m_scsi0_byte_count = m_scsi0_flags & 0x3fff;
m_scsi0_next_addr = space.read_dword(m_scsi0_desc+8);
LOGMASKED(LOG_CHAIN, "Fetching chain from %08x: %08x %08x %08x (length %04x)\n", m_scsi0_desc, m_scsi0_addr, m_scsi0_flags, m_scsi0_next_addr, m_scsi0_byte_count);
scsi_dma_t &dma = m_scsi_dma[channel];
dma.m_addr = m_cpu_space->read_dword(dma.m_desc);
dma.m_ctrl = m_cpu_space->read_dword(dma.m_desc+4);
dma.m_next = m_cpu_space->read_dword(dma.m_desc+8);
dma.m_length = dma.m_ctrl & 0x3fff;
LOGMASKED(LOG_CHAIN, "Fetching chain from %08x:\n", dma.m_desc);
LOGMASKED(LOG_CHAIN, " Addr: %08x\n", dma.m_addr);
LOGMASKED(LOG_CHAIN, " Ctrl: %08x\n", dma.m_ctrl);
LOGMASKED(LOG_CHAIN, " Next: %08x\n", dma.m_next);
}
bool hpc3_device::decrement_chain(address_space &space)
void hpc3_device::decrement_chain(int channel)
{
m_scsi0_byte_count--;
if (m_scsi0_byte_count == 0)
scsi_dma_t &dma = m_scsi_dma[channel];
dma.m_length--;
if (dma.m_length == 0)
{
if (BIT(m_scsi0_flags, 31))
if (BIT(dma.m_ctrl, 31))
{
return false;
dma.m_active = false;
dma.m_ctrl &= ~HPC3_DMACTRL_ENABLE;
return;
}
m_scsi0_desc = m_scsi0_next_addr;
fetch_chain(space);
dma.m_desc = dma.m_next;
fetch_chain(channel);
}
return true;
}
WRITE_LINE_MEMBER(hpc3_device::scsi_irq)
void hpc3_device::scsi_drq(bool state, int channel)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
#if 0
scsi_dma_t &dma = m_scsi_dma[channel];
if (state)
if (!dma.m_active)
{
uint8_t dma_buffer[4096];
if (m_wd33c93->get_dma_count())
{
LOGMASKED(LOG_SCSI, "m_wd33c93->get_dma_count() is %d\n", m_wd33c93->get_dma_count());
if (m_scsi0_dma_ctrl & HPC3_DMACTRL_ENABLE)
{
if (m_scsi0_dma_ctrl & HPC3_DMACTRL_IRQ)
LOGMASKED(LOG_SCSI, "IP22: Unhandled SCSI DMA IRQ\n");
LOGMASKED(LOG_SCSI_DMA, "HPC3: SCSI%d DRQ set while no active SCSI DMA!\n", channel);
return;
}
bool big_endian = (m_scsi0_dma_ctrl & HPC3_DMACTRL_ENDIAN);
if (m_scsi0_dma_ctrl & HPC3_DMACTRL_ENABLE)
if (dma.m_to_device)
m_wd33c93->dma_w(m_cpu_space->read_byte(dma.m_big_endian ? BYTE4_XOR_BE(dma.m_addr) : BYTE4_XOR_LE(dma.m_addr)));
else
m_cpu_space->write_byte(dma.m_big_endian ? BYTE4_XOR_BE(dma.m_addr) : BYTE4_XOR_LE(dma.m_addr), m_wd33c93->dma_r());
dma.m_addr++;
decrement_chain(channel);
if (!dma.m_active)
{
if (m_scsi0_dma_ctrl & HPC3_DMACTRL_DIR)
// clear HPC3 DMA active flag
dma.m_ctrl &= ~HPC3_DMACTRL_ENABLE;
}
#endif
}
WRITE_LINE_MEMBER(hpc3_device::scsi0_drq)
{
scsi_drq(state, 0);
}
WRITE_LINE_MEMBER(hpc3_device::scsi1_drq)
{
scsi_drq(state, 1);
}
void hpc3_device::scsi_dma(int channel)
{
int byte_count = channel ? m_wd33c93_2->get_dma_count() : m_wd33c93->get_dma_count();
scsi_dma_t &dma = m_scsi_dma[channel];
LOGMASKED(LOG_SCSI_DMA, "HPC3: Transferring %d bytes %s %08x %s SCSI0\n",
byte_count, dma.m_to_device ? "from" : "to", dma.m_addr, dma.m_to_device ? "to" : "from");
if (dma.m_irq)
LOGMASKED(LOG_SCSI_DMA, "HPC3: Not yet implemented: SCSI DMA IRQ\n");
uint8_t dma_buffer[512];
memset(dma_buffer, 0, 512);
if (dma.m_to_device)
{
// HPC3 DMA: host to device
int byte_count = m_wd33c93->get_dma_count();
//dump_chain(space, m_scsi0_desc);
fetch_chain(space);
LOGMASKED(LOG_SCSI, "DMA to SCSI device: %d bytes from %08x\n", byte_count, m_scsi0_addr);
if (byte_count <= 512)
{
for (int i = 0; i < byte_count; i++)
{
dma_buffer[big_endian ? BYTE4_XOR_BE(i) : BYTE4_XOR_LE(i)] = space.read_byte(m_scsi0_addr+i);
if (!decrement_chain(space))
dma_buffer[dma.m_big_endian ? BYTE4_XOR_BE(i) : BYTE4_XOR_LE(i)] = m_cpu_space->read_byte(dma.m_addr);
dma.m_addr++;
decrement_chain(channel);
if (!dma.m_active)
break;
}
if (channel)
m_wd33c93_2->dma_write_data(byte_count, dma_buffer);
else
m_wd33c93->dma_write_data(byte_count, dma_buffer);
}
else
{
int dstoffs = 0;
while (byte_count)
{
int sub_count = std::min(512, byte_count);
for (int i = 0; i < sub_count; i++)
{
dma_buffer[big_endian ? BYTE4_XOR_BE(dstoffs+i) : BYTE4_XOR_LE(dstoffs+i)] = space.read_byte(m_scsi0_addr);
m_scsi0_addr++;
if (!decrement_chain(space))
dma_buffer[dma.m_big_endian ? BYTE4_XOR_BE(i) : BYTE4_XOR_LE(i)] = m_cpu_space->read_byte(dma.m_addr);
dma.m_addr++;
decrement_chain(channel);
if (!dma.m_active)
break;
}
if (channel)
m_wd33c93_2->dma_write_data(sub_count, dma_buffer);
else
m_wd33c93->dma_write_data(sub_count, dma_buffer);
if (!dma.m_active)
{
break;
}
else
{
memset(dma_buffer, 0, sub_count);
byte_count -= sub_count;
}
}
// clear DMA on the controller too
m_wd33c93->clear_dma();
}
}
else
{
// HPC3 DMA: device to host
int byte_count = m_wd33c93->get_dma_count();
//dump_chain(space, m_scsi0_desc);
fetch_chain(space);
LOGMASKED(LOG_SCSI, "DMA from SCSI device: %d bytes to %08x\n", byte_count, m_scsi0_addr);
if (byte_count < 512)
if (byte_count <= 512)
{
if (channel)
m_wd33c93_2->dma_read_data(byte_count, dma_buffer);
else
m_wd33c93->dma_read_data(byte_count, dma_buffer);
for (int i = 0; i < byte_count; i++)
{
space.write_byte(big_endian ? BYTE4_XOR_BE(m_scsi0_addr+i) : BYTE4_XOR_LE(m_scsi0_addr+i), dma_buffer[i]);
if (!decrement_chain(space))
m_cpu_space->write_byte(dma.m_big_endian ? BYTE4_XOR_BE(dma.m_addr) : BYTE4_XOR_LE(dma.m_addr), dma_buffer[i]);
dma.m_addr++;
decrement_chain(channel);
if (!dma.m_active)
break;
}
}
@ -650,30 +709,40 @@ WRITE_LINE_MEMBER(hpc3_device::scsi_irq)
{
while (byte_count)
{
int sub_count = m_wd33c93->dma_read_data(512, dma_buffer);
int sub_count;
if (channel)
sub_count = m_wd33c93_2->dma_read_data(512, dma_buffer);
else
sub_count = m_wd33c93->dma_read_data(512, dma_buffer);
for (int i = 0; i < sub_count; i++)
{
space.write_byte(big_endian ? BYTE4_XOR_BE(m_scsi0_addr) : BYTE4_XOR_LE(m_scsi0_addr), dma_buffer[i]);
m_scsi0_addr++;
if (!decrement_chain(space))
m_cpu_space->write_byte(dma.m_big_endian ? BYTE4_XOR_BE(dma.m_addr) : BYTE4_XOR_LE(dma.m_addr), dma_buffer[i]);
dma.m_addr++;
decrement_chain(channel);
if (!dma.m_active)
break;
}
if (!dma.m_active)
break;
else
byte_count -= sub_count;
}
}
}
// clear DMA on the controller too
// clear DMA on the controller
m_wd33c93->clear_dma();
}
}
}
// clear HPC3 DMA active flag
m_scsi0_dma_ctrl &= ~HPC3_DMACTRL_ENABLE;
WRITE_LINE_MEMBER(hpc3_device::scsi0_irq)
{
if (state)
{
if (m_wd33c93->get_dma_count() && m_scsi_dma[0].m_active)
scsi_dma(0);
// set the interrupt
m_ioc2->raise_local0_irq(ioc2_device::INT3_LOCAL0_SCSI0);
}
else
@ -681,3 +750,18 @@ WRITE_LINE_MEMBER(hpc3_device::scsi_irq)
m_ioc2->lower_local0_irq(ioc2_device::INT3_LOCAL0_SCSI0);
}
}
WRITE_LINE_MEMBER(hpc3_device::scsi1_irq)
{
if (state)
{
if (m_wd33c93_2->get_dma_count() && m_scsi_dma[1].m_active)
scsi_dma(1);
m_ioc2->raise_local0_irq(ioc2_device::INT3_LOCAL0_SCSI1);
}
else
{
m_ioc2->lower_local0_irq(ioc2_device::INT3_LOCAL0_SCSI1);
}
}

View File

@ -58,7 +58,10 @@ public:
DECLARE_READ32_MEMBER(pio_config_r);
DECLARE_WRITE32_MEMBER(pio_config_w);
DECLARE_WRITE_LINE_MEMBER(scsi_irq);
DECLARE_WRITE_LINE_MEMBER(scsi0_irq);
DECLARE_WRITE_LINE_MEMBER(scsi0_drq);
DECLARE_WRITE_LINE_MEMBER(scsi1_irq);
DECLARE_WRITE_LINE_MEMBER(scsi1_drq);
protected:
void device_start() override;
@ -67,9 +70,11 @@ protected:
void do_pbus_dma(uint32_t channel);
void dump_chain(address_space &space, uint32_t ch_base);
void fetch_chain(address_space &space);
bool decrement_chain(address_space &space);
void dump_chain(uint32_t base);
void fetch_chain(int channel);
void decrement_chain(int channel);
void scsi_drq(bool state, int channel);
void scsi_dma(int channel);
static const device_timer_id TIMER_PBUS_DMA = 0;
@ -127,15 +132,26 @@ protected:
uint32_t m_enetr_nbdp;
uint32_t m_enetr_cbp;
uint32_t m_scsi0_desc;
uint32_t m_scsi0_addr;
uint32_t m_scsi0_flags;
uint32_t m_scsi0_byte_count;
uint32_t m_scsi0_next_addr;
uint32_t m_scsi0_dma_ctrl;
struct scsi_dma_t
{
uint32_t m_desc;
uint32_t m_addr;
uint32_t m_ctrl;
uint32_t m_length;
uint32_t m_next;
bool m_irq;
bool m_big_endian;
bool m_to_device;
bool m_active;
};
scsi_dma_t m_scsi_dma[2];
pbus_dma_t m_pbus_dma[8];
uint32_t m_pio_config[10];
address_space *m_cpu_space;
inline void ATTR_PRINTF(3,4) verboselog(int n_level, const char *s_fmt, ... );
};