summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/mb8795.cpp
blob: 0ec30d1f84b3c7d974f7a21b0192cd4fa4699465 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                                     



                   
                                                                     
 

                                         








                                                                                                                          
 
 
                                                                                                               




                                                                                                         



                         


 













                                                       




                            























                                         
                                                  





                                

                                     
                                                                                 






                                         
                                                                             



                                     
                                                                             






                                      
                                                                             



                                     
                                                                             






                                         
                                                                             



                                     
                                                                             






                                      
                                                                             



                                     
                                                                             





                                      
                                                                             



                                     
                                                                             





                                      
                                                                             









                                      
                                                                                      







                                   
                                                                                            

















                                             
                                                    











                                        
                                                                                                  


                                                                                                   


                                                                                       














                                                           
                                                      




















                                                           














                                                                                        
                                                                                               

                                                                                   
                 
                          
              








                                                         























































                                                                                            
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert

#include "emu.h"
#include "mb8795.h"

DEFINE_DEVICE_TYPE(MB8795, mb8795_device, "mb8795", "Fujitsu MB8795")

void mb8795_device::map(address_map &map)
{
	map(0x0, 0x0).rw(FUNC(mb8795_device::txstat_r), FUNC(mb8795_device::txstat_w));
	map(0x1, 0x1).rw(FUNC(mb8795_device::txmask_r), FUNC(mb8795_device::txmask_w));
	map(0x2, 0x2).rw(FUNC(mb8795_device::rxstat_r), FUNC(mb8795_device::rxstat_w));
	map(0x3, 0x3).rw(FUNC(mb8795_device::rxmask_r), FUNC(mb8795_device::rxmask_w));
	map(0x4, 0x4).rw(FUNC(mb8795_device::txmode_r), FUNC(mb8795_device::txmode_w));
	map(0x5, 0x5).rw(FUNC(mb8795_device::rxmode_r), FUNC(mb8795_device::rxmode_w));
	map(0x6, 0x6).w(FUNC(mb8795_device::reset_w));
	map(0x7, 0x7).r(FUNC(mb8795_device::tdc_lsb_r));
	map(0x8, 0xf).rw(FUNC(mb8795_device::mac_r), FUNC(mb8795_device::mac_w)); // Mapping limitation, real is up to 0xd
}

mb8795_device::mb8795_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, MB8795, tag, owner, clock),
	device_network_interface(mconfig, *this, 10),
	txstat(0), txmask(0), rxstat(0), rxmask(0), txmode(0), rxmode(0), txlen(0), rxlen(0), txcount(0),
	drq_tx(false), drq_rx(false), irq_tx(false), irq_rx(false),
	timer_tx(nullptr), timer_rx(nullptr),
	irq_tx_cb(*this),
	irq_rx_cb(*this),
	drq_tx_cb(*this),
	drq_rx_cb(*this)
{
}

void mb8795_device::check_irq()
{
	bool old_irq_tx = irq_tx;
	bool old_irq_rx = irq_rx;
	irq_tx = txstat & txmask;
	irq_rx = rxstat & rxmask;
	if(irq_tx != old_irq_tx && !irq_tx_cb.isnull())
		irq_tx_cb(irq_tx);
	if(irq_rx != old_irq_rx && !irq_rx_cb.isnull())
		irq_rx_cb(irq_rx);
}

void mb8795_device::device_start()
{
	irq_tx_cb.resolve();
	irq_rx_cb.resolve();
	drq_tx_cb.resolve();
	drq_rx_cb.resolve();

	memset(mac, 0, 6);
	timer_tx = timer_alloc(TIMER_TX);
	timer_rx = timer_alloc(TIMER_RX);
}

void mb8795_device::device_reset()
{
	txstat = EN_TXS_READY;
	txmask = 0x00;
	rxstat = 0x00;
	rxmask = 0x00;
	txmode = 0x00;
	rxmode = 0x00;

	drq_tx = drq_rx = false;
	irq_tx = irq_rx = false;

	txlen = rxlen = txcount = 0;

	set_promisc(true);

	start_send();
}

