mirror of
https://github.com/holub/mame
synced 2025-04-23 08:49:55 +03:00
dp83932c: implement networking
(nw)This is enough to get networking working for the MIPS Magnum 4000 (Jazz) running Windows NT 4.0. Many details of the device are still unimplemented or untested. Also: * jazz: handle soft reset, hook up sonic dma * mct_adr: handle sonic dma bus master (crude), handle reset
This commit is contained in:
parent
30038dd15d
commit
f5eb2f59f2
@ -10,118 +10,565 @@
|
||||
* http://bitsavers.org/components/national/_dataBooks/1995_National_Ethernet_Databook.pdf
|
||||
*
|
||||
* TODO
|
||||
* - everything (skeleton only)
|
||||
* - bus mode (big endian, interrupts active low)
|
||||
* - byte count mismatch
|
||||
* - data widths
|
||||
* - tally counters
|
||||
* - software reset
|
||||
* - watchdog timers
|
||||
* - loopback modes
|
||||
* - programmable outputs and extended bus mode
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "dp83932c.h"
|
||||
#include "hashing.h"
|
||||
|
||||
#define VERBOSE 0
|
||||
#define LOG_GENERAL (1U << 0)
|
||||
#define LOG_COMMAND (1U << 1)
|
||||
#define LOG_FILTER (1U << 2)
|
||||
#define LOG_PACKETS (1U << 3)
|
||||
|
||||
//#define VERBOSE (LOG_GENERAL|LOG_COMMAND|LOG_FILTER|LOG_PACKETS)
|
||||
#include "logmacro.h"
|
||||
|
||||
#define EA(hi, lo) ((u32(hi) << 16) | lo)
|
||||
|
||||
DEFINE_DEVICE_TYPE(DP83932C, dp83932c_device, "dp83932c", "National Semiconductor DP83932C SONIC")
|
||||
|
||||
dp83932c_device::dp83932c_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
static constexpr u32 FCS_RESIDUE = 0xdebb20e3;
|
||||
|
||||
static char const *const regname[] =
|
||||
{
|
||||
"CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA",
|
||||
"TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0",
|
||||
"CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP",
|
||||
"RWP", "TRBA0", "TRBA1", "TBWC0", "TBWC1", "ADDR0", "ADDR1", "LLFA",
|
||||
|
||||
"TTDA", "CEP", "CAP2", "CAP1", "CAP0", "CE", "CDP", "CDC",
|
||||
"SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT",
|
||||
"30", "31", "32", "33", "34", "35", "36", "37",
|
||||
"38", "39", "3a", "3b", "3c", "3d", "3e", "DCR2",
|
||||
};
|
||||
|
||||
static u16 const regmask[] =
|
||||
{
|
||||
0x03bf, 0xbfff, 0xfe00, 0xf000, 0x7fff, 0x7fff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xfffe, 0xfffe, 0xfffe,
|
||||
0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
|
||||
0xffff, 0x000f, 0x0000, 0x0000, 0x0000, 0xffff, 0xfffe, 0x001f,
|
||||
0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xf017,
|
||||
};
|
||||
|
||||
dp83932c_device::dp83932c_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
|
||||
: device_t(mconfig, DP83932C, tag, owner, clock)
|
||||
, device_network_interface(mconfig, *this, 10.0f)
|
||||
, m_ram(*this, finder_base::DUMMY_TAG)
|
||||
, m_bus(*this, finder_base::DUMMY_TAG, 0)
|
||||
, m_out_int(*this)
|
||||
, m_int_state(false)
|
||||
{
|
||||
}
|
||||
|
||||
void dp83932c_device::map(address_map &map)
|
||||
{
|
||||
// datasheet uses unshifted register addresses
|
||||
int const shift = 1;
|
||||
|
||||
// command and status registers
|
||||
map(0x00 << shift, (0x00 << shift) | 0x01).rw(FUNC(dp83932c_device::cr_r), FUNC(dp83932c_device::cr_w));
|
||||
//map(0x01 << shift, (0x01 << shift) | 0x01).rw(FUNC(dp83932c_device::dcr_r), FUNC(dp83932c_device::dcr_w));
|
||||
//map(0x02 << shift, (0x02 << shift) | 0x01).rw(FUNC(dp83932c_device::rcr_r), FUNC(dp83932c_device::rcr_w));
|
||||
map(0x03 << shift, (0x03 << shift) | 0x01).rw(FUNC(dp83932c_device::tcr_r), FUNC(dp83932c_device::tcr_w));
|
||||
//map(0x04 << shift, (0x04 << shift) | 0x01).rw(FUNC(dp83932c_device::imr_r), FUNC(dp83932c_device::imr_w));
|
||||
map(0x05 << shift, (0x05 << shift) | 0x01).rw(FUNC(dp83932c_device::isr_r), FUNC(dp83932c_device::isr_w));
|
||||
|
||||
// transmit registers
|
||||
map(0x06 << shift, (0x06 << shift) | 0x01).rw(FUNC(dp83932c_device::utda_r), FUNC(dp83932c_device::utda_w));
|
||||
//map(0x07 << shift, (0x07 << shift) | 0x01).rw(FUNC(dp83932c_device::ctda_r), FUNC(dp83932c_device::ctda_w));
|
||||
|
||||
// tps
|
||||
// tfc
|
||||
// tsa0
|
||||
// tsa1
|
||||
// tfs
|
||||
|
||||
// receive registers
|
||||
//map(0x0d << shift, (0x0d << shift) | 0x01).rw(FUNC(dp83932c_device::urda_r), FUNC(dp83932c_device::urda_w));
|
||||
map(0x0e << shift, (0x0e << shift) | 0x01).rw(FUNC(dp83932c_device::crda_r), FUNC(dp83932c_device::crda_w));
|
||||
|
||||
// crba0
|
||||
// crba1
|
||||
// rbwc0
|
||||
// rbwc1
|
||||
// eobc
|
||||
// urra
|
||||
// rsa
|
||||
// rea
|
||||
map(0x17 << shift, (0x17 << shift) | 0x01).rw(FUNC(dp83932c_device::rrp_r), FUNC(dp83932c_device::rrp_w));
|
||||
map(0x18 << shift, (0x18 << shift) | 0x01).rw(FUNC(dp83932c_device::rwp_r), FUNC(dp83932c_device::rwp_w));
|
||||
// trba0
|
||||
// trba1
|
||||
// tbwc0
|
||||
// tbwc1
|
||||
// addr0
|
||||
// addr1
|
||||
// llfa
|
||||
// ttda
|
||||
// cep
|
||||
// cap2
|
||||
// cap1
|
||||
// cap0
|
||||
map(0x25 << shift, (0x25 << shift) | 0x01).rw(FUNC(dp83932c_device::ce_r), FUNC(dp83932c_device::ce_w));
|
||||
// cdp
|
||||
// cdc
|
||||
// sr
|
||||
map(0x29 << shift, (0x29 << shift) | 0x01).rw(FUNC(dp83932c_device::wt0_r), FUNC(dp83932c_device::wt0_w));
|
||||
map(0x2a << shift, (0x2a << shift) | 0x01).rw(FUNC(dp83932c_device::wt1_r), FUNC(dp83932c_device::wt1_w));
|
||||
map(0x2b << shift, (0x2b << shift) | 0x01).rw(FUNC(dp83932c_device::rsc_r), FUNC(dp83932c_device::rsc_w));
|
||||
// crct
|
||||
map(0x2d << shift, (0x2d << shift) | 0x01).rw(FUNC(dp83932c_device::faet_r), FUNC(dp83932c_device::faet_w));
|
||||
// mpt
|
||||
// mdt
|
||||
|
||||
// 30-3e internal use registers
|
||||
// dcr2
|
||||
map(0x00, 0x7f).rw(FUNC(dp83932c_device::reg_r), FUNC(dp83932c_device::reg_w));
|
||||
}
|
||||
|
||||
void dp83932c_device::device_start()
|
||||
{
|
||||
m_out_int.resolve();
|
||||
|
||||
m_command = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(dp83932c_device::command), this));
|
||||
|
||||
save_item(NAME(m_int_state));
|
||||
save_item(NAME(m_reg));
|
||||
save_item(NAME(m_cam));
|
||||
|
||||
for (u16 ® : m_reg)
|
||||
reg = 0;
|
||||
|
||||
m_reg[SR] = 6; // silicon revision for DP83932CVF
|
||||
}
|
||||
|
||||
void dp83932c_device::device_reset()
|
||||
{
|
||||
m_cr = RST | STP | RXDIS;
|
||||
m_tcr = NCRS | PTX;
|
||||
m_isr = 0;
|
||||
m_ce = 0;
|
||||
m_rsc = 0;
|
||||
}
|
||||
m_reg[CR] = CR_RST | CR_STP | CR_RXDIS;
|
||||
m_reg[DCR] &= ~(DCR_EXBUS | DCR_LBR); // TODO: sample USR1,0
|
||||
m_reg[RCR] &= ~(RCR_RNT | RCR_BRD | RCR_LB);
|
||||
m_reg[TCR] |= TCR_NCRS | TCR_PTX;
|
||||
m_reg[TCR] &= ~(TCR_TPC | TCR_BCM);
|
||||
m_reg[IMR] = 0;
|
||||
m_reg[ISR] = 0;
|
||||
m_reg[EOBC] = 0x02f8;
|
||||
m_reg[CE] = 0;
|
||||
m_reg[RSC] = 0;
|
||||
m_reg[DCR2] = 0;
|
||||
|
||||
void dp83932c_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
}
|
||||
|
||||
void dp83932c_device::send_complete_cb(int result)
|
||||
{
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
int dp83932c_device::recv_start_cb(u8 *buf, int length)
|
||||
{
|
||||
return 0;
|
||||
unsigned const width = (m_reg[DCR] & DCR_DW) ? 4 : 2;
|
||||
|
||||
if (!(m_reg[CR] & CR_RXEN))
|
||||
return -1;
|
||||
|
||||
m_reg[RCR] &= ~(RCR_MC | RCR_BC | RCR_LPKT | RCR_CRCR | RCR_FAER | RCR_LBK | RCR_PRX);
|
||||
|
||||
// address filter
|
||||
if (!address_filter(buf))
|
||||
return -1;
|
||||
|
||||
if ((length < 64) && !(m_reg[RCR] & RCR_RNT))
|
||||
return -1;
|
||||
|
||||
u32 const fcs = util::crc32_creator::simple(buf, length);
|
||||
if (~fcs != FCS_RESIDUE)
|
||||
{
|
||||
if (m_reg[RCR] & RCR_ERR)
|
||||
m_reg[RCR] |= RCR_CRCR;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
m_reg[RCR] |= RCR_PRX;
|
||||
|
||||
LOG("recv_start_cb %d\n", length);
|
||||
|
||||
// loopback
|
||||
if (m_reg[RCR] & RCR_LB)
|
||||
m_reg[RCR] |= RCR_LBK;
|
||||
|
||||
dump_bytes(buf, length);
|
||||
|
||||
if (m_reg[CRDA] & 1)
|
||||
{
|
||||
// re-read the previous descriptor link field
|
||||
m_reg[CRDA] = m_bus->read_word(EA(m_reg[URDA], m_reg[LLFA]));
|
||||
if (m_reg[CRDA] & 1)
|
||||
{
|
||||
logerror("no receive descriptor available\n");
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
// save rba pointer registers
|
||||
m_reg[TRBA0] = m_reg[CRBA0];
|
||||
m_reg[TRBA1] = m_reg[CRBA1];
|
||||
m_reg[TBWC0] = m_reg[RBWC0];
|
||||
m_reg[TBWC1] = m_reg[RBWC1];
|
||||
|
||||
// store data to rba
|
||||
// TODO: word/dword transfers (allow unaligned)
|
||||
// TODO: pad to word/dword size with 0xff
|
||||
// TODO: check for buffer overflow
|
||||
offs_t const rba = EA(m_reg[CRBA1], m_reg[CRBA0]);
|
||||
for (unsigned i = 0; i < length; i++)
|
||||
m_bus->write_byte(rba + i, buf[i]);
|
||||
|
||||
// update remaining buffer word count
|
||||
u32 const rbwc = ((u32(m_reg[RBWC1]) << 16) | m_reg[RBWC0]) - (length + 1) / 2;
|
||||
m_reg[RBWC1] = rbwc >> 16;
|
||||
m_reg[RBWC0] = u16(rbwc);
|
||||
|
||||
if (rbwc < m_reg[EOBC])
|
||||
m_reg[RCR] |= RCR_LPKT;
|
||||
|
||||
// write status to rda
|
||||
// TODO: don't write the rda if rba limit exceeded (buffer overflow)
|
||||
offs_t const rda = EA(m_reg[URDA], m_reg[CRDA]);
|
||||
m_bus->write_word(rda + 0 * width, m_reg[RCR]);
|
||||
m_bus->write_word(rda + 1 * width, length);
|
||||
m_bus->write_word(rda + 2 * width, m_reg[CRBA0]);
|
||||
m_bus->write_word(rda + 3 * width, m_reg[CRBA1]);
|
||||
m_bus->write_word(rda + 4 * width, m_reg[RSC]);
|
||||
m_reg[LLFA] = m_reg[CRDA] + 5 * width;
|
||||
m_reg[CRDA] = m_bus->read_word(rda + 5 * width);
|
||||
|
||||
// check for end of list
|
||||
if (m_reg[CRDA] & 1)
|
||||
m_reg[ISR] |= ISR_RDE;
|
||||
else
|
||||
m_bus->write_word(rda + 6 * width, 0);
|
||||
|
||||
// handle buffer exhaustion
|
||||
if (rbwc < m_reg[EOBC])
|
||||
read_rra();
|
||||
else
|
||||
m_reg[RSC] = (m_reg[RSC] & 0xff00) | u8(m_reg[RSC] + 1);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void dp83932c_device::recv_complete_cb(int result)
|
||||
{
|
||||
if (result > 0)
|
||||
{
|
||||
m_reg[ISR] |= ISR_PKTRX;
|
||||
update_interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
void dp83932c_device::reg_w(offs_t offset, u16 data)
|
||||
{
|
||||
LOG("reg_w register %s data 0x%04x (%s)\n", regname[offset], data, machine().describe_context());
|
||||
|
||||
// TODO: can only write during reset: DCR, DCR2
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
case CR:
|
||||
if (m_reg[CR] & CR_RST)
|
||||
{
|
||||
if (!(data & CR_RST))
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "exit software reset\n");
|
||||
|
||||
m_reg[CR] &= ~CR_RST;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (data & CR_RST)
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "enter software reset\n");
|
||||
|
||||
m_command->adjust(attotime::never);
|
||||
|
||||
m_reg[CR] &= ~(CR_LCAM | CR_RRRA | CR_TXP | CR_HTX);
|
||||
m_reg[CR] |= (CR_RST | CR_RXDIS);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_reg[offset] |= data & regmask[offset];
|
||||
m_command->adjust(attotime::zero, data & regmask[offset]);
|
||||
break;
|
||||
|
||||
case RCR:
|
||||
m_reg[offset] = (m_reg[offset] & ~regmask[offset]) | (data & regmask[offset]);
|
||||
set_loopback(bool(m_reg[offset] & RCR_LB));
|
||||
break;
|
||||
|
||||
case IMR:
|
||||
m_reg[offset] = (m_reg[offset] & ~regmask[offset]) | (data & regmask[offset]);
|
||||
update_interrupts();
|
||||
break;
|
||||
|
||||
case ISR:
|
||||
m_reg[offset] &= ~(data & regmask[offset]);
|
||||
// TODO: reload rra after RBE cleared
|
||||
update_interrupts();
|
||||
break;
|
||||
|
||||
case CRCT:
|
||||
case FAET:
|
||||
case MPT:
|
||||
// inverted
|
||||
m_reg[offset] = ~data;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (regmask[offset])
|
||||
m_reg[offset] = (m_reg[offset] & ~regmask[offset]) | (data & regmask[offset]);
|
||||
else
|
||||
logerror("write to read-only register %s data 0x%04x (%s)\n",
|
||||
regname[offset], data, machine().describe_context());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void dp83932c_device::command(void *ptr, s32 param)
|
||||
{
|
||||
if (param & CR_HTX)
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "halt transmission\n");
|
||||
m_reg[CR] &= ~CR_TXP;
|
||||
}
|
||||
|
||||
if (param & CR_TXP)
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "transmit\n");
|
||||
m_reg[CR] &= ~CR_HTX;
|
||||
|
||||
transmit();
|
||||
}
|
||||
|
||||
if (param & CR_RXDIS)
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "receiver disable\n");
|
||||
m_reg[CR] &= ~CR_RXEN;
|
||||
}
|
||||
|
||||
if (param & CR_RXEN)
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "receiver enable\n");
|
||||
m_reg[CR] &= ~CR_RXDIS;
|
||||
}
|
||||
|
||||
if (param & CR_STP)
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "stop timer\n");
|
||||
m_reg[CR] &= ~CR_ST;
|
||||
}
|
||||
|
||||
if (param & CR_ST)
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "start timer\n");
|
||||
m_reg[CR] &= ~CR_STP;
|
||||
}
|
||||
|
||||
if (param & CR_RRRA)
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "read rra\n");
|
||||
read_rra(true);
|
||||
}
|
||||
|
||||
if (param & CR_LCAM)
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "load cam\n");
|
||||
load_cam();
|
||||
}
|
||||
|
||||
update_interrupts();
|
||||
}
|
||||
|
||||
void dp83932c_device::transmit()
|
||||
{
|
||||
unsigned const width = (m_reg[DCR] & DCR_DW) ? 4 : 2;
|
||||
|
||||
m_reg[TTDA] = m_reg[CTDA];
|
||||
offs_t const tda = EA(m_reg[UTDA], m_reg[CTDA]);
|
||||
unsigned word = 1;
|
||||
|
||||
// read control information from tda and load registers
|
||||
u16 const tcr = m_reg[TCR];
|
||||
m_reg[TCR] = m_bus->read_word(tda + word++ * width) & TCR_TPC;
|
||||
m_reg[TPS] = m_bus->read_word(tda + word++ * width);
|
||||
m_reg[TFC] = m_bus->read_word(tda + word++ * width);
|
||||
|
||||
// check for programmable interrupt
|
||||
if ((m_reg[TCR] & TCR_PINT) && !(tcr & TCR_PINT))
|
||||
m_reg[ISR] |= ISR_PINT;
|
||||
|
||||
// FIXME: abort if tps > buffer size
|
||||
u8 buf[1520];
|
||||
unsigned length = 0;
|
||||
|
||||
// read fragments into buffer
|
||||
for (unsigned fragment = 0; fragment < m_reg[TFC]; fragment++)
|
||||
{
|
||||
// read fragment address and size
|
||||
m_reg[TSA0] = m_bus->read_word(tda + word++ * width);
|
||||
m_reg[TSA1] = m_bus->read_word(tda + word++ * width);
|
||||
m_reg[TFS] = m_bus->read_word(tda + word++ * width);
|
||||
|
||||
offs_t const tsa = EA(m_reg[TSA1], m_reg[TSA0]);
|
||||
|
||||
// FIXME: word/dword transfers (allow unaligned)
|
||||
for (unsigned byte = 0; byte < m_reg[TFS]; byte++)
|
||||
buf[length++] = m_bus->read_byte(tsa + byte);
|
||||
}
|
||||
|
||||
// append fcs if not inhibited
|
||||
if (!(m_reg[TCR] & TCR_CRCI))
|
||||
{
|
||||
u32 const crc = util::crc32_creator::simple(buf, length);
|
||||
|
||||
// insert the fcs
|
||||
buf[length++] = crc >> 0;
|
||||
buf[length++] = crc >> 8;
|
||||
buf[length++] = crc >> 16;
|
||||
buf[length++] = crc >> 24;
|
||||
}
|
||||
|
||||
// advance ctda to the link field
|
||||
m_reg[CTDA] += word * width;
|
||||
|
||||
// transmit data
|
||||
dump_bytes(buf, length);
|
||||
send(buf, length);
|
||||
}
|
||||
|
||||
void dp83932c_device::send_complete_cb(int result)
|
||||
{
|
||||
// TODO: errors
|
||||
if (result > 0)
|
||||
{
|
||||
// TODO: number of collisions
|
||||
|
||||
m_reg[TCR] |= TCR_PTX;
|
||||
}
|
||||
|
||||
// write descriptor status
|
||||
m_bus->write_word(EA(m_reg[UTDA], m_reg[TTDA]), m_reg[TCR] & TCR_TPS);
|
||||
|
||||
// check for halt
|
||||
if (!(m_reg[CR] & CR_HTX))
|
||||
{
|
||||
// load next descriptor address
|
||||
m_reg[CTDA] = m_bus->read_word(EA(m_reg[UTDA], m_reg[CTDA]));
|
||||
|
||||
// check for end of list
|
||||
if (m_reg[CTDA] & 1)
|
||||
{
|
||||
m_reg[ISR] |= ISR_TXDN;
|
||||
m_reg[CR] &= ~CR_TXP;
|
||||
|
||||
update_interrupts();
|
||||
}
|
||||
else
|
||||
// transmit next packet
|
||||
if (m_command->enabled())
|
||||
m_command->set_param(m_command->param() | CR_TXP);
|
||||
else
|
||||
m_command->adjust(attotime::zero, CR_TXP);
|
||||
}
|
||||
else
|
||||
m_reg[CR] &= ~CR_TXP;
|
||||
}
|
||||
|
||||
void dp83932c_device::read_rra(bool command)
|
||||
{
|
||||
unsigned const width = (m_reg[DCR] & DCR_DW) ? 4 : 2;
|
||||
|
||||
offs_t const rrp = EA(m_reg[URRA], m_reg[RRP]);
|
||||
|
||||
m_reg[CRBA0] = m_bus->read_word(rrp + 0 * width);
|
||||
m_reg[CRBA1] = m_bus->read_word(rrp + 1 * width);
|
||||
m_reg[RBWC0] = m_bus->read_word(rrp + 2 * width);
|
||||
m_reg[RBWC1] = m_bus->read_word(rrp + 3 * width);
|
||||
|
||||
LOG("read_rra crba 0x%08x rbwc 0x%08x\n",
|
||||
EA(m_reg[CRBA1], m_reg[CRBA0]), EA(m_reg[RBWC1], m_reg[RBWC0]));
|
||||
|
||||
// advance rrp
|
||||
m_reg[RRP] += 4 * width;
|
||||
|
||||
// check for wrapping and resource exhaustion
|
||||
if (m_reg[RRP] == m_reg[REA])
|
||||
m_reg[RRP] = m_reg[RSA];
|
||||
|
||||
if (m_reg[RRP] == m_reg[RWP])
|
||||
m_reg[ISR] |= ISR_RBE;
|
||||
|
||||
if (command)
|
||||
m_reg[CR] &= ~CR_RRRA;
|
||||
else
|
||||
m_reg[RSC] = (m_reg[RSC] & 0xff00) + 0x100;
|
||||
}
|
||||
|
||||
void dp83932c_device::load_cam()
|
||||
{
|
||||
unsigned const width = (m_reg[DCR] & DCR_DW) ? 4 : 2;
|
||||
|
||||
while (m_reg[CDC])
|
||||
{
|
||||
offs_t const cdp = EA(m_reg[URRA], m_reg[CDP]);
|
||||
|
||||
u16 const cep = m_bus->read_word(cdp + 0 * width) & 0xf;
|
||||
u16 const cap0 = m_bus->read_word(cdp + 1 * width);
|
||||
u16 const cap1 = m_bus->read_word(cdp + 2 * width);
|
||||
u16 const cap2 = m_bus->read_word(cdp + 3 * width);
|
||||
|
||||
// FIXME: documented byte/word order doesn't match emulation
|
||||
|
||||
LOG("load_cam entry %2d %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
cep, u8(cap0), cap0 >> 8, u8(cap1), cap1 >> 8, u8(cap2), cap2 >> 8);
|
||||
|
||||
m_cam[cep] =
|
||||
(u64(u8(cap0 >> 0)) << 40) | (u64(u8(cap0 >> 8)) << 32) | (u64(u8(cap1 >> 0)) << 24) |
|
||||
(u64(u8(cap1 >> 8)) << 16) | (u64(u8(cap2 >> 0)) << 8) | (u64(u8(cap2 >> 8)) << 0);
|
||||
|
||||
m_reg[CDP] += 4 * width;
|
||||
m_reg[CDC]--;
|
||||
}
|
||||
|
||||
// read cam enable
|
||||
m_reg[CE] = m_bus->read_word(EA(m_reg[URRA], m_reg[CDP]));
|
||||
LOG("load_cam enable 0x%04x\n", m_reg[CE]);
|
||||
|
||||
m_reg[CR] &= ~CR_LCAM;
|
||||
m_reg[ISR] |= ISR_LCD;
|
||||
}
|
||||
|
||||
void dp83932c_device::update_interrupts()
|
||||
{
|
||||
bool const int_state = bool(m_reg[ISR] & m_reg[IMR]);
|
||||
|
||||
if (int_state != m_int_state)
|
||||
{
|
||||
m_int_state = int_state;
|
||||
m_out_int(m_int_state);
|
||||
}
|
||||
}
|
||||
|
||||
bool dp83932c_device::address_filter(u8 *buf)
|
||||
{
|
||||
if (m_reg[RCR] & RCR_PRO)
|
||||
{
|
||||
LOGMASKED(LOG_FILTER, "address_filter accepted (promiscuous)\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 const address =
|
||||
(u64(buf[0]) << 40) | (u64(buf[1]) << 32) | (u64(buf[2]) << 24) |
|
||||
(u64(buf[3]) << 16) | (u64(buf[4]) << 8) | (u64(buf[5]) << 0);
|
||||
|
||||
// broadcast
|
||||
if ((address == 0xffff'ffffffffULL) && (m_reg[RCR] & (RCR_AMC | RCR_BRD)))
|
||||
{
|
||||
LOGMASKED(LOG_FILTER, "address_filter accepted (broadcast) %02x-%02x-%02x-%02x-%02x-%02x\n",
|
||||
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
|
||||
|
||||
m_reg[RCR] |= RCR_BC;
|
||||
return true;
|
||||
}
|
||||
|
||||
// multicast
|
||||
if ((address & 0x0100'00000000ULL) && (m_reg[RCR] & RCR_AMC))
|
||||
{
|
||||
LOGMASKED(LOG_FILTER, "address_filter accepted (multicast) %02x-%02x-%02x-%02x-%02x-%02x\n",
|
||||
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
|
||||
|
||||
m_reg[RCR] |= RCR_MC;
|
||||
return true;
|
||||
}
|
||||
|
||||
// content addressable memory
|
||||
for (unsigned i = 0; i < 16; i++)
|
||||
{
|
||||
if ((address == m_cam[i]) && BIT(m_reg[CE], i))
|
||||
{
|
||||
LOGMASKED(LOG_FILTER, "address_filter accepted (cam entry %d match) %02x-%02x-%02x-%02x-%02x-%02x\n",
|
||||
i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void dp83932c_device::dump_bytes(u8 *buf, int length)
|
||||
{
|
||||
if (VERBOSE & LOG_PACKETS)
|
||||
{
|
||||
// pad with zeros to 8-byte boundary
|
||||
for (int i = 0; i < 8 - (length % 8); i++)
|
||||
buf[length + i] = 0;
|
||||
|
||||
// dump length / 8 (rounded up) groups of 8 bytes
|
||||
for (int i = 0; i < (length + 7) / 8; i++)
|
||||
LOGMASKED(LOG_PACKETS, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
buf[i * 8 + 0], buf[i * 8 + 1], buf[i * 8 + 2], buf[i * 8 + 3],
|
||||
buf[i * 8 + 4], buf[i * 8 + 5], buf[i * 8 + 6], buf[i * 8 + 7]);
|
||||
}
|
||||
}
|
||||
|
@ -6,111 +6,207 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "machine/ram.h"
|
||||
|
||||
class dp83932c_device
|
||||
: public device_t
|
||||
, public device_network_interface
|
||||
{
|
||||
public:
|
||||
dp83932c_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
static constexpr feature_type imperfect_features() { return feature::LAN; }
|
||||
dp83932c_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||
|
||||
// configuration
|
||||
template <typename T> void set_ram(T &&tag) { m_ram.set_tag(std::forward<T>(tag)); }
|
||||
template <typename T> void set_bus(T &&tag, int spacenum) { m_bus.set_tag(std::forward<T>(tag), spacenum); }
|
||||
auto out_int_cb() { return m_out_int.bind(); }
|
||||
|
||||
// external interface
|
||||
void map(address_map &map);
|
||||
u16 reg_r(offs_t offset) { return m_reg[offset]; }
|
||||
void reg_w(offs_t offset, u16 data);
|
||||
|
||||
protected:
|
||||
// device_t overrides
|
||||
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;
|
||||
|
||||
// device_network_interface overrides
|
||||
virtual void send_complete_cb(int result) override;
|
||||
virtual int recv_start_cb(u8 *buf, int length) override;
|
||||
virtual void recv_complete_cb(int result) override;
|
||||
|
||||
// command helpers
|
||||
void command(void *ptr, s32 param);
|
||||
void transmit();
|
||||
void read_rra(bool command = false);
|
||||
void load_cam();
|
||||
void update_interrupts();
|
||||
bool address_filter(u8 *buf);
|
||||
|
||||
// diagnostic helper
|
||||
void dump_bytes(u8 *buf, int length);
|
||||
|
||||
enum registers : unsigned
|
||||
{
|
||||
CR = 0x00, // command
|
||||
DCR = 0x01, // data configuration
|
||||
RCR = 0x02, // receive control
|
||||
TCR = 0x03, // transmit control
|
||||
IMR = 0x04, // interrupt mask
|
||||
ISR = 0x05, // interrupt status
|
||||
UTDA = 0x06, // upper transmit descriptor address
|
||||
CTDA = 0x07, // current transmit descriptor address
|
||||
TPS = 0x08, // transmit packet size
|
||||
TFC = 0x09, // transmit fragment count
|
||||
TSA0 = 0x0a, // transmit start address 0
|
||||
TSA1 = 0x0b, // transmit start address 1
|
||||
TFS = 0x0c, // transmit fragment size
|
||||
URDA = 0x0d, // upper receive descriptor address
|
||||
CRDA = 0x0e, // current receive descriptor address
|
||||
CRBA0 = 0x0f, // current receive buffer address 0
|
||||
CRBA1 = 0x10, // current receive buffer address 1
|
||||
RBWC0 = 0x11, // remaining buffer word count 0
|
||||
RBWC1 = 0x12, // remaining buffer word count 1
|
||||
EOBC = 0x13, // end of buffer word count
|
||||
URRA = 0x14, // upper receive resource address
|
||||
RSA = 0x15, // resource start address
|
||||
REA = 0x16, // resource end address
|
||||
RRP = 0x17, // resource read pointer
|
||||
RWP = 0x18, // resource write pointer
|
||||
TRBA0 = 0x19, // temporary receive buffer address 0
|
||||
TRBA1 = 0x1a, // temporary receive buffer address 1
|
||||
TBWC0 = 0x1b, // temporary buffer word count 0
|
||||
TBWC1 = 0x1c, // temporary buffer word count 1
|
||||
ADDR0 = 0x1d, // address generator 0
|
||||
ADDR1 = 0x1e, // address generator 1
|
||||
LLFA = 0x1f, // last link field address
|
||||
TTDA = 0x20, // temporary transmit descriptor address
|
||||
CEP = 0x21, // cam entry pointer
|
||||
CAP2 = 0x22, // cam address port 2
|
||||
CAP1 = 0x23, // cam address port 1
|
||||
CAP0 = 0x24, // cam address port 0
|
||||
CE = 0x25, // cam enable
|
||||
CDP = 0x26, // cam descriptor pointer
|
||||
CDC = 0x27, // cam descriptor count
|
||||
SR = 0x28, // silicon revision
|
||||
WT0 = 0x29, // watchdog timer 0
|
||||
WT1 = 0x2a, // watchdog timer 1
|
||||
RSC = 0x2b, // receive sequence counter
|
||||
CRCT = 0x2c, // crc error tally
|
||||
FAET = 0x2d, // fae tally
|
||||
MPT = 0x2e, // missed packet tally
|
||||
MDT = 0x2f, // maximum deferral timer
|
||||
// factory use only
|
||||
DCR2 = 0x3f, // data configuration 2
|
||||
};
|
||||
|
||||
enum cr_mask : u16
|
||||
{
|
||||
HTX = 0x0001, // halt transmission
|
||||
TXP = 0x0002, // transmit packets
|
||||
RXDIS = 0x0004, // receiver disable
|
||||
RXEN = 0x0008, // receiver enable
|
||||
STP = 0x0010, // stop timer
|
||||
ST = 0x0020, // start timer
|
||||
RST = 0x0080, // software reset
|
||||
RRRA = 0x0100, // read rra
|
||||
LCAM = 0x0200, // load cam
|
||||
|
||||
CR_WMASK = 0x03bf
|
||||
CR_HTX = 0x0001, // halt transmission
|
||||
CR_TXP = 0x0002, // transmit packets
|
||||
CR_RXDIS = 0x0004, // receiver disable
|
||||
CR_RXEN = 0x0008, // receiver enable
|
||||
CR_STP = 0x0010, // stop timer
|
||||
CR_ST = 0x0020, // start timer
|
||||
CR_RST = 0x0080, // software reset
|
||||
CR_RRRA = 0x0100, // read rra
|
||||
CR_LCAM = 0x0200, // load cam
|
||||
};
|
||||
enum dcr_mask : u16
|
||||
{
|
||||
DCR_TFT = 0x0003, // transmit fifo threshold
|
||||
DCR_RFT = 0x000c, // receive fifo threshold
|
||||
DCR_BMS = 0x0010, // block mode select for dma
|
||||
DCR_DW = 0x0020, // data width select
|
||||
DCR_WC = 0x00c0, // wait state control
|
||||
DCR_USR = 0x0300, // user definable pins
|
||||
DCR_SBUS = 0x0400, // synchronous bus mode
|
||||
DCR_PO = 0x1800, // programmable outputs
|
||||
DCR_LBR = 0x2000, // latched bus retry
|
||||
DCR_EXBUS = 0x8000, // extended bus mode
|
||||
};
|
||||
enum rcr_mask : u16
|
||||
{
|
||||
RCR_PRX = 0x0001, // packet received ok
|
||||
RCR_LBK = 0x0002, // loopback packet received
|
||||
RCR_FAER = 0x0004, // frame alignment error
|
||||
RCR_CRCR = 0x0008, // crc error
|
||||
RCR_COL = 0x0010, // collision activity
|
||||
RCR_CRS = 0x0020, // carrier sense activity
|
||||
RCR_LPKT = 0x0040, // last packet in rba
|
||||
RCR_BC = 0x0080, // broadcast packet received
|
||||
RCR_MC = 0x0100, // multicast packet received
|
||||
RCR_LB = 0x0600, // loopback control
|
||||
RCR_AMC = 0x0800, // accept all multicast packets
|
||||
RCR_PRO = 0x1000, // physical promiscuous mode
|
||||
RCR_BRD = 0x2000, // accept broadcast packets
|
||||
RCR_RNT = 0x4000, // accept runt packets
|
||||
RCR_ERR = 0x8000, // accept packet with crc errors or collisions
|
||||
};
|
||||
|
||||
enum tcr_mask : u16
|
||||
{
|
||||
PTX = 0x0001, // packet transmitted ok
|
||||
BCM = 0x0002, // byte count mismatch
|
||||
FU = 0x0004, // fifo underrun
|
||||
PMB = 0x0008, // packet monitored bad
|
||||
OWC = 0x0020, // out of window collision
|
||||
EXC = 0x0040, // excessive collisions
|
||||
CRSL = 0x0080, // crs lost
|
||||
NCRS = 0x0100, // no crs
|
||||
DEF = 0x0200, // deferred transmission
|
||||
EXD = 0x0400, // excessive deferral
|
||||
EXDIS = 0x1000, // disable excessive deferral timer
|
||||
CRCI = 0x2000, // crc inhibit
|
||||
POWC = 0x4000, // programmed out of window collision timer
|
||||
PINT = 0x8000, // programmable interrupt
|
||||
TCR_PTX = 0x0001, // packet transmitted ok
|
||||
TCR_BCM = 0x0002, // byte count mismatch
|
||||
TCR_FU = 0x0004, // fifo underrun
|
||||
TCR_PMB = 0x0008, // packet monitored bad
|
||||
TCR_OWC = 0x0020, // out of window collision
|
||||
TCR_EXC = 0x0040, // excessive collisions
|
||||
TCR_CRSL = 0x0080, // crs lost
|
||||
TCR_NCRS = 0x0100, // no crs
|
||||
TCR_DEF = 0x0200, // deferred transmission
|
||||
TCR_EXD = 0x0400, // excessive deferral
|
||||
TCR_EXDIS = 0x1000, // disable excessive deferral timer
|
||||
TCR_CRCI = 0x2000, // crc inhibit
|
||||
TCR_POWC = 0x4000, // programmed out of window collision timer
|
||||
TCR_PINT = 0x8000, // programmable interrupt
|
||||
|
||||
TCR_WMASK = 0xf000
|
||||
TCR_TPC = 0xf000, // tx packet descriptor config
|
||||
TCR_TPS = 0x07ff, // tx packet descriptor status
|
||||
|
||||
};
|
||||
enum imr_mask : u16
|
||||
{
|
||||
IMR_RFOEN = 0x0001, // receive fifo overrun
|
||||
IMR_MPEN = 0x0002, // missed packet tally counter warning
|
||||
IMR_FAEEN = 0x0004, // frame alignment error tally counter warning
|
||||
IMR_CRCEN = 0x0008, // crc tally counter warning
|
||||
IMR_RBAEEN = 0x0010, // receive buffer area exceeded
|
||||
IMR_RBEEN = 0x0020, // receive buffers exhausted
|
||||
IMR_RDEEN = 0x0040, // receive descriptors exhausted
|
||||
IMR_TCEN = 0x0080, // general purpose timer complete
|
||||
IMR_TXEREN = 0x0100, // transmit error
|
||||
IMR_PTXEN = 0x0200, // packet transmitted ok
|
||||
IMR_PRXEN = 0x0400, // packet received
|
||||
IMR_PINTEN = 0x0800, // programmable interrupt
|
||||
IMR_LCDEN = 0x1000, // load cam done
|
||||
IMR_HBLEN = 0x2000, // heartbeat lost
|
||||
IMR_BREN = 0x4000, // bus retry occurred
|
||||
};
|
||||
enum isr_mask : u16
|
||||
{
|
||||
ISR_RFO = 0x0001, // receive fifo overrun
|
||||
ISR_MP = 0x0002, // missed packet counter rollover
|
||||
ISR_FAE = 0x0004, // frame alignment error tally counter rollover
|
||||
ISR_CRC = 0x0008, // crc tally counter rollover
|
||||
ISR_RBAE = 0x0010, // receive buffer area exceeded
|
||||
ISR_RBE = 0x0020, // receive buffer exhausted
|
||||
ISR_RDE = 0x0040, // receive descriptors exhausted
|
||||
ISR_TC = 0x0080, // general purpose timer complete
|
||||
ISR_TXER = 0x0100, // transmit error
|
||||
ISR_TXDN = 0x0200, // transmission done
|
||||
ISR_PKTRX = 0x0400, // packet received
|
||||
ISR_PINT = 0x0800, // programmed interrupt
|
||||
ISR_LCD = 0x1000, // load cam done
|
||||
ISR_HBL = 0x2000, // cd heartbeat lost
|
||||
ISR_BR = 0x4000, // bus retry occurred
|
||||
};
|
||||
|
||||
u16 cr_r() { return m_cr; }
|
||||
u16 tcr_r() { return m_tcr; }
|
||||
u16 utda_r() { return m_utda; }
|
||||
u16 crda_r() { return m_crda; }
|
||||
u16 rrp_r() { return m_rrp; }
|
||||
u16 rwp_r() { return m_rwp; }
|
||||
u16 isr_r() { return m_isr; }
|
||||
u16 ce_r() { return m_ce; }
|
||||
u16 wt0_r() { return m_wt0; }
|
||||
u16 wt1_r() { return m_wt1; }
|
||||
u16 rsc_r() { return m_rsc; }
|
||||
u16 faet_r() { return m_faet; }
|
||||
|
||||
void cr_w(u16 data) { m_cr = (data & CR_WMASK) | (m_cr & ~CR_WMASK); }
|
||||
void tcr_w(u16 data) { m_tcr = (data & TCR_WMASK) | (m_tcr & ~TCR_WMASK); }
|
||||
void utda_w(u16 data) { m_utda = data; }
|
||||
void crda_w(u16 data) { m_crda = data; }
|
||||
void rrp_w(u16 data) { m_rrp = data; }
|
||||
void rwp_w(u16 data) { m_rwp = data; }
|
||||
void isr_w(u16 data) { m_isr = data; }
|
||||
void ce_w(u16 data) { m_ce = data; }
|
||||
void wt0_w(u16 data) { m_wt0 = data; }
|
||||
void wt1_w(u16 data) { m_wt1 = data; }
|
||||
void rsc_w(u16 data) { m_rsc = data; }
|
||||
void faet_w(u16 data) { m_faet = ~data; }
|
||||
|
||||
private:
|
||||
required_device<ram_device> m_ram;
|
||||
|
||||
required_address_space m_bus;
|
||||
devcb_write_line m_out_int;
|
||||
|
||||
u16 m_cr;
|
||||
u16 m_tcr;
|
||||
u16 m_utda;
|
||||
u16 m_crda;
|
||||
u16 m_rrp;
|
||||
u16 m_rwp;
|
||||
u16 m_isr;
|
||||
u16 m_ce;
|
||||
u16 m_wt0;
|
||||
u16 m_wt1;
|
||||
u16 m_rsc;
|
||||
u16 m_faet;
|
||||
emu_timer *m_command;
|
||||
|
||||
bool m_int_state;
|
||||
u16 m_reg[64];
|
||||
u64 m_cam[16];
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(DP83932C, dp83932c_device)
|
||||
|
@ -135,7 +135,7 @@ void jazz_state::jazz_common_map(address_map &map)
|
||||
map(0x60080000, 0x60081fff).m(m_cvc, FUNC(g364_device::map));
|
||||
map(0x60180000, 0x60180007).lw32([this] (u32 data) { m_cvc->reset(); }, "g364_reset");
|
||||
|
||||
map(0x80000000, 0x80000fff).m(m_mct_adr, FUNC(jazz_mct_adr_device::map));
|
||||
map(0x80000000, 0x80000fff).m(m_mct_adr, FUNC(mct_adr_device::map));
|
||||
|
||||
map(0x80001000, 0x800010ff).m(m_net, FUNC(dp83932c_device::map)).umask32(0x0000ffff);
|
||||
map(0x80002000, 0x8000200f).m(m_scsi, FUNC(ncr53c94_device::map));
|
||||
@ -185,8 +185,8 @@ void jazz_state::jazz_common_map(address_map &map)
|
||||
//map(0x92000000, 0x92ffffff).m(); // EISA I/O ports?
|
||||
//map(0x93000000, 0x93ffffff).m(); // EISA memory
|
||||
|
||||
map(0xf0000000, 0xf0000007).r(m_mct_adr, FUNC(jazz_mct_adr_device::isr_r)).umask64(0xffff);
|
||||
map(0xf0000000, 0xf0000007).rw(m_mct_adr, FUNC(jazz_mct_adr_device::imr_r), FUNC(jazz_mct_adr_device::imr_w)).umask64(0xffff0000);
|
||||
map(0xf0000000, 0xf0000007).r(m_mct_adr, FUNC(mct_adr_device::isr_r)).umask64(0xffff);
|
||||
map(0xf0000000, 0xf0000007).rw(m_mct_adr, FUNC(mct_adr_device::imr_r), FUNC(mct_adr_device::imr_w)).umask64(0xffff0000);
|
||||
|
||||
map(0xfff00000, 0xfff3ffff).r(m_flash, FUNC(amd_28f020_device::read)); // mirror?
|
||||
}
|
||||
@ -217,7 +217,7 @@ void jazz_state::jazz(machine_config &config)
|
||||
m_vram->set_default_value(0);
|
||||
|
||||
// local bus dma, timer and interrupt controller
|
||||
JAZZ_MCT_ADR(config, m_mct_adr, 0);
|
||||
MCT_ADR(config, m_mct_adr, 0);
|
||||
m_mct_adr->set_bus(m_cpu, 0);
|
||||
m_mct_adr->out_int_dma_cb().set_inputline(m_cpu, INPUT_LINE_IRQ0);
|
||||
m_mct_adr->out_int_device_cb().set_inputline(m_cpu, INPUT_LINE_IRQ1);
|
||||
@ -240,17 +240,17 @@ void jazz_state::jazz(machine_config &config)
|
||||
{
|
||||
ncr53c94_device &adapter = downcast<ncr53c94_device &>(*device);
|
||||
|
||||
adapter.irq_handler_cb().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<5>));;
|
||||
adapter.drq_handler_cb().set(m_mct_adr, FUNC(jazz_mct_adr_device::drq<0>));
|
||||
adapter.irq_handler_cb().set(m_mct_adr, FUNC(mct_adr_device::irq<5>));;
|
||||
adapter.drq_handler_cb().set(m_mct_adr, FUNC(mct_adr_device::drq<0>));
|
||||
|
||||
subdevice<jazz_mct_adr_device>(":mct_adr")->dma_r_cb<0>().set(adapter, FUNC(ncr53c94_device::dma_r));
|
||||
subdevice<jazz_mct_adr_device>(":mct_adr")->dma_w_cb<0>().set(adapter, FUNC(ncr53c94_device::dma_w));
|
||||
subdevice<mct_adr_device>(":mct_adr")->dma_r_cb<0>().set(adapter, FUNC(ncr53c94_device::dma_r));
|
||||
subdevice<mct_adr_device>(":mct_adr")->dma_w_cb<0>().set(adapter, FUNC(ncr53c94_device::dma_w));
|
||||
});
|
||||
|
||||
// floppy controller and drive
|
||||
N82077AA(config, m_fdc, 24_MHz_XTAL);
|
||||
m_fdc->intrq_wr_callback().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<1>));
|
||||
m_fdc->drq_wr_callback().set(m_mct_adr, FUNC(jazz_mct_adr_device::drq<1>));
|
||||
m_fdc->intrq_wr_callback().set(m_mct_adr, FUNC(mct_adr_device::irq<1>));
|
||||
m_fdc->drq_wr_callback().set(m_mct_adr, FUNC(mct_adr_device::drq<1>));
|
||||
FLOPPY_CONNECTOR(config, "fdc:0", "35hd", FLOPPY_35_HD, true, jazz_state::floppy_formats).enable_sound(false);
|
||||
m_mct_adr->dma_r_cb<1>().set(m_fdc, FUNC(n82077aa_device::dma_r));
|
||||
m_mct_adr->dma_w_cb<1>().set(m_fdc, FUNC(n82077aa_device::dma_w));
|
||||
@ -283,18 +283,18 @@ void jazz_state::jazz(machine_config &config)
|
||||
// keyboard controller
|
||||
PS2_KEYBOARD_CONTROLLER(config, m_kbdc, 12_MHz_XTAL);
|
||||
// FIXME: reset is probably routed through the MCT-ADR
|
||||
m_kbdc->hot_res().set([this](int state) { logerror("reset %d\n", state); });
|
||||
m_kbdc->hot_res().set([this](int state) { machine().schedule_soft_reset(); });
|
||||
m_kbdc->kbd_clk().set(kbd_con, FUNC(pc_kbdc_device::clock_write_from_mb));
|
||||
m_kbdc->kbd_data().set(kbd_con, FUNC(pc_kbdc_device::data_write_from_mb));
|
||||
m_kbdc->kbd_irq().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<6>));
|
||||
m_kbdc->kbd_irq().set(m_mct_adr, FUNC(mct_adr_device::irq<6>));
|
||||
m_kbdc->aux_clk().set(aux_con, FUNC(pc_kbdc_device::clock_write_from_mb));
|
||||
m_kbdc->aux_data().set(aux_con, FUNC(pc_kbdc_device::data_write_from_mb));
|
||||
m_kbdc->aux_irq().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<7>));
|
||||
m_kbdc->aux_irq().set(m_mct_adr, FUNC(mct_adr_device::irq<7>));
|
||||
|
||||
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
|
||||
m_screen->set_raw(78643200, 1280, 0, 1280, 1024, 0, 1024);
|
||||
m_screen->set_screen_update(m_cvc, FUNC(g364_device::screen_update));
|
||||
m_screen->screen_vblank().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<3>)); // maybe?
|
||||
m_screen->screen_vblank().set(m_mct_adr, FUNC(mct_adr_device::irq<3>)); // maybe?
|
||||
|
||||
G364(config, m_cvc, 5_MHz_XTAL); // FIXME: guessed clock
|
||||
m_cvc->set_screen(m_screen);
|
||||
@ -307,7 +307,7 @@ void jazz_state::jazz(machine_config &config)
|
||||
m_ace[0]->out_dtr_callback().set(serial0, FUNC(rs232_port_device::write_dtr));
|
||||
m_ace[0]->out_rts_callback().set(serial0, FUNC(rs232_port_device::write_rts));
|
||||
m_ace[0]->out_tx_callback().set(serial0, FUNC(rs232_port_device::write_txd));
|
||||
m_ace[0]->out_int_callback().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<8>));
|
||||
m_ace[0]->out_int_callback().set(m_mct_adr, FUNC(mct_adr_device::irq<8>));
|
||||
|
||||
serial0.cts_handler().set(m_ace[0], FUNC(ns16550_device::cts_w));
|
||||
serial0.dcd_handler().set(m_ace[0], FUNC(ns16550_device::dcd_w));
|
||||
@ -321,7 +321,7 @@ void jazz_state::jazz(machine_config &config)
|
||||
m_ace[1]->out_dtr_callback().set(serial1, FUNC(rs232_port_device::write_dtr));
|
||||
m_ace[1]->out_rts_callback().set(serial1, FUNC(rs232_port_device::write_rts));
|
||||
m_ace[1]->out_tx_callback().set(serial1, FUNC(rs232_port_device::write_txd));
|
||||
m_ace[1]->out_int_callback().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<9>));
|
||||
m_ace[1]->out_int_callback().set(m_mct_adr, FUNC(mct_adr_device::irq<9>));
|
||||
|
||||
serial1.cts_handler().set(m_ace[1], FUNC(ns16550_device::cts_w));
|
||||
serial1.dcd_handler().set(m_ace[1], FUNC(ns16550_device::dcd_w));
|
||||
@ -330,7 +330,7 @@ void jazz_state::jazz(machine_config &config)
|
||||
serial1.rxd_handler().set(m_ace[1], FUNC(ns16550_device::rx_w));
|
||||
|
||||
PC_LPT(config, m_lpt, 0);
|
||||
m_lpt->irq_handler().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<0>));
|
||||
m_lpt->irq_handler().set(m_mct_adr, FUNC(mct_adr_device::irq<0>));
|
||||
|
||||
// TODO: sound, interrupt 2, drq 2(l) & 3(r)
|
||||
|
||||
@ -340,8 +340,8 @@ void jazz_state::jazz(machine_config &config)
|
||||
m_buzzer->add_route(ALL_OUTPUTS, "mono", 0.50);
|
||||
|
||||
DP83932C(config, m_net, 20_MHz_XTAL);
|
||||
m_net->out_int_cb().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<4>));
|
||||
m_net->set_ram(m_ram);
|
||||
m_net->out_int_cb().set(m_mct_adr, FUNC(mct_adr_device::irq<4>));
|
||||
m_net->set_bus(m_mct_adr, 0);
|
||||
|
||||
I82357(config, m_isp, 14.318181_MHz_XTAL);
|
||||
m_isp->out_rtc_cb().set(m_rtc, FUNC(mc146818_device::write));
|
||||
@ -378,6 +378,6 @@ ROM_START(mmr4000le)
|
||||
ROMX_LOAD("ntprom.bin", 0x00000, 0x40000, CRC(d91018d7) SHA1(316de17820192c89b8ee6d9936ab8364a739ca53), ROM_BIOS(0))
|
||||
ROM_END
|
||||
|
||||
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
|
||||
COMP( 1992, mmr4000be, 0, 0, mmr4000be, 0, jazz_state, init_common, "MIPS", "Magnum R4000 (big)", MACHINE_NOT_WORKING)
|
||||
COMP( 1992, mmr4000le, 0, 0, mmr4000le, 0, jazz_state, init_common, "MIPS", "Magnum R4000 (little)", MACHINE_NO_SOUND | MACHINE_NODEVICE_LAN)
|
||||
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
|
||||
COMP(1992, mmr4000be, 0, 0, mmr4000be, 0, jazz_state, init_common, "MIPS", "Magnum R4000 (be)", MACHINE_NOT_WORKING)
|
||||
COMP(1992, mmr4000le, 0, 0, mmr4000le, 0, jazz_state, init_common, "MIPS", "Magnum R4000 (le)", MACHINE_NO_SOUND)
|
||||
|
@ -93,7 +93,7 @@ protected:
|
||||
required_device<r4000_device> m_cpu;
|
||||
required_device<ram_device> m_ram;
|
||||
required_device<ram_device> m_vram;
|
||||
required_device<jazz_mct_adr_device> m_mct_adr;
|
||||
required_device<mct_adr_device> m_mct_adr;
|
||||
required_device<nscsi_bus_device> m_scsibus;
|
||||
required_device<ncr53c94_device> m_scsi;
|
||||
required_device<n82077aa_device> m_fdc;
|
||||
|
@ -19,6 +19,9 @@
|
||||
* https://github.com/torvalds/linux/tree/master/arch/mips/jazz/
|
||||
* http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/arch/arc/jazz/
|
||||
*
|
||||
* https://www.linux-mips.org/archives/riscy/1993-08/msg00064.html
|
||||
* https://www.linux-mips.org/archives/riscy/1993-08/msg00069.html
|
||||
*
|
||||
* TODO
|
||||
* - proper width dma
|
||||
* - dma address translation errors
|
||||
@ -32,10 +35,12 @@
|
||||
#define VERBOSE 0
|
||||
#include "logmacro.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(JAZZ_MCT_ADR, jazz_mct_adr_device, "jazz_mct_adr", "Jazz MCT-ADR")
|
||||
DEFINE_DEVICE_TYPE(MCT_ADR, mct_adr_device, "mct_adr", "MCT-ADR Address Path Controller")
|
||||
|
||||
jazz_mct_adr_device::jazz_mct_adr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, JAZZ_MCT_ADR, tag, owner, clock)
|
||||
mct_adr_device::mct_adr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, MCT_ADR, tag, owner, clock)
|
||||
, device_memory_interface(mconfig, *this)
|
||||
, m_dma_config("dma", ENDIANNESS_LITTLE, 32, 32, 0, address_map_constructor(FUNC(mct_adr_device::dma), this))
|
||||
, m_bus(*this, finder_base::DUMMY_TAG, -1, 64)
|
||||
, m_out_int_dma(*this)
|
||||
, m_out_int_device(*this)
|
||||
@ -46,7 +51,7 @@ jazz_mct_adr_device::jazz_mct_adr_device(const machine_config &mconfig, const ch
|
||||
{
|
||||
}
|
||||
|
||||
void jazz_mct_adr_device::map(address_map &map)
|
||||
void mct_adr_device::map(address_map &map)
|
||||
{
|
||||
map(0x000, 0x007).lrw32(NAME([this] () { return m_config; }), NAME([this] (u32 data) { m_config = data; }));
|
||||
map(0x008, 0x00f).lr32([] () { return 1; }, "revision_level");
|
||||
@ -118,7 +123,23 @@ void jazz_mct_adr_device::map(address_map &map)
|
||||
map(0x238, 0x23b).lr32(NAME([this] () { return m_eisa_iack(); }));
|
||||
}
|
||||
|
||||
void jazz_mct_adr_device::device_start()
|
||||
// HACK: this address map translates i386 bus master DMA device access (the
|
||||
// SONIC network controller) to DRAM.
|
||||
device_memory_interface::space_config_vector mct_adr_device::memory_space_config() const
|
||||
{
|
||||
return space_config_vector{
|
||||
std::make_pair(0, &m_dma_config)
|
||||
};
|
||||
}
|
||||
|
||||
void mct_adr_device::dma(address_map &map)
|
||||
{
|
||||
map(0x00000000U, 0xffffffffU).lrw32(
|
||||
[this](offs_t offset) { return m_bus->read_dword(translate_address(offset << 2)); }, "dma_r",
|
||||
[this](offs_t offset, u32 data, u32 mem_mask) { m_bus->write_dword(translate_address(offset << 2), data, mem_mask); }, "dma_w");
|
||||
}
|
||||
|
||||
void mct_adr_device::device_start()
|
||||
{
|
||||
m_out_int_dma.resolve();
|
||||
m_out_int_device.resolve();
|
||||
@ -131,11 +152,21 @@ void jazz_mct_adr_device::device_start()
|
||||
m_dma_w[i].resolve_safe();
|
||||
}
|
||||
|
||||
m_config = 0x104; // REV1, REV2 is 0x410
|
||||
|
||||
m_ioc_maint = 0;
|
||||
m_ioc_physical_tag = 0;
|
||||
m_ioc_logical_tag = 0;
|
||||
|
||||
m_irq_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mct_adr_device::irq_check), this));
|
||||
m_dma_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mct_adr_device::dma_check), this));
|
||||
m_interval_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mct_adr_device::interval_timer), this));
|
||||
|
||||
m_out_int_timer_asserted = false;
|
||||
m_out_int_device_asserted = false;
|
||||
}
|
||||
|
||||
void mct_adr_device::device_reset()
|
||||
{
|
||||
m_config = 0x104; // REV1, REV2 is 0x410
|
||||
m_trans_tbl_base = 0;
|
||||
m_trans_tbl_limit = 0;
|
||||
m_ioc_byte_mask = 0;
|
||||
@ -146,26 +177,19 @@ void jazz_mct_adr_device::device_start()
|
||||
for (u32 &val : m_dma_reg)
|
||||
val = 0;
|
||||
|
||||
m_dma_interrupt_source = 0;
|
||||
m_memory_refresh_rate = 0x18186;
|
||||
m_nvram_protect = 0x7;
|
||||
|
||||
m_irq_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(jazz_mct_adr_device::irq_check), this));
|
||||
m_dma_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(jazz_mct_adr_device::dma_check), this));
|
||||
m_interval_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(jazz_mct_adr_device::interval_timer), this));
|
||||
|
||||
m_out_int_timer_asserted = false;
|
||||
m_out_int_device_asserted = false;
|
||||
}
|
||||
|
||||
void jazz_mct_adr_device::device_reset()
|
||||
{
|
||||
m_isr = 0;
|
||||
m_imr = 0; // 0x10;
|
||||
m_imr = 0x10; // firmware diagnostic expects network interrupts to be unmasked at boot
|
||||
|
||||
m_interval_timer->adjust(attotime::from_msec(1), 0, attotime::from_msec(1));
|
||||
|
||||
irq_check(nullptr, 0);
|
||||
}
|
||||
|
||||
void jazz_mct_adr_device::set_irq_line(int irq, int state)
|
||||
void mct_adr_device::set_irq_line(int irq, int state)
|
||||
{
|
||||
if ((irq != 3) && (m_isr & (1 << irq)) ^ (state << irq))
|
||||
LOG("set_irq_line %d state %d m_imr 0x%04x\n", irq, state, m_imr);
|
||||
@ -178,7 +202,7 @@ void jazz_mct_adr_device::set_irq_line(int irq, int state)
|
||||
m_irq_check->adjust(attotime::zero);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(jazz_mct_adr_device::irq_check)
|
||||
TIMER_CALLBACK_MEMBER(mct_adr_device::irq_check)
|
||||
{
|
||||
if (bool(m_isr & m_imr) != m_out_int_device_asserted)
|
||||
{
|
||||
@ -188,13 +212,10 @@ TIMER_CALLBACK_MEMBER(jazz_mct_adr_device::irq_check)
|
||||
}
|
||||
}
|
||||
|
||||
u16 jazz_mct_adr_device::isr_r()
|
||||
u16 mct_adr_device::isr_r()
|
||||
{
|
||||
u16 const pending = m_isr & m_imr;
|
||||
|
||||
// FIXME: really?
|
||||
//m_out_int_device(CLEAR_LINE);
|
||||
|
||||
for (u16 irq = 0; irq < 16; irq++)
|
||||
if (BIT(pending, irq))
|
||||
return (irq + 1) << 2;
|
||||
@ -202,7 +223,7 @@ u16 jazz_mct_adr_device::isr_r()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jazz_mct_adr_device::imr_w(u16 data)
|
||||
void mct_adr_device::imr_w(u16 data)
|
||||
{
|
||||
LOG("imr_w 0x%04x (%s)\n", data, machine().describe_context());
|
||||
|
||||
@ -211,7 +232,7 @@ void jazz_mct_adr_device::imr_w(u16 data)
|
||||
m_irq_check->adjust(attotime::zero);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(jazz_mct_adr_device::interval_timer)
|
||||
TIMER_CALLBACK_MEMBER(mct_adr_device::interval_timer)
|
||||
{
|
||||
if (m_out_int_timer_asserted)
|
||||
m_out_int_timer(0);
|
||||
@ -221,7 +242,7 @@ TIMER_CALLBACK_MEMBER(jazz_mct_adr_device::interval_timer)
|
||||
m_out_int_timer(1);
|
||||
}
|
||||
|
||||
void jazz_mct_adr_device::set_drq_line(int channel, int state)
|
||||
void mct_adr_device::set_drq_line(int channel, int state)
|
||||
{
|
||||
m_drq_active[channel] = state == ASSERT_LINE;
|
||||
|
||||
@ -229,7 +250,7 @@ void jazz_mct_adr_device::set_drq_line(int channel, int state)
|
||||
m_dma_check->adjust(attotime::zero);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(jazz_mct_adr_device::dma_check)
|
||||
TIMER_CALLBACK_MEMBER(mct_adr_device::dma_check)
|
||||
{
|
||||
bool active = false;
|
||||
|
||||
@ -294,7 +315,7 @@ TIMER_CALLBACK_MEMBER(jazz_mct_adr_device::dma_check)
|
||||
m_dma_check->adjust(attotime::zero);
|
||||
}
|
||||
|
||||
u32 jazz_mct_adr_device::translate_address(u32 logical_address)
|
||||
u32 mct_adr_device::translate_address(u32 logical_address)
|
||||
{
|
||||
u32 page = logical_address >> 12;
|
||||
if (page < (m_trans_tbl_limit) >> 3)
|
||||
|
@ -1,15 +1,17 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
#ifndef MAME_MACHINE_JAZZ_MCT_ADR_H
|
||||
#define MAME_MACHINE_JAZZ_MCT_ADR_H
|
||||
#ifndef MAME_MACHINE_MCT_ADR_H
|
||||
#define MAME_MACHINE_MCT_ADR_H
|
||||
|
||||
#pragma once
|
||||
|
||||
class jazz_mct_adr_device : public device_t
|
||||
class mct_adr_device
|
||||
: public device_t
|
||||
, public device_memory_interface
|
||||
{
|
||||
public:
|
||||
jazz_mct_adr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
mct_adr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// configuration
|
||||
template <typename T> void set_bus(T &&tag, int spacenum) { m_bus.set_tag(std::forward<T>(tag), spacenum); }
|
||||
@ -25,7 +27,7 @@ public:
|
||||
template <unsigned IRQ> DECLARE_WRITE_LINE_MEMBER(irq) { set_irq_line(IRQ, state); }
|
||||
template <unsigned DRQ> DECLARE_WRITE_LINE_MEMBER(drq) { set_drq_line(DRQ, state); }
|
||||
|
||||
virtual void map(address_map &map);
|
||||
void map(address_map &map);
|
||||
|
||||
u16 isr_r();
|
||||
u16 imr_r() { return m_imr; }
|
||||
@ -36,7 +38,13 @@ protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
// device_memory_interface overrides
|
||||
virtual space_config_vector memory_space_config() const override;
|
||||
//virtual bool memory_translate(int spacenum, int intention, offs_t &address) override;
|
||||
|
||||
private:
|
||||
void dma(address_map &map);
|
||||
|
||||
void set_irq_line(int number, int state);
|
||||
void set_drq_line(int channel, int state);
|
||||
|
||||
@ -46,6 +54,7 @@ private:
|
||||
|
||||
u32 translate_address(u32 logical_address);
|
||||
|
||||
address_space_config m_dma_config;
|
||||
required_address_space m_bus;
|
||||
|
||||
devcb_write_line m_out_int_dma;
|
||||
@ -146,6 +155,6 @@ private:
|
||||
};
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(JAZZ_MCT_ADR, jazz_mct_adr_device)
|
||||
DECLARE_DEVICE_TYPE(MCT_ADR, mct_adr_device)
|
||||
|
||||
#endif // MAME_MACHINE_JAZZ_MCT_ADR_H
|
||||
#endif // MAME_MACHINE_MCT_ADR_H
|
||||
|
Loading…
Reference in New Issue
Block a user