diff options
author | Patrick Mackinlay <pmackinlay@hotmail.com> | 2020-01-22 21:21:23 +0700 |
---|---|---|
committer | Patrick Mackinlay <pmackinlay@hotmail.com> | 2020-01-22 21:21:23 +0700 |
commit | f5eb2f59f209dad9ab83a789dfc78bab054eb7be (patch) | |
tree | 4ff0fd37ffd470725b8357aad5349a72c9b0434c | |
parent | 30038dd15dbfceb38763252427416b2223c91264 (diff) |
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
-rw-r--r-- | src/devices/machine/dp83932c.cpp | 595 | ||||
-rw-r--r-- | src/devices/machine/dp83932c.h | 244 | ||||
-rw-r--r-- | src/mame/drivers/jazz.cpp | 44 | ||||
-rw-r--r-- | src/mame/includes/jazz.h | 2 | ||||
-rw-r--r-- | src/mame/machine/jazz_mct_adr.cpp | 79 | ||||
-rw-r--r-- | src/mame/machine/jazz_mct_adr.h | 23 |
6 files changed, 780 insertions, 207 deletions
diff --git a/src/devices/machine/dp83932c.cpp b/src/devices/machine/dp83932c.cpp index 82d70f02797..c08a16b655c 100644 --- a/src/devices/machine/dp83932c.cpp +++ b/src/devices/machine/dp83932c.cpp @@ -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; + + update_interrupts(); } -void dp83932c_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +int dp83932c_device::recv_start_cb(u8 *buf, int length) { + 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; } -int dp83932c_device::recv_start_cb(u8 *buf, int length) +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() { - return 0; + 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::recv_complete_cb(int result) +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]); + } } diff --git a/src/devices/machine/dp83932c.h b/src/devices/machine/dp83932c.h index e608f7508a6..054bb9e28cd 100644 --- a/src/devices/machine/dp83932c.h +++ b/src/devices/machine/dp83932c.h @@ -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; - enum cr_mask : u16 + // 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 { - 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 = 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 tcr_mask : u16 + enum cr_mask : u16 + { + 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 { - 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_WMASK = 0xf000 + 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 + { + 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_TPC = 0xf000, // tx packet descriptor config + TCR_TPS = 0x07ff, // tx packet descriptor status - 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; } + }; + 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 + }; 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) diff --git a/src/mame/drivers/jazz.cpp b/src/mame/drivers/jazz.cpp index a663a38a78b..8f18f685cc6 100644 --- a/src/mame/drivers/jazz.cpp +++ b/src/mame/drivers/jazz.cpp @@ -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) diff --git a/src/mame/includes/jazz.h b/src/mame/includes/jazz.h index e4f1d75f847..17d1e3fa36b 100644 --- a/src/mame/includes/jazz.h +++ b/src/mame/includes/jazz.h @@ -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; diff --git a/src/mame/machine/jazz_mct_adr.cpp b/src/mame/machine/jazz_mct_adr.cpp index 8c4c13b325f..947cbad6d34 100644 --- a/src/mame/machine/jazz_mct_adr.cpp +++ b/src/mame/machine/jazz_mct_adr.cpp @@ -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) diff --git a/src/mame/machine/jazz_mct_adr.h b/src/mame/machine/jazz_mct_adr.h index 353b905cea2..6adfa508be1 100644 --- a/src/mame/machine/jazz_mct_adr.h +++ b/src/mame/machine/jazz_mct_adr.h @@ -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 |