void mb8795_device::recv_cb(uint8_t *buf, int len)
{
	memcpy(rxbuf, buf, len);
	rxlen = len;
	receive();
}

READ8_MEMBER(mb8795_device::txstat_r)
{
	//  logerror("txstat_r %02x %s\n", txstat, machine().describe_context());
	return txstat;
}

WRITE8_MEMBER(mb8795_device::txstat_w)
{
	txstat = txstat & (0xf0 | ~data);
	check_irq();
	logerror("txstat_w %02x %s\n", txstat, machine().describe_context());
}

READ8_MEMBER(mb8795_device::txmask_r)
{
	logerror("txmask_r %02x %s\n", txmask, machine().describe_context());
	return txmask;
}

WRITE8_MEMBER(mb8795_device::txmask_w)
{
	txmask = data & 0xaf;
	check_irq();
	logerror("txmask_w %02x %s\n", txmask, machine().describe_context());
}

READ8_MEMBER(mb8795_device::rxstat_r)
{
	logerror("rxstat_r %02x %s\n", rxstat, machine().describe_context());
	return rxstat;
}

WRITE8_MEMBER(mb8795_device::rxstat_w)
{
	rxstat = rxstat & (0x70 | ~data);
	check_irq();
	logerror("rxstat_w %02x %s\n", rxstat, machine().describe_context());
}

READ8_MEMBER(mb8795_device::rxmask_r)
{
	logerror("rxmask_r %02x %s\n", rxmask, machine().describe_context());
	return rxmask;
}

WRITE8_MEMBER(mb8795_device::rxmask_w)
{
	rxmask = data & 0x9f;
	check_irq();
	logerror("rxmask_w %02x %s\n", rxmask, machine().describe_context());
}

READ8_MEMBER(mb8795_device::txmode_r)
{
	logerror("txmode_r %02x %s\n", txmode, machine().describe_context());
	return txmode;
}

WRITE8_MEMBER(mb8795_device::txmode_w)
{
	txmode = data;
	logerror("txmode_w %02x %s\n", txmode, machine().describe_context());
}

READ8_MEMBER(mb8795_device::rxmode_r)
{
	logerror("rxmode_r %02x %s\n", rxmode, machine().describe_context());
	return rxmode;
}

WRITE8_MEMBER(mb8795_device::rxmode_w)
{
	rxmode = data;
	logerror("rxmode_w %02x %s\n", rxmode, machine().describe_context());
}

WRITE8_MEMBER(mb8795_device::reset_w)
{
	if(data & EN_RST_RESET)
		device_reset();
}

READ8_MEMBER(mb8795_device::tdc_lsb_r)
{
	logerror("tdc_lsb_r %02x %s\n", txcount & 0xff, machine().describe_context());
	return txcount;
}

READ8_MEMBER(mb8795_device::mac_r)
{
	if(offset < 6)
		return mac[offset];
	if(offset == 7) {
		logerror("tdc_msb_r %02x %s\n", txcount >> 8, machine().describe_context());
		return (txcount >> 8) & 0x3f;
	}
	return 0;
}

WRITE8_MEMBER(mb8795_device::mac_w)
{
	if(offset < 6) {
		mac[offset] = data;
		set_mac((const char *)mac);
	}
}

void mb8795_device::start_send()
{
	timer_tx->adjust(attotime::zero);
}

