mirror of
https://github.com/holub/mame
synced 2025-04-21 07:52:35 +03:00
-am79c90: Added rudimentary AMD 79C90 LANCE ethernet controller support, enough to make sun4 happy. [Ryan Holtz]
This commit is contained in:
parent
c0b70ec306
commit
a24d9ab6ae
@ -610,6 +610,18 @@ if (MACHINES["AM53CF96"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/am79c90.h,MACHINES["AM79C90"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (MACHINES["AM79C90"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/am79c90.cpp",
|
||||
MAME_DIR .. "src/devices/machine/am79c90.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/am9513.h,MACHINES["AM9513"] = true
|
||||
|
@ -396,6 +396,7 @@ MACHINES["ADC1213X"] = true
|
||||
MACHINES["AICARTC"] = true
|
||||
MACHINES["AM2847"] = true
|
||||
MACHINES["AM53CF96"] = true
|
||||
MACHINES["AM79C90"] = true
|
||||
MACHINES["AM9513"] = true
|
||||
MACHINES["AM9517A"] = true
|
||||
MACHINES["AM9519"] = true
|
||||
|
570
src/devices/machine/am79c90.cpp
Normal file
570
src/devices/machine/am79c90.cpp
Normal file
@ -0,0 +1,570 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Ryan Holtz
|
||||
/*****************************************************************************
|
||||
|
||||
AMD Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)
|
||||
|
||||
TODO:
|
||||
- Communication with the outside world
|
||||
- Error handling
|
||||
- Clocks
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "am79c90.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(AM79C90, am79c90_device, "am79c90", "Am79C90 LANCE Ethernet Controller")
|
||||
|
||||
am79c90_device::am79c90_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, AM79C90, tag, owner, clock)
|
||||
, m_receive_timer(nullptr)
|
||||
//, m_receive_poll_timer(nullptr)
|
||||
, m_transmit_timer(nullptr)
|
||||
, m_transmit_poll_timer(nullptr)
|
||||
, m_irq_out_cb(*this)
|
||||
, m_dma_out_cb(*this)
|
||||
, m_dma_in_cb(*this)
|
||||
{
|
||||
}
|
||||
|
||||
void am79c90_device::device_start()
|
||||
{
|
||||
m_irq_out_cb.resolve_safe();
|
||||
m_dma_out_cb.resolve_safe(); // TODO: Should be read/write16!
|
||||
m_dma_in_cb.resolve_safe(0);
|
||||
|
||||
m_transmit_poll_timer = timer_alloc(TIMER_TRANSMIT_POLL);
|
||||
m_transmit_poll_timer->adjust(attotime::never);
|
||||
m_transmit_timer = timer_alloc(TIMER_TRANSMIT);
|
||||
m_transmit_timer->adjust(attotime::never);
|
||||
m_receive_timer = timer_alloc(TIMER_RECEIVE);
|
||||
m_receive_timer->adjust(attotime::never);
|
||||
|
||||
save_item(NAME(m_curr_transmit_desc.m_tmd01));
|
||||
save_item(NAME(m_curr_transmit_desc.m_tmd23));
|
||||
save_item(NAME(m_next_transmit_desc.m_tmd01));
|
||||
save_item(NAME(m_next_transmit_desc.m_tmd23));
|
||||
save_item(NAME(m_curr_recv_desc.m_tmd01));
|
||||
save_item(NAME(m_curr_recv_desc.m_tmd23));
|
||||
save_item(NAME(m_next_recv_desc.m_tmd01));
|
||||
save_item(NAME(m_next_recv_desc.m_tmd23));
|
||||
save_item(NAME(m_rap));
|
||||
save_item(NAME(m_csr));
|
||||
save_item(NAME(m_mode));
|
||||
save_item(NAME(m_logical_addr_filter));
|
||||
save_item(NAME(m_physical_addr));
|
||||
|
||||
save_item(NAME(m_recv_message_count));
|
||||
save_item(NAME(m_recv_ring_addr));
|
||||
save_item(NAME(m_recv_buf_addr));
|
||||
save_item(NAME(m_recv_buf_count));
|
||||
save_item(NAME(m_recv_ring_length));
|
||||
save_item(NAME(m_recv_ring_pos));
|
||||
save_item(NAME(m_recv_fifo));
|
||||
save_item(NAME(m_recv_fifo_write));
|
||||
save_item(NAME(m_recv_fifo_read));
|
||||
save_item(NAME(m_receiving));
|
||||
|
||||
save_item(NAME(m_transmit_ring_addr));
|
||||
save_item(NAME(m_transmit_buf_addr));
|
||||
save_item(NAME(m_transmit_buf_count));
|
||||
save_item(NAME(m_transmit_ring_length));
|
||||
save_item(NAME(m_transmit_ring_pos));
|
||||
save_item(NAME(m_transmit_fifo));
|
||||
save_item(NAME(m_transmit_fifo_write));
|
||||
save_item(NAME(m_transmit_fifo_read));
|
||||
save_item(NAME(m_transmitting));
|
||||
}
|
||||
|
||||
void am79c90_device::device_reset()
|
||||
{
|
||||
memset(&m_curr_transmit_desc, 0, sizeof(ring_descriptor));
|
||||
memset(&m_next_transmit_desc, 0, sizeof(ring_descriptor));
|
||||
memset(&m_curr_recv_desc, 0, sizeof(ring_descriptor));
|
||||
memset(&m_next_recv_desc, 0, sizeof(ring_descriptor));
|
||||
m_rap = 0;
|
||||
memset(m_csr, 0, sizeof(uint16_t) * 4);
|
||||
m_csr[0] = CSR0_STOP;
|
||||
m_mode = 0;
|
||||
m_logical_addr_filter = 0;
|
||||
m_physical_addr = 0;
|
||||
|
||||
m_recv_message_count = 0;
|
||||
m_recv_ring_addr = 0;
|
||||
m_recv_buf_addr = 0;
|
||||
m_recv_buf_count = 0;
|
||||
m_recv_ring_length = 0;
|
||||
m_recv_ring_pos = 0;
|
||||
memset(m_recv_fifo, 0, sizeof(uint32_t) * ARRAY_LENGTH(m_recv_fifo));
|
||||
m_recv_fifo_write = 0;
|
||||
m_recv_fifo_read = 0;
|
||||
m_receiving = false;
|
||||
|
||||
m_transmit_ring_addr = 0;
|
||||
m_transmit_buf_addr = 0;
|
||||
m_transmit_buf_count = 0;
|
||||
m_transmit_ring_length = 0;
|
||||
m_transmit_ring_pos = 0;
|
||||
memset(m_transmit_fifo, 0, sizeof(uint32_t) * ARRAY_LENGTH(m_transmit_fifo));
|
||||
m_transmit_fifo_write = 0;
|
||||
m_transmit_fifo_read = 0;
|
||||
m_transmitting = false;
|
||||
}
|
||||
|
||||
void am79c90_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case TIMER_TRANSMIT_POLL:
|
||||
poll_transmit();
|
||||
break;
|
||||
|
||||
case TIMER_TRANSMIT:
|
||||
transmit();
|
||||
break;
|
||||
|
||||
case TIMER_RECEIVE:
|
||||
receive();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void am79c90_device::fetch_transmit_descriptor()
|
||||
{
|
||||
const uint32_t next_addr = (m_transmit_ring_addr >> 2) + (m_transmit_ring_pos << 1);
|
||||
ring_descriptor &next = m_next_transmit_desc;
|
||||
next.m_tmd01 = m_dma_in_cb(next_addr, ~0);
|
||||
next.m_tmd23 = m_dma_in_cb(next_addr + 1, ~0);
|
||||
}
|
||||
|
||||
void am79c90_device::fetch_receive_descriptor()
|
||||
{
|
||||
const uint32_t next_addr = (m_recv_ring_addr >> 2) + (m_recv_ring_pos << 1);
|
||||
ring_descriptor &next = m_next_recv_desc;
|
||||
next.m_rmd01 = m_dma_in_cb(next_addr, ~0);
|
||||
next.m_rmd23 = m_dma_in_cb(next_addr + 1, ~0);
|
||||
}
|
||||
|
||||
void am79c90_device::recv_fifo_push(uint32_t value)
|
||||
{
|
||||
// TODO: Poll for the FIFO at 1.6ms, don't instantly start receiving!
|
||||
// "...If the C-LANCE does not own it, it will poll the ring once every 1.6ms until
|
||||
// it owns it."
|
||||
|
||||
logerror("%s: LANCE pushing %08x onto receive FIFO\n", machine().describe_context(), value);
|
||||
if (!m_receiving && !(m_mode & MODE_LOOP))
|
||||
{
|
||||
begin_receiving();
|
||||
}
|
||||
|
||||
if (m_recv_fifo_write >= ARRAY_LENGTH(m_recv_fifo))
|
||||
{
|
||||
logerror("%s: LANCE can't push onto receive FIFO, %d >= %d\n", machine().describe_context(), value, m_recv_fifo_write, ARRAY_LENGTH(m_recv_fifo));
|
||||
// TODO: Do something
|
||||
return;
|
||||
}
|
||||
m_recv_fifo[m_recv_fifo_write] = value;
|
||||
m_recv_fifo_write++;
|
||||
if (m_recv_fifo_write == ARRAY_LENGTH(m_recv_fifo))
|
||||
{
|
||||
// TODO: Do something
|
||||
}
|
||||
}
|
||||
|
||||
void am79c90_device::begin_receiving()
|
||||
{
|
||||
fetch_receive_descriptor();
|
||||
m_curr_recv_desc = m_next_recv_desc;
|
||||
|
||||
ring_descriptor &curr = m_curr_recv_desc;
|
||||
if (curr.m_rmd01 & RMD1_OWN)
|
||||
{
|
||||
logerror("%s: LANCE owns the current buffer, activating receive timer, RMD0123 is %08x %08x\n", machine().describe_context(), curr.m_rmd01, curr.m_rmd23);
|
||||
|
||||
m_receiving = true;
|
||||
m_recv_buf_addr = (((curr.m_rmd01 << 16) | (curr.m_rmd01 >> 16)) & 0x00ffffff) | 0xff000000;
|
||||
const int32_t rmd2 = (int16_t)(curr.m_rmd23 >> 16);
|
||||
m_recv_buf_count = (uint16_t)((-rmd2) & 0x00000fff);
|
||||
if (m_recv_buf_count == 0)
|
||||
m_recv_buf_count = 0x1000;
|
||||
|
||||
if (m_mode & MODE_LOOP)
|
||||
{
|
||||
m_recv_buf_count = (m_mode & MODE_DTCR) ? 32 : 36;
|
||||
}
|
||||
|
||||
if (curr.m_rmd01 & RMD1_STP)
|
||||
{
|
||||
m_recv_message_count = 0;
|
||||
}
|
||||
m_receive_timer->adjust(attotime::from_hz(10'000'000), 0, attotime::from_hz(10'000'000));
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("%s: LANCE does not own the current buffer, deactivating receive timer\n", machine().describe_context());
|
||||
m_receiving = false;
|
||||
m_receive_timer->adjust(attotime::never);
|
||||
}
|
||||
}
|
||||
|
||||
void am79c90_device::receive()
|
||||
{
|
||||
const uint32_t received_value = (m_recv_fifo_write == 0) ? 0 : m_recv_fifo[m_recv_fifo_read];
|
||||
m_recv_fifo_read++;
|
||||
if (m_recv_fifo_read >= m_recv_fifo_write)
|
||||
{
|
||||
m_recv_fifo_read = 0;
|
||||
m_recv_fifo_write = 0;
|
||||
}
|
||||
|
||||
if (m_recv_buf_count >= 4)
|
||||
{
|
||||
logerror("%s: LANCE receiving %08x to address %08x, remaining %d\n", machine().describe_context(), received_value, m_recv_buf_addr, m_recv_buf_count - 4);
|
||||
m_dma_out_cb(m_recv_buf_addr >> 2, received_value, ~0);
|
||||
|
||||
m_recv_buf_addr += 4;
|
||||
m_recv_message_count += 4;
|
||||
m_recv_buf_count -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint32_t mask = 0xffffffff << (m_recv_buf_count << 3);
|
||||
logerror("%s: LANCE receiving %08x & %08x to address %08x, remaining %d\n", machine().describe_context(), received_value, mask, m_recv_buf_addr, 0);
|
||||
m_dma_out_cb(m_recv_buf_addr >> 2, received_value, mask);
|
||||
|
||||
m_recv_buf_addr += m_recv_buf_count;
|
||||
m_recv_message_count += m_recv_buf_count;
|
||||
m_recv_buf_count = 0;
|
||||
}
|
||||
|
||||
if (m_recv_buf_count == 0)
|
||||
{
|
||||
logerror("%s: LANCE has completed receiving a buffer, clearing OWN bit and advancing receive ring position\n", machine().describe_context());
|
||||
ring_descriptor &curr = m_curr_recv_desc;
|
||||
curr.m_rmd01 &= ~RMD1_OWN;
|
||||
const uint32_t addr = (m_recv_ring_addr >> 2) + (m_recv_ring_pos << 1);
|
||||
logerror("%s: LANCE is writing new RMD01: %08x\n", machine().describe_context(), curr.m_rmd01);
|
||||
m_dma_out_cb(addr, curr.m_rmd01, ~0);
|
||||
|
||||
if (curr.m_rmd01 & TMD1_ENP)
|
||||
{
|
||||
curr.m_rmd23 &= 0xfffff000;
|
||||
if (m_recv_message_count != 0x1000)
|
||||
{
|
||||
curr.m_rmd23 |= m_recv_message_count & 0xfff;
|
||||
}
|
||||
|
||||
m_dma_out_cb(addr + 1, curr.m_rmd23, ~0);
|
||||
|
||||
logerror("%s: LANCE has completed receiving a message, total message length %d bytes, new RMD23 %08x\n", machine().describe_context(), m_recv_message_count, curr.m_rmd23);
|
||||
}
|
||||
m_recv_ring_pos++;
|
||||
m_recv_ring_pos &= m_recv_ring_length - 1;
|
||||
|
||||
if (!(m_mode & MODE_LOOP))
|
||||
{
|
||||
begin_receiving();
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("%s: LANCE loopback test receive finished, setting RINT and stopping timer.\n", machine().describe_context());
|
||||
m_csr[0] |= CSR0_RINT;
|
||||
update_interrupts();
|
||||
m_receiving = false;
|
||||
m_receive_timer->adjust(attotime::never);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void am79c90_device::transmit()
|
||||
{
|
||||
logerror("%s: LANCE transmit, fetching from %08x\n", machine().describe_context(), m_transmit_buf_addr >> 2);
|
||||
uint32_t transmit_value = 0;
|
||||
const bool dtcr = m_mode & MODE_DTCR;
|
||||
if (m_transmit_buf_count > 4 || dtcr)
|
||||
{
|
||||
transmit_value = m_dma_in_cb(m_transmit_buf_addr >> 2, ~0);
|
||||
if (!dtcr)
|
||||
{
|
||||
m_crc32.append(&transmit_value, sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
transmit_value = (uint32_t)m_crc32.finish();
|
||||
}
|
||||
const bool loopback = (m_mode & MODE_LOOP);
|
||||
if (loopback)
|
||||
{
|
||||
// TODO: Differentiate between internal and external loopback
|
||||
recv_fifo_push(transmit_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Send data to an actual network interface and/or our real transmit FIFO
|
||||
}
|
||||
|
||||
if (m_transmit_buf_count >= 4)
|
||||
{
|
||||
m_transmit_buf_addr += 4;
|
||||
m_transmit_buf_count -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_transmit_buf_addr += m_transmit_buf_count;
|
||||
m_transmit_buf_count = 0;
|
||||
}
|
||||
|
||||
if (m_transmit_buf_count == 0)
|
||||
{
|
||||
const uint32_t base_addr = (m_transmit_ring_addr >> 2) + (m_transmit_ring_pos << 1);
|
||||
ring_descriptor &curr = m_curr_transmit_desc;
|
||||
curr.m_tmd01 &= ~TMD1_OWN;
|
||||
|
||||
m_dma_out_cb(base_addr, curr.m_tmd01, ~0);
|
||||
|
||||
if (!(curr.m_tmd01 & TMD1_ENP))
|
||||
{
|
||||
fetch_transmit_descriptor();
|
||||
m_curr_transmit_desc = m_next_transmit_desc;
|
||||
|
||||
if (!(curr.m_tmd01 & TMD1_OWN))
|
||||
{
|
||||
logerror("%s: LANCE is done transmitting a buffer of this descriptor ring, next ring unowned, resuming polling.\n", machine().describe_context());
|
||||
m_transmitting = false;
|
||||
m_transmit_timer->adjust(attotime::never);
|
||||
m_transmit_poll_timer->adjust(attotime::from_usec(1600), 0, attotime::from_usec(1600));
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("%s: LANCE is done transmitting a buffer of this descriptor ring, preparing to transmit next buffer.\n", machine().describe_context());
|
||||
prepare_transmit_buf();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("%s: LANCE is done transmitting the last buffer of this descriptor ring, raising TINT and resuming polling.\n", machine().describe_context());
|
||||
if (m_mode & MODE_LOOP)
|
||||
{
|
||||
begin_receiving();
|
||||
}
|
||||
|
||||
m_csr[0] |= CSR0_TINT;
|
||||
update_interrupts();
|
||||
m_transmitting = false;
|
||||
m_transmit_timer->adjust(attotime::never);
|
||||
m_transmit_poll_timer->adjust(attotime::from_usec(1600), 0, attotime::from_usec(1600));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void am79c90_device::prepare_transmit_buf()
|
||||
{
|
||||
ring_descriptor &curr = m_curr_transmit_desc;
|
||||
m_transmit_buf_addr = ((curr.m_tmd01 << 16) | ((curr.m_tmd01 >> 16) & 0x00ffffff)) | 0xff000000;
|
||||
const int32_t tmd2 = (int16_t)(curr.m_tmd23 >> 16);
|
||||
m_transmit_buf_count = (uint16_t)((-tmd2) & 0x00000fff);
|
||||
if (m_transmit_buf_count == 0)
|
||||
m_transmit_buf_count = 0x1000;
|
||||
if (!(m_mode & MODE_DTCR))
|
||||
{
|
||||
m_transmit_buf_count += 4;
|
||||
}
|
||||
logerror("%s: LANCE: Valid transmit descriptors found, preparing to transmit %d bytes\n", machine().describe_context(), m_transmit_buf_count);
|
||||
}
|
||||
|
||||
void am79c90_device::poll_transmit()
|
||||
{
|
||||
ring_descriptor &curr = m_curr_transmit_desc;
|
||||
const uint32_t base_addr = (m_transmit_ring_addr >> 2) + (m_transmit_ring_pos << 1);
|
||||
logerror("%s: LANCE polling for packets from %08x\n", machine().describe_context(), base_addr);
|
||||
curr.m_tmd01 = m_dma_in_cb(base_addr, ~0);
|
||||
|
||||
const uint16_t tmd1 = (uint16_t)curr.m_tmd01;
|
||||
if (!(tmd1 & TMD1_OWN))
|
||||
return;
|
||||
|
||||
if (!(tmd1 & TMD1_STP) && !m_transmitting)
|
||||
{
|
||||
// "The STP bit must be set in the first buffer of the packet, or the C-LANCE will skip over this
|
||||
// descriptor and poll the next descriptor(s) until the OWN and STP bits are set."
|
||||
m_transmit_ring_pos++;
|
||||
m_transmit_ring_pos &= m_transmit_ring_length - 1;
|
||||
logerror("%s: LANCE: No STP on this entry and not transmitting, skipping to next entry\n", machine().describe_context());
|
||||
return;
|
||||
}
|
||||
|
||||
logerror("%s: LANCE: Starting transmitting\n", machine().describe_context());
|
||||
|
||||
m_transmit_poll_timer->adjust(attotime::never);
|
||||
m_transmitting = true;
|
||||
m_crc32.reset();
|
||||
|
||||
// TMD0's value is retrieved from the value fetched above, but per the AMD Am79C90 manual, page 30:
|
||||
// "The C-LANCE will read TMD0 and TMD2 to get the rest of the buffer address and the buffer byte count
|
||||
// when it owns the descriptor. Each of these memory reads is done separately with a new arbitration
|
||||
// cycle for each transfer."
|
||||
m_dma_in_cb(base_addr, ~0);
|
||||
|
||||
curr.m_tmd23 = m_dma_in_cb(base_addr + 1, ~0);
|
||||
|
||||
m_transmit_ring_pos++;
|
||||
m_transmit_ring_pos &= m_transmit_ring_length - 1;
|
||||
|
||||
if (!(tmd1 & TMD1_ENP))
|
||||
{
|
||||
logerror("%s: LANCE: No EOP on this entry, caching next entry and checking ownership\n", machine().describe_context());
|
||||
// "BUFFER ERROR is set by the C-LANCE during transmission when the C-LANCE does not find the ENP
|
||||
// flag in the current buffer and does not own the next buffer."
|
||||
fetch_transmit_descriptor();
|
||||
ring_descriptor &next = m_next_transmit_desc;
|
||||
|
||||
if (!((next.m_tmd01 >> 16) & TMD1_OWN))
|
||||
{
|
||||
logerror("%s: LANCE: No EOP on this entry, but we don't own the next one; setting BUFF\n", machine().describe_context());
|
||||
curr.m_tmd23 |= TMD3_BUFF;
|
||||
m_dma_out_cb(base_addr + 1, curr.m_tmd23, ~0);
|
||||
m_csr[0] &= ~CSR0_TXON;
|
||||
m_transmitting = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
prepare_transmit_buf();
|
||||
|
||||
m_transmit_timer->adjust(attotime::from_hz(10'000'000), 0, attotime::from_hz(10'000'000));
|
||||
}
|
||||
|
||||
void am79c90_device::update_interrupts()
|
||||
{
|
||||
if (m_csr[0] & CSR0_ANY_INTR)
|
||||
{
|
||||
m_csr[0] |= CSR0_INTR;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_csr[0] &= ~CSR0_INTR;
|
||||
}
|
||||
m_irq_out_cb((m_csr[0] & CSR0_INTR) ? 1 : 0);
|
||||
}
|
||||
|
||||
READ16_MEMBER(am79c90_device::regs_r)
|
||||
{
|
||||
uint16_t ret = 0;
|
||||
if (offset)
|
||||
{
|
||||
ret = m_rap;
|
||||
logerror("%s: lance_r: RAP = %04x\n", machine().describe_context(), ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = m_csr[m_rap];
|
||||
logerror("%s: lance_r: CSR%d = %04x\n", machine().describe_context(), m_rap, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
WRITE16_MEMBER(am79c90_device::regs_w)
|
||||
{
|
||||
if (offset)
|
||||
{
|
||||
logerror("%s: lance_r: RAP = %d\n", machine().describe_context(), data & 3);
|
||||
m_rap = data & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("%s: lance_w: CSR%d = %04x\n", machine().describe_context(), m_rap, data);
|
||||
switch (m_rap)
|
||||
{
|
||||
case 0: // Control/Status
|
||||
m_csr[0] &= ~(data & (CSR0_ANY_ERR | CSR0_IDON));
|
||||
if (m_csr[0] & CSR0_ANY_ERR)
|
||||
m_csr[0] |= CSR0_ERR;
|
||||
else
|
||||
m_csr[0] &= ~CSR0_ERR;
|
||||
if (data & CSR0_STOP)
|
||||
{
|
||||
data &= ~(CSR0_RXON | CSR0_TXON | CSR0_TDMD | CSR0_STRT | CSR0_INIT);
|
||||
m_csr[0] &= ~(CSR0_IDON | CSR0_RXON | CSR0_TXON | CSR0_TDMD | CSR0_STRT | CSR0_INIT);
|
||||
m_csr[0] |= CSR0_STOP;
|
||||
m_csr[3] = 0;
|
||||
m_receive_timer->adjust(attotime::never);
|
||||
m_transmit_timer->adjust(attotime::never);
|
||||
m_transmit_poll_timer->adjust(attotime::never);
|
||||
}
|
||||
if (data & CSR0_INIT)
|
||||
{
|
||||
uint32_t init_addr = 0xff000000 | m_csr[1] | (m_csr[2] << 16);
|
||||
uint16_t init_block[12];
|
||||
|
||||
logerror("%s: LANCE Init block:\n", machine().describe_context());
|
||||
|
||||
for (uint32_t i = 0; i < 6; i++)
|
||||
{
|
||||
uint32_t value = m_dma_in_cb((init_addr >> 2) + i, ~0);
|
||||
init_block[i*2 + 0] = (uint16_t)(value >> 16);
|
||||
init_block[i*2 + 1] = (uint16_t)value;
|
||||
logerror("%s: IADR +%02d: %04x\n", machine().describe_context(), i*4, init_block[i*2 + 0]);
|
||||
logerror("%s: IADR +%02d: %04x\n", machine().describe_context(), i*4 + 2, init_block[i*2 + 1]);
|
||||
}
|
||||
|
||||
m_mode = init_block[0];
|
||||
m_physical_addr = ((uint64_t)init_block[3] << 32) | ((uint64_t)init_block[2] << 16) | (uint64_t)init_block[1];
|
||||
m_logical_addr_filter = ((uint64_t)init_block[7] << 48) | ((uint64_t)init_block[6] << 32)
|
||||
| ((uint64_t)init_block[5] << 16) | (uint64_t)init_block[4];
|
||||
m_recv_ring_addr = (((uint32_t)init_block[9] << 16) | (uint32_t)init_block[8]) & 0x00fffff8;
|
||||
m_recv_ring_addr |= 0xff000000;
|
||||
m_transmit_ring_addr = (((uint32_t)init_block[11] << 16) | (uint32_t)init_block[10]) & 0x00fffff8;
|
||||
m_transmit_ring_addr |= 0xff000000;
|
||||
m_recv_ring_length = 1 << ((init_block[9] >> 13) & 7);
|
||||
m_transmit_ring_length = 1 << ((init_block[11] >> 13) & 7);
|
||||
|
||||
m_transmit_ring_pos = 0;
|
||||
m_recv_ring_pos = 0;
|
||||
|
||||
logerror("%s: Mode: %04x\n", machine().describe_context(), m_mode);
|
||||
logerror("%s: Physical Address: %08x%08x\n", machine().describe_context(),
|
||||
(uint32_t)(m_physical_addr >> 32), (uint32_t)m_physical_addr);
|
||||
logerror("%s: Logical Address Filter: %08x%08x\n", machine().describe_context(),
|
||||
(uint32_t)(m_logical_addr_filter >> 32), (uint32_t)m_logical_addr_filter);
|
||||
logerror("%s: Receive Ring Address: %08x\n", machine().describe_context(), m_recv_ring_addr);
|
||||
logerror("%s: Receive Ring Length: %04x\n", machine().describe_context(), m_recv_ring_length);
|
||||
logerror("%s: Transmit Ring Address: %08x\n", machine().describe_context(), m_transmit_ring_addr);
|
||||
logerror("%s: Transmit Ring Length: %04x\n", machine().describe_context(), m_transmit_ring_length);
|
||||
|
||||
m_csr[0] &= ~CSR0_STOP;
|
||||
m_csr[0] |= CSR0_IDON | CSR0_INIT | CSR0_TXON | CSR0_RXON;
|
||||
|
||||
m_receive_timer->adjust(attotime::never);
|
||||
m_transmit_timer->adjust(attotime::never);
|
||||
m_transmit_poll_timer->adjust(attotime::never);
|
||||
}
|
||||
if (data & CSR0_STRT)
|
||||
{
|
||||
m_csr[0] &= ~CSR0_STOP;
|
||||
if (m_mode & MODE_DRX)
|
||||
m_csr[0] &= ~CSR0_RXON;
|
||||
if (m_mode & MODE_DTX)
|
||||
m_csr[0] &= ~CSR0_TXON;
|
||||
if (m_csr[0] & CSR0_TXON)
|
||||
m_transmit_poll_timer->adjust(attotime::from_usec(1600), 0, attotime::from_usec(1600));
|
||||
}
|
||||
update_interrupts();
|
||||
if (data & CSR0_TDMD)
|
||||
{
|
||||
// TODO: Handle transmit demand
|
||||
}
|
||||
break;
|
||||
case 1: // Least significant 15 bits of the Initialization Block
|
||||
m_csr[1] = data & 0xfffe;
|
||||
break;
|
||||
case 2: // Most significant 8 bits of the Initialization Block
|
||||
m_csr[2] = data & 0x00ff;
|
||||
break;
|
||||
case 3: // Bus master interface
|
||||
m_csr[3] = data & 0x0007;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
202
src/devices/machine/am79c90.h
Normal file
202
src/devices/machine/am79c90.h
Normal file
@ -0,0 +1,202 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Ryan Holtz
|
||||
/*****************************************************************************
|
||||
|
||||
AMD Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)
|
||||
|
||||
TODO:
|
||||
- Communication with the outside world
|
||||
- Error handling
|
||||
- Clocks
|
||||
|
||||
******************************************************************************
|
||||
_____ _____
|
||||
Vss 1 |* \_/ | 48 Vdd
|
||||
DAL7 2 | | 47 DAL8
|
||||
DAL6 3 | | 46 DAL9
|
||||
DAL5 4 | | 45 DAL10
|
||||
DAL4 5 | | 44 DAL11
|
||||
DAL3 6 | | 43 DAL12
|
||||
DAL2 7 | | 42 DAL13
|
||||
DAL1 8 | | 41 DAL14
|
||||
DAL0 9 | | 40 DAL15
|
||||
READ 10 | | 39 A16
|
||||
/INTR 11 | | 38 A17
|
||||
/DALI 12 | Am79C90 | 37 A18
|
||||
/DALI 13 | | 36 A19
|
||||
/DAS 14 | | 35 A20
|
||||
/BM0,BYTE 15 | | 34 A21
|
||||
/BM1,/BUSAKO 16 | | 33 A22
|
||||
/HOLD,/BUSRQ 17 | | 32 A23
|
||||
ALE,/AS 18 | | 31 RX
|
||||
/HLDA 19 | | 30 RENA
|
||||
/CS 20 | | 29 TX
|
||||
ADR 21 | | 28 CLSN
|
||||
/READY 22 | | 27 RCLK
|
||||
/RESET 23 | | 26 TENA
|
||||
Vss 24 |_____________| 25 TCLK
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef MAME_MACHINE_AM79C90_H
|
||||
#define MAME_MACHINE_AM79C90_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hashing.h"
|
||||
|
||||
class am79c90_device : public device_t
|
||||
{
|
||||
public:
|
||||
am79c90_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
auto dma_out() { return m_dma_out_cb.bind(); }
|
||||
auto dma_in() { return m_dma_in_cb.bind(); }
|
||||
auto irq_out() { return m_irq_out_cb.bind(); }
|
||||
|
||||
DECLARE_READ16_MEMBER(regs_r);
|
||||
DECLARE_WRITE16_MEMBER(regs_w);
|
||||
|
||||
private:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
static const device_timer_id TIMER_TRANSMIT_POLL = 0;
|
||||
static const device_timer_id TIMER_TRANSMIT = 1;
|
||||
//static const device_timer_id TIMER_RECEIVE_POLL = 2;
|
||||
static const device_timer_id TIMER_RECEIVE = 3;
|
||||
|
||||
enum
|
||||
{
|
||||
CSR0_ERR = 0x8000,
|
||||
CSR0_BABL = 0x4000,
|
||||
CSR0_CERR = 0x2000,
|
||||
CSR0_MISS = 0x1000,
|
||||
CSR0_MERR = 0x0800,
|
||||
CSR0_RINT = 0x0400,
|
||||
CSR0_TINT = 0x0200,
|
||||
CSR0_IDON = 0x0100,
|
||||
CSR0_INTR = 0x0080,
|
||||
CSR0_INEA = 0x0040,
|
||||
CSR0_RXON = 0x0020,
|
||||
CSR0_TXON = 0x0010,
|
||||
CSR0_TDMD = 0x0008,
|
||||
CSR0_STOP = 0x0004,
|
||||
CSR0_STRT = 0x0002,
|
||||
CSR0_INIT = 0x0001,
|
||||
CSR0_ANY_INTR = CSR0_BABL | CSR0_MISS | CSR0_MERR | CSR0_RINT | CSR0_TINT | CSR0_IDON,
|
||||
CSR0_ANY_ERR = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR,
|
||||
|
||||
CSR3_BSWP = 0x0004,
|
||||
CSR3_ACON = 0x0002,
|
||||
CSR3_BCON = 0x0001,
|
||||
|
||||
MODE_DRX = 0x0001,
|
||||
MODE_DTX = 0x0002,
|
||||
MODE_LOOP = 0x0004,
|
||||
MODE_DTCR = 0x0008,
|
||||
MODE_COLL = 0x0010,
|
||||
MODE_DRTY = 0x0020,
|
||||
MODE_INTL = 0x0040,
|
||||
MODE_EMBA = 0x0080,
|
||||
MODE_PROM = 0x8000,
|
||||
|
||||
TMD1_ENP = 0x0100,
|
||||
TMD1_STP = 0x0200,
|
||||
TMD1_DEF = 0x0400,
|
||||
TMD1_ONE = 0x0800,
|
||||
TMD1_MORE = 0x1000,
|
||||
TMD1_ADD_FCS = 0x2000,
|
||||
TMD1_ERR = 0x4000,
|
||||
TMD1_OWN = 0x8000,
|
||||
|
||||
TMD3_RTRY = 0x0400,
|
||||
TMD3_LCAR = 0x0800,
|
||||
TMD3_LCOL = 0x1000,
|
||||
TMD3_RES = 0x2000,
|
||||
TMD3_UFLO = 0x4000,
|
||||
TMD3_BUFF = 0x8000,
|
||||
|
||||
RMD1_ENP = 0x0100,
|
||||
RMD1_STP = 0x0200,
|
||||
RMD1_BUFF = 0x0400,
|
||||
RMD1_CRC = 0x0800,
|
||||
RMD1_OFLO = 0x1000,
|
||||
RMD1_FRAM = 0x2000,
|
||||
RMD1_ERR = 0x4000,
|
||||
RMD1_OWN = 0x8000
|
||||
};
|
||||
|
||||
void prepare_transmit_buf();
|
||||
void begin_receiving();
|
||||
void recv_fifo_push(uint32_t value);
|
||||
void fetch_receive_descriptor();
|
||||
void fetch_transmit_descriptor();
|
||||
void poll_transmit();
|
||||
//void poll_receive(); TODO
|
||||
void transmit();
|
||||
void receive();
|
||||
void update_interrupts();
|
||||
|
||||
struct ring_descriptor
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t m_tmd23;
|
||||
uint32_t m_rmd23;
|
||||
};
|
||||
union
|
||||
{
|
||||
uint32_t m_tmd01;
|
||||
uint32_t m_rmd01;
|
||||
};
|
||||
uint16_t m_byte_count;
|
||||
uint32_t m_buffer_addr;
|
||||
};
|
||||
|
||||
ring_descriptor m_curr_transmit_desc;
|
||||
ring_descriptor m_next_transmit_desc;
|
||||
ring_descriptor m_curr_recv_desc;
|
||||
ring_descriptor m_next_recv_desc;
|
||||
|
||||
uint16_t m_rap;
|
||||
uint16_t m_csr[4];
|
||||
uint16_t m_mode;
|
||||
uint64_t m_logical_addr_filter;
|
||||
uint64_t m_physical_addr;
|
||||
uint32_t m_recv_message_count;
|
||||
uint32_t m_recv_ring_addr;
|
||||
uint32_t m_recv_buf_addr;
|
||||
uint16_t m_recv_buf_count;
|
||||
uint8_t m_recv_ring_length;
|
||||
uint8_t m_recv_ring_pos;
|
||||
uint32_t m_recv_fifo[16];
|
||||
uint8_t m_recv_fifo_write;
|
||||
uint8_t m_recv_fifo_read;
|
||||
bool m_receiving;
|
||||
emu_timer *m_receive_timer;
|
||||
//emu_timer *m_receive_poll_timer;
|
||||
|
||||
uint32_t m_transmit_ring_addr;
|
||||
uint32_t m_transmit_buf_addr;
|
||||
uint16_t m_transmit_buf_count;
|
||||
uint8_t m_transmit_ring_length;
|
||||
uint8_t m_transmit_ring_pos;
|
||||
uint32_t m_transmit_fifo[12];
|
||||
uint8_t m_transmit_fifo_write;
|
||||
uint8_t m_transmit_fifo_read;
|
||||
bool m_transmitting;
|
||||
emu_timer *m_transmit_timer;
|
||||
emu_timer *m_transmit_poll_timer;
|
||||
|
||||
devcb_write_line m_irq_out_cb;
|
||||
devcb_write32 m_dma_out_cb; // TODO: Should be read/write16!
|
||||
devcb_read32 m_dma_in_cb;
|
||||
|
||||
util::crc32_creator m_crc32;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(AM79C90, am79c90_device)
|
||||
|
||||
#endif // MAME_MACHINE_AM79C90_H
|
@ -414,6 +414,7 @@
|
||||
#include "bus/rs232/rs232.h"
|
||||
#include "bus/sunkbd/sunkbd.h"
|
||||
#include "cpu/sparc/sparc.h"
|
||||
#include "machine/am79c90.h"
|
||||
#include "machine/bankdev.h"
|
||||
#include "machine/ncr5390.h"
|
||||
#include "machine/nscsi_bus.h"
|
||||
@ -434,7 +435,6 @@
|
||||
#include "formats/mfi_dsk.h"
|
||||
#include "formats/pc_dsk.h"
|
||||
|
||||
|
||||
#define SUN4_LOG_FCODES (0)
|
||||
|
||||
#define TIMEKEEPER_TAG "timekpr"
|
||||
@ -444,6 +444,7 @@
|
||||
#define RS232A_TAG "rs232a"
|
||||
#define RS232B_TAG "rs232b"
|
||||
#define FDC_TAG "fdc"
|
||||
#define LANCE_TAG "lance"
|
||||
|
||||
#define ENA_NOTBOOT (0x80)
|
||||
#define ENA_SDVMA (0x20)
|
||||
@ -540,6 +541,7 @@ public:
|
||||
, m_scc1(*this, SCC1_TAG)
|
||||
, m_scc2(*this, SCC2_TAG)
|
||||
, m_fdc(*this, FDC_TAG)
|
||||
, m_lance(*this, LANCE_TAG)
|
||||
, m_scsibus(*this, "scsibus")
|
||||
, m_scsi(*this, "scsibus:7:ncr53c90a")
|
||||
, m_type0space(*this, "type0")
|
||||
@ -584,8 +586,8 @@ private:
|
||||
DECLARE_WRITE8_MEMBER( fdc_w );
|
||||
DECLARE_READ32_MEMBER( dma_r );
|
||||
DECLARE_WRITE32_MEMBER( dma_w );
|
||||
DECLARE_READ16_MEMBER( lance_r );
|
||||
DECLARE_WRITE16_MEMBER( lance_w );
|
||||
DECLARE_READ32_MEMBER( lance_dma_r ); // TODO: Should be 16 bits
|
||||
DECLARE_WRITE32_MEMBER( lance_dma_w );
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( scsi_irq );
|
||||
DECLARE_WRITE_LINE_MEMBER( scsi_drq );
|
||||
@ -605,6 +607,12 @@ private:
|
||||
void type1space_map(address_map &map);
|
||||
void type1space_s4_map(address_map &map);
|
||||
|
||||
enum sun4_arch
|
||||
{
|
||||
SUN4 = 0,
|
||||
SUN4C = 1
|
||||
};
|
||||
|
||||
required_device<mb86901_device> m_maincpu;
|
||||
|
||||
required_device<mk48t12_device> m_timekpr;
|
||||
@ -613,6 +621,7 @@ private:
|
||||
required_device<z80scc_device> m_scc2;
|
||||
|
||||
required_device<n82077aa_device> m_fdc;
|
||||
required_device<am79c90_device> m_lance;
|
||||
required_device<nscsi_bus_device> m_scsibus;
|
||||
required_device<ncr53c90a_device> m_scsi;
|
||||
|
||||
@ -644,9 +653,6 @@ private:
|
||||
uint8_t m_diag;
|
||||
int m_arch;
|
||||
|
||||
uint16_t m_lance_rap;
|
||||
uint16_t m_lance_csr[4];
|
||||
|
||||
emu_timer *m_c0_timer, *m_c1_timer;
|
||||
emu_timer *m_reset_timer;
|
||||
|
||||
@ -783,7 +789,7 @@ void sun4_state::write_insn_data_4c(uint8_t asi, address_space &space, uint32_t
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("sun4c: INVALID PTE entry %d %08x accessed! vaddr=%x PC=%x\n", entry, m_pagemap[entry], offset <<2, m_maincpu->pc());
|
||||
printf("sun4c: INVALID PTE entry %d %08x accessed! data=%08x vaddr=%x PC=%x\n", entry, m_pagemap[entry], data, offset <<2, m_maincpu->pc());
|
||||
//m_maincpu->trap(SPARC_DATA_ACCESS_EXCEPTION);
|
||||
//m_buserr[0] = 0x8; // invalid PTE
|
||||
//m_buserr[1] = offset<<2;
|
||||
@ -910,7 +916,7 @@ WRITE32_MEMBER( sun4_state::sun4c_mmu_w )
|
||||
{
|
||||
m_reset_timer->adjust(attotime::from_usec(1));
|
||||
m_maincpu->set_input_line(SPARC_RESET, ASSERT_LINE);
|
||||
//printf("Asserting reset line\n");
|
||||
logerror("%s: Asserting reset line\n", machine().describe_context());
|
||||
}
|
||||
//printf("%08x to system enable, mask %08x\n", data, mem_mask);
|
||||
if (m_system_enable & ENA_RESET)
|
||||
@ -1066,7 +1072,7 @@ void sun4_state::write_insn_data(uint8_t asi, address_space &space, uint32_t off
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("sun4: INVALID PTE entry %d %08x accessed! vaddr=%x PC=%x\n", entry, m_pagemap[entry], offset <<2, m_maincpu->pc());
|
||||
printf("sun4: INVALID PTE entry %d %08x accessed! data=%08x vaddr=%x PC=%x\n", entry, m_pagemap[entry], data, offset <<2, m_maincpu->pc());
|
||||
//m_maincpu->trap(SPARC_DATA_ACCESS_EXCEPTION);
|
||||
//m_buserr[0] = 0x8; // invalid PTE
|
||||
//m_buserr[1] = offset<<2;
|
||||
@ -1191,6 +1197,7 @@ WRITE32_MEMBER( sun4_state::sun4_mmu_w )
|
||||
{
|
||||
m_reset_timer->adjust(attotime::from_usec(1));
|
||||
m_maincpu->set_input_line(SPARC_RESET, ASSERT_LINE);
|
||||
logerror("%s: Asserting reset line\n", machine().describe_context());
|
||||
}
|
||||
//printf("%08x to system enable, mask %08x\n", data, mem_mask);
|
||||
if (m_system_enable & ENA_RESET)
|
||||
@ -1352,31 +1359,6 @@ void sun4_state::sun4c_mem(address_map &map)
|
||||
static INPUT_PORTS_START( sun4 )
|
||||
INPUT_PORTS_END
|
||||
|
||||
enum
|
||||
{
|
||||
LANCE_CSR0_ERR = 0x8000,
|
||||
LANCE_CSR0_BABL = 0x4000,
|
||||
LANCE_CSR0_CERR = 0x2000,
|
||||
LANCE_CSR0_MISS = 0x1000,
|
||||
LANCE_CSR0_MERR = 0x0800,
|
||||
LANCE_CSR0_RINT = 0x0400,
|
||||
LANCE_CSR0_TINT = 0x0200,
|
||||
LANCE_CSR0_IDON = 0x0100,
|
||||
LANCE_CSR0_INTR = 0x0080,
|
||||
LANCE_CSR0_INEA = 0x0040,
|
||||
LANCE_CSR0_RXON = 0x0020,
|
||||
LANCE_CSR0_TXON = 0x0010,
|
||||
LANCE_CSR0_TDMD = 0x0008,
|
||||
LANCE_CSR0_STOP = 0x0004,
|
||||
LANCE_CSR0_STRT = 0x0002,
|
||||
LANCE_CSR0_INIT = 0x0001,
|
||||
LANCE_CSR0_ANY_ERR = LANCE_CSR0_BABL | LANCE_CSR0_CERR | LANCE_CSR0_MISS | LANCE_CSR0_MERR,
|
||||
|
||||
LANCE_CSR3_BSWP = 0x0004,
|
||||
LANCE_CSR3_ACON = 0x0002,
|
||||
LANCE_CSR3_BCON = 0x0001
|
||||
};
|
||||
|
||||
void sun4_state::machine_reset()
|
||||
{
|
||||
m_context = 0;
|
||||
@ -1387,10 +1369,6 @@ void sun4_state::machine_reset()
|
||||
m_dma_tc_read = false;
|
||||
m_dma_pack_register = 0;
|
||||
|
||||
m_lance_rap = 0;
|
||||
memset(m_lance_csr, 0, sizeof(uint16_t) * 4);
|
||||
m_lance_csr[0] = LANCE_CSR0_STOP;
|
||||
|
||||
memset(m_counter, 0, sizeof(m_counter));
|
||||
memset(m_dma, 0, sizeof(m_dma));
|
||||
}
|
||||
@ -1514,7 +1492,7 @@ void sun4_state::type1space_map(address_map &map)
|
||||
map(0x08000000, 0x08000003).r(FUNC(sun4_state::ss1_sl0_id)); // slot 0 contains SCSI/DMA/Ethernet
|
||||
map(0x08400000, 0x0840000f).rw(FUNC(sun4_state::dma_r), FUNC(sun4_state::dma_w));
|
||||
map(0x08800000, 0x0880001f).m(m_scsi, FUNC(ncr53c90a_device::map)).umask32(0xff000000);
|
||||
map(0x08c00000, 0x08c00003).rw(FUNC(sun4_state::lance_r), FUNC(sun4_state::lance_w));
|
||||
map(0x08c00000, 0x08c00003).rw(m_lance, FUNC(am79c90_device::regs_r), FUNC(am79c90_device::regs_w));
|
||||
map(0x0e000000, 0x0e000003).r(FUNC(sun4_state::ss1_sl3_id)); // slot 3 contains video board
|
||||
map(0x0e800000, 0x0e8fffff).ram().share("bw2_vram");
|
||||
}
|
||||
@ -1743,7 +1721,7 @@ void sun4_state::dma_transfer_write()
|
||||
logerror("Read from device: %02x, pack count %d\n", dma_value, pack_cnt);
|
||||
m_dma_pack_register |= dma_value << bit_index;
|
||||
|
||||
if ((m_dma[DMA_CTRL] & DMA_EN_CNT) != 0)
|
||||
//if (m_dma[DMA_CTRL] & DMA_EN_CNT)
|
||||
m_dma[DMA_BYTE_COUNT]--;
|
||||
|
||||
pack_cnt++;
|
||||
@ -1802,7 +1780,7 @@ void sun4_state::dma_transfer_read()
|
||||
word_cached = false;
|
||||
|
||||
m_dma[DMA_ADDR]++;
|
||||
if ((m_dma[DMA_CTRL] & DMA_EN_CNT) != 0)
|
||||
//if (m_dma[DMA_CTRL] & DMA_EN_CNT)
|
||||
m_dma[DMA_BYTE_COUNT]--;
|
||||
}
|
||||
}
|
||||
@ -1818,7 +1796,7 @@ void sun4_state::dma_transfer()
|
||||
dma_transfer_read();
|
||||
}
|
||||
|
||||
if (m_dma[DMA_BYTE_COUNT] == 0)
|
||||
if (m_dma[DMA_BYTE_COUNT] == 0 && (m_dma[DMA_CTRL] & DMA_EN_CNT))
|
||||
{
|
||||
m_dma[DMA_CTRL] |= DMA_TC;
|
||||
m_dma_tc_read = false;
|
||||
@ -1911,7 +1889,7 @@ WRITE_LINE_MEMBER( sun4_state::scsi_drq )
|
||||
{
|
||||
logerror("scsi_drq, DMA pending\n");
|
||||
m_dma[DMA_CTRL] |= DMA_REQ_PEND;
|
||||
if (m_dma[DMA_CTRL] & DMA_EN_DMA)
|
||||
if (m_dma[DMA_CTRL] & DMA_EN_DMA && m_dma[DMA_BYTE_COUNT])
|
||||
{
|
||||
logerror("DMA enabled, starting dma\n");
|
||||
dma_transfer();
|
||||
@ -1919,6 +1897,22 @@ WRITE_LINE_MEMBER( sun4_state::scsi_drq )
|
||||
}
|
||||
}
|
||||
|
||||
READ32_MEMBER( sun4_state::lance_dma_r )
|
||||
{
|
||||
if (m_arch == ARCH_SUN4)
|
||||
return read_insn_data(11, m_maincpu->space(AS_PROGRAM), offset, mem_mask);
|
||||
else
|
||||
return read_insn_data_4c(11, m_maincpu->space(AS_PROGRAM), offset, mem_mask);
|
||||
}
|
||||
|
||||
WRITE32_MEMBER( sun4_state::lance_dma_w )
|
||||
{
|
||||
if (m_arch == ARCH_SUN4)
|
||||
write_insn_data(11, m_maincpu->space(AS_PROGRAM), offset, data, mem_mask);
|
||||
else
|
||||
write_insn_data_4c(11, m_maincpu->space(AS_PROGRAM), offset, data, mem_mask);
|
||||
}
|
||||
|
||||
// indicate 4/60 SCSI/DMA/Ethernet card exists
|
||||
READ32_MEMBER( sun4_state::ss1_sl0_id )
|
||||
{
|
||||
@ -1931,75 +1925,6 @@ READ32_MEMBER( sun4_state::ss1_sl3_id )
|
||||
return 0xfe010101;
|
||||
}
|
||||
|
||||
READ16_MEMBER( sun4_state::lance_r )
|
||||
{
|
||||
uint16_t ret = 0;
|
||||
if (offset)
|
||||
{
|
||||
ret = m_lance_rap;
|
||||
logerror("%s: lance_r: RAP = %04x\n", machine().describe_context(), ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = m_lance_csr[m_lance_rap];
|
||||
logerror("%s: lance_r: CSR%d = %04x\n", machine().describe_context(), m_lance_rap, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
WRITE16_MEMBER( sun4_state::lance_w )
|
||||
{
|
||||
if (offset)
|
||||
{
|
||||
logerror("%s: lance_r: RAP = %d\n", machine().describe_context(), data & 3);
|
||||
m_lance_rap = data & 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("%s: lance_w: CSR%d = %04x\n", machine().describe_context(), m_lance_rap, data);
|
||||
switch (m_lance_rap)
|
||||
{
|
||||
case 0: // Control/Status
|
||||
m_lance_csr[0] &= ~(data & (LANCE_CSR0_ANY_ERR | LANCE_CSR0_IDON));
|
||||
if (m_lance_csr[0] & LANCE_CSR0_ANY_ERR)
|
||||
m_lance_csr[0] |= LANCE_CSR0_ERR;
|
||||
else
|
||||
m_lance_csr[0] &= ~LANCE_CSR0_ERR;
|
||||
if (data & LANCE_CSR0_STOP)
|
||||
{
|
||||
data &= ~(LANCE_CSR0_RXON | LANCE_CSR0_TXON | LANCE_CSR0_TDMD | LANCE_CSR0_STRT | LANCE_CSR0_INIT);
|
||||
m_lance_csr[0] &= ~(LANCE_CSR0_IDON | LANCE_CSR0_RXON | LANCE_CSR0_TXON | LANCE_CSR0_TDMD | LANCE_CSR0_STRT | LANCE_CSR0_INIT);
|
||||
m_lance_csr[3] = 0;
|
||||
}
|
||||
if (data & LANCE_CSR0_INIT)
|
||||
{
|
||||
// TODO: Actually parse initialization block
|
||||
m_lance_csr[0] &= ~LANCE_CSR0_STOP;
|
||||
m_lance_csr[0] |= LANCE_CSR0_IDON | LANCE_CSR0_INIT;
|
||||
}
|
||||
if (data & LANCE_CSR0_STRT)
|
||||
{
|
||||
m_lance_csr[0] &= ~LANCE_CSR0_STOP;
|
||||
m_lance_csr[0] |= (LANCE_CSR0_RXON | LANCE_CSR0_TXON | LANCE_CSR0_TINT | LANCE_CSR0_RINT); // TODO: Handle DTX/DRX in initialization block
|
||||
}
|
||||
if (data & (LANCE_CSR0_BABL | LANCE_CSR0_MISS | LANCE_CSR0_MERR | LANCE_CSR0_RINT | LANCE_CSR0_TINT | LANCE_CSR0_IDON))
|
||||
{
|
||||
m_lance_csr[0] |= LANCE_CSR0_INTR;
|
||||
}
|
||||
break;
|
||||
case 1: // Least significant 15 bits of the Initialization Block
|
||||
m_lance_csr[1] = data & 0xfffe;
|
||||
break;
|
||||
case 2: // Most significant 8 bits of the Initialization Block
|
||||
m_lance_csr[2] = data & 0x00ff;
|
||||
break;
|
||||
case 3: // Bus master interface
|
||||
m_lance_csr[3] = data & 0x0007;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FLOPPY_FORMATS_MEMBER( sun4_state::floppy_formats )
|
||||
FLOPPY_PC_FORMAT
|
||||
FLOPPY_FORMATS_END
|
||||
@ -2044,6 +1969,11 @@ MACHINE_CONFIG_START(sun4_state::sun4)
|
||||
// MMU Type 1 device space
|
||||
ADDRESS_MAP_BANK(config, "type1").set_map(&sun4_state::type1space_s4_map).set_options(ENDIANNESS_BIG, 32, 32, 0x80000000);
|
||||
|
||||
// Ethernet
|
||||
AM79C90(config, m_lance, 10'000'000); // clock is a guess
|
||||
m_lance->dma_in().set(FUNC(sun4_state::lance_dma_r));
|
||||
m_lance->dma_out().set(FUNC(sun4_state::lance_dma_w));
|
||||
|
||||
// Keyboard/mouse
|
||||
SCC8530N(config, m_scc1, 4.9152_MHz_XTAL);
|
||||
m_scc1->out_int_callback().set(FUNC(sun4_state::scc1_int));
|
||||
@ -2099,6 +2029,11 @@ MACHINE_CONFIG_START(sun4_state::sun4c)
|
||||
// MMU Type 1 device space
|
||||
ADDRESS_MAP_BANK(config, "type1").set_map(&sun4_state::type1space_map).set_options(ENDIANNESS_BIG, 32, 32, 0x80000000);
|
||||
|
||||
// Ethernet
|
||||
AM79C90(config, m_lance, 10'000'000); // clock is a guess
|
||||
m_lance->dma_in().set(FUNC(sun4_state::lance_dma_r));
|
||||
m_lance->dma_out().set(FUNC(sun4_state::lance_dma_w));
|
||||
|
||||
// Keyboard/mouse
|
||||
SCC8530N(config, m_scc1, 4.9152_MHz_XTAL);
|
||||
m_scc1->out_int_callback().set(FUNC(sun4_state::scc1_int));
|
||||
|
Loading…
Reference in New Issue
Block a user