void mb8795_device::tx_dma_w(uint8_t data, bool eof)
{
	txbuf[txlen++] = data;
	if(txstat & EN_TXS_READY) {
		txstat &= ~EN_TXS_READY;
		check_irq();
	}

	drq_tx = false;
	if(!drq_tx_cb.isnull())
		drq_tx_cb(drq_tx);

	if(eof) {
		logerror("send packet, dest=%02x.%02x.%02x.%02x.%02x.%02x len=%04x loopback=%s\n",
					txbuf[0], txbuf[1], txbuf[2], txbuf[3], txbuf[4], txbuf[5],
					txlen,
					txmode & EN_TMD_LB_DISABLE ? "off" : "on");

		if(txlen > 1500)
			txlen = 1500; // Weird packet send on loopback test in the next

		if(!(txmode & EN_TMD_LB_DISABLE)) {
			memcpy(rxbuf, txbuf, txlen);
			rxlen = txlen;
			receive();
		}
		send(txbuf, txlen);
		txlen = 0;
		txstat |= EN_TXS_READY;
		txcount++;
		start_send();
	} else
		timer_tx->adjust(attotime::from_nsec(800));
}

void mb8795_device::rx_dma_r(uint8_t &data, bool &eof)
{
	drq_rx = false;
	if(!drq_rx_cb.isnull())
		drq_rx_cb(drq_rx);

	if(rxlen) {
		data = rxbuf[0];
		rxlen--;
		memmove(rxbuf, rxbuf+1, rxlen);
	} else
		data = 0;

	if(rxlen) {
		timer_rx->adjust(attotime::from_nsec(800));
		eof = false;
	} else
		eof = true;
}

void mb8795_device::receive()
{
	bool keep = false;
	switch(rxmode & EN_RMD_WHATRECV) {
	case EN_RMD_RECV_NONE:
		keep = false;
		break;
	case EN_RMD_RECV_NORMAL:
		keep = recv_is_broadcast() || recv_is_me() || recv_is_local_multicast();
		break;
	case EN_RMD_RECV_MULTI:
		keep = recv_is_broadcast() || recv_is_me() || recv_is_multicast();
		break;
	case EN_RMD_RECV_PROMISC:
		keep = true;
		break;
	}
	logerror("received packet for %02x.%02x.%02x.%02x.%02x.%02x len=%04x, mode=%d -> %s\n",
			rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5],
			rxlen, rxmode & 3, keep ? "kept" : "dropped");
	if(!keep)
		rxlen = 0;
	else {
		// Minimal ethernet packet size
		if(rxlen < 64) {
			memset(rxbuf+rxlen, 0, 64-rxlen);
			rxlen = 64;
		}
		// Checksum?  In any case, it's there
		memset(rxbuf+rxlen, 0, 4);
		rxlen += 4;

		rxstat |= EN_RXS_OK;
		check_irq();
		timer_rx->adjust(attotime::zero);
	}
}

bool mb8795_device::recv_is_broadcast()
{
	return
		rxbuf[0] == 0xff &&
		rxbuf[1] == 0xff &&
		rxbuf[2] == 0xff &&
		rxbuf[3] == 0xff &&
		rxbuf[4] == 0xff &&
		rxbuf[5] == 0xff;
}

bool mb8795_device::recv_is_me()
{
	return
		rxbuf[0] == mac[0] &&
		rxbuf[1] == mac[1] &&
		rxbuf[2] == mac[2] &&
		rxbuf[3] == mac[3] &&
		rxbuf[4] == mac[4] &&
		((rxmode & EN_RMD_ADDRSIZE) || rxbuf[5] == mac[5]);
}

bool mb8795_device::recv_is_local_multicast()
{
	return
		(rxbuf[0] & 0x01) &&
		(rxbuf[0] & 0xfe) == mac[0] &&
		rxbuf[1] == mac[1] &&
		rxbuf[2] == mac[2];
}

bool mb8795_device::recv_is_multicast()
{
	return rxbuf[0] & 0x01;
}

void mb8795_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	if(id == TIMER_TX) {
		drq_tx = true;
		if(!drq_tx_cb.isnull())
			drq_tx_cb(drq_tx);
	}

	if(id == TIMER_RX && rxlen) {
		drq_rx = true;
		if(!drq_rx_cb.isnull())
			drq_rx_cb(drq_rx);
	}
}