static int log_transmit = 1;
static int log_receive = 1;
int a2065_promiscuous = 0;
+int a2065_mungemac = 1;
#define RECEIVE_QUEUE_SIZE 256
#define RECEIVE_DRAIN_LIMIT 16
if (!memcmp(fakemac, realmac, 6)) {
return 1;
}
- if (!memcmp (packet, fakemac, 6)) {
- memcpy (packet, realmac, 6);
+ if (!memcmp(packet, fakemac, 6)) {
+ memcpy(packet, realmac, 6);
return 1;
}
- if (!memcmp (packet, realmac, 6)) {
- memcpy (packet, fakemac, 6);
+ if (!memcmp(packet, realmac, 6)) {
+ memcpy(packet, fakemac, 6);
return 1;
}
return 0;
// We have to do this because drivers are hardcoded to
// Commodore's MAC address range.
-static int mungepacket (uae_u8 *packet, int len)
+static int mungepacket(uae_u8 *packet, int len)
{
uae_u8 *data;
uae_u16 type;
int ret = 0;
+ if (!a2065_mungemac) {
+ return 0;
+ }
if (len < 20)
return 0;
if (!memcmp(fakemac, realmac, 6))
return len;
#if DUMPPACKET
- dumppacket (_T("pre:"), packet, len);
+ dumppacket(_T("pre:"), packet, len);
#endif
data = packet + 14;
type = (packet[12] << 8) | packet[13];
// switch destination mac
- ret |= dofakemac (packet);
+ ret |= dofakemac(packet);
// switch source mac
- ret |= dofakemac (packet + 6);
+ ret |= dofakemac(packet + 6);
if (type == 0x0806) { // ARP?
if (((data[0] << 8) | data[1]) == 1 && data[4] == 6) { // Ethernet and LEN=6?
- ret |= dofakemac (data + 8); // sender
- ret |= dofakemac (data + 8 + 6 + 4); // target
+ ret |= dofakemac(data + 8); // sender
+ ret |= dofakemac(data + 8 + 6 + 4); // target
}
} else if (type == 0x0800) { // IPv4?
int proto = data[9];
int dp = (data[2] << 8) | data[3];
int len2 = (data[4] << 8) | data[5];
if (sp == 67 || sp == 68 || dp == 67 || dp == 68)
- udpcrc |= dofakemac (data + 36); // DHCP CHADDR
+ udpcrc |= dofakemac(data + 36); // DHCP CHADDR
if (udpcrc && (data[6] || data[7])) {
// fix UDP checksum
int i;
if (sum == 0)
sum = 0xffff;
data[6] = sum >> 8;
- data[7] = sum >> 0;
+ data[7] = sum >> 0;
ret |= 1;
}
// this all just to translate single DHCP MAC..
}
}
#if DUMPPACKET
- dumppacket (_T("post:"), packet, len);
+ dumppacket(_T("post:"), packet, len);
#endif
return ret;
}
bool wasintr = (csr[0] & CSR0_INTR) != 0;
csr[0] &= ~CSR0_INTR;
uae_u16 mask = csr[0];
- if (AM79C960)
+ if (AM79C960) {
mask &= (~csr[3]) & (0x4000 | 0x1000 | 0x800 | 0x400 | 0x200 | 0x100);
- if (mask & (CSR0_BABL | CSR0_MISS | CSR0_MERR | CSR0_RINT | CSR0_TINT | CSR0_IDON))
+// if ((csr[4] & 0x0008) && !(csr[4] & 0x0004)) { // TXSTRT
+// csr[0] |= CSR0_INTR;
+// }
+ }
+ if (mask & (CSR0_BABL | CSR0_MISS | CSR0_MERR | CSR0_RINT | CSR0_TINT | CSR0_IDON)) {
csr[0] |= CSR0_INTR;
+ }
if ((csr[0] & (CSR0_INTR | CSR0_INEA)) == (CSR0_INTR | CSR0_INEA)) {
safe_interrupt_set(IRQ_SOURCE_A2065, 0, false);
if (log_a2065 > 1 && !wasintr) {
return 1; // just allow everything
}
+static uae_u16 get_ram_word_volatile(uae_u32 offset)
+{
+ volatile const uae_u8 *ram = boardram;
+ return ((uae_u16)ram[offset & RAM_MASK] << 8) |
+ ram[(offset + 1) & RAM_MASK];
+}
static uae_u8 get_ram_byte(uae_u32 offset)
{
return boardram[offset & RAM_MASK];
put_ram_byte(offset + 1, (uae_u8)v);
}
+static void log_packet(const uae_u8 *p, int size)
+{
+ write_log(" \n");
+ for (int i = 0; i < size; i++) {
+ write_log("%02X", p[i]);
+ }
+ write_log("\n");
+}
+
static void gotfunc2(void *devv, const uae_u8 *databuf, int len)
{
int i;
srcmac = databuf + 6;
if (log_a2065 > 1 && log_receive) {
- write_log (_T("7790<!DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d\n"),
+ write_log(_T("7790<!DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d"),
dstmac[0], dstmac[1], dstmac[2], dstmac[3], dstmac[4], dstmac[5],
- srcmac[6], srcmac[7], srcmac[8], srcmac[9], srcmac[10], srcmac[11],
+ srcmac[0], srcmac[1], srcmac[2], srcmac[3], srcmac[4], srcmac[5],
(databuf[12] << 8) | databuf[13], len);
+ log_packet(databuf, len);
}
if (!(csr[0] & CSR0_RXON)) // receiver off?
dstmac = d;
srcmac = d + 6;
if (log_a2065 && log_receive) {
- if (memcmp (dstmac, realmac, sizeof realmac) == 0) {
- write_log (_T("7990<-DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d\n"),
+ if (memcmp(dstmac, realmac, sizeof realmac) == 0) {
+ write_log(_T("7990<-DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d"),
dstmac[0], dstmac[1], dstmac[2], dstmac[3], dstmac[4], dstmac[5],
- srcmac[6], srcmac[7], srcmac[8], srcmac[9], srcmac[10], srcmac[11],
+ srcmac[0], srcmac[1], srcmac[2], srcmac[3], srcmac[4], srcmac[5],
(d[12] << 8) | d[13], len);
+ log_packet(d, len);
}
}
- if (mungepacket (d, len)) {
+ if (mungepacket(d, len)) {
if (log_a2065 && log_receive) {
- write_log (_T("7990<*DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d\n"),
+ write_log(_T("7990<*DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d"),
dstmac[0], dstmac[1], dstmac[2], dstmac[3], dstmac[4], dstmac[5],
- srcmac[6], srcmac[7], srcmac[8], srcmac[9], srcmac[10], srcmac[11],
+ srcmac[0], srcmac[1], srcmac[2], srcmac[3], srcmac[4], srcmac[5],
(d[12] << 8) | d[13], len);
+ log_packet(d, len);
}
}
for (int i = 0; i < am_rdr_rlen; i++) {
const int offset = (rdr_offset + i) % am_rdr_rlen;
const uae_u32 off = am_rdr_rdra + offset * 8;
- const uae_u16 rmd1 = get_ram_word(off + 2);
- const uae_u16 rmd2 = get_ram_word(off + 4);
+ const uae_u16 rmd1 = get_ram_word_volatile(off + 2);
+ const uae_u16 rmd2 = get_ram_word_volatile(off + 4);
if (!(rmd1 & RX_OWN))
return false;
needed -= 65536 - rmd2;
uae_u32 addr, bufaddr;
uae_u16 tmd0, tmd1, tmd2, tmd3;
uae_u32 off;
+ bool found = false;
err = 0;
size = 0;
outsize = 0;
- if (!am_tdr_tlen)
+ if (!am_tdr_tlen) {
return;
+ }
tdr_offset %= am_tdr_tlen;
bufaddr = am_tdr_tdra + tdr_offset * 8;
off = bufaddr;
tmd1 = get_ram_word(off + 2);
if (!(tmd1 & TX_OWN) || !(tmd1 & TX_STP)) {
- tdr_offset++;
+ if (!AM79C960 || !(csr[4] & 0x1000)) { // DPOLL
+ tdr_offset++;
+ }
return;
}
- if (!(tmd1 & TX_ENP) && log_a2065 > 0)
+ if (!(tmd1 & TX_ENP) && log_a2065 > 0) {
write_log (_T("7990: chained transmit!?\n"));
+ }
add_fcs = tmd1 & TX_ADD_FCS;
tmd3 |= TX_BUFF | TX_UFLO;
tmd1 |= TX_ERR;
csr[0] &= ~CSR0_TXON;
+ csr[0] &= ~CSR0_TDMD;
write_log (_T("7990: TRANSMIT OWN NOT SET\n"));
err = 1;
} else {
}
}
tdr_offset++;
+ found = true;
}
put_ram_word(off + 2, tmd1);
put_ram_word(off + 6, tmd3);
if ((am_mode & MODE_DTCR) && !add_fcs)
outsize -= 4; // do not include checksum bytes
if (log_a2065 && log_transmit) {
- write_log (_T("7990->DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d ADDR=%04X\n"),
+ write_log (_T("7990->DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d ADDR=%04X"),
d[0], d[1], d[2], d[3], d[4], d[5],
d[6], d[7], d[8], d[9], d[10], d[11],
(d[12] << 8) | d[13], outsize, bufaddr);
+ log_packet(d, outsize);
}
transmitlen = outsize;
if (mungepacket (d, transmitlen)) {
if (log_a2065 && log_transmit) {
- write_log (_T("7990*>DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d\n"),
+ write_log (_T("7990*>DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d"),
d[0], d[1], d[2], d[3], d[4], d[5],
d[6], d[7], d[8], d[9], d[10], d[11],
(d[12] << 8) | d[13], outsize);
}
+ log_packet(d, outsize);
}
ethernet_trigger (td, sysdata);
}
+
csr[0] |= CSR0_TINT;
+ if (!found) {
+ csr[0] &= ~CSR0_TDMD;
+ }
+ if (AM79C960) {
+ csr[4] |= 0x0008; // TXSTRT
+ }
devices_rethink_all(rethink_a2065);
}
-static void check_transmit(bool tdmd)
+static void check_transmit(void)
{
if (transmitlen > 0)
return;
- if (!(csr[0] & CSR0_TXON))
- return;
- if (AM79C960 && !tdmd && (csr[4] & 0x1000)) // DPOLL
+ if (!(csr[0] & CSR0_TXON)) {
+ csr[0] &= ~CSR0_TDMD;
return;
+ }
+ if (AM79C960) {
+ // TDMD == 0 and DPOLL = 1: transmit disabled
+ if (!(csr[0] & CSR0_TDMD) && (csr[4] & 0x1000)) { // DPOLL
+ return;
+ }
+ }
+
transmitnow = 0;
- do_transmit ();
+ do_transmit();
}
static void a2065_hsync_handler(void)
receive_queue_drain();
cnt--;
- if (cnt < 0 || transmitnow) {
- check_transmit(false);
+ if (cnt < 0 || transmitnow || (csr[0] & CSR0_TDMD)) {
+ check_transmit();
cnt = 15;
}
}
write_log(_T("7990: INIT. %04X -> %04X -> %04X\n"), oreg, v, csr[0]);
}
- if ((csr[0] & CSR0_STRT)) {
- if (am_initialized) {
- if (csr[0] & CSR0_TDMD)
- check_transmit(true);
- } else if (AM79C960) {
+ if (csr[0] & CSR0_STRT) {
+ if (AM79C960 && !am_initialized) {
chip_init2();
am_initialized = 1;
- if (csr[0] & CSR0_TDMD)
- check_transmit(true);
}
}
- csr[0] &= ~CSR0_TDMD;
devices_rethink_all(rethink_a2065);
break;
// Am79C960 extra
- // logical address filter
+ case 4: // test and features
+ v &= ~(0x80 | 0x40); // Reserved
+ // JAB. TXSTRT, RCVCCO, MFCOM cleared when writing 1.
+ csr[4] &= ~(v & (0x0002 | 0x0008 | 0x0020 | 0x0200));
+ csr[4] &= 0x0002 | 0x0008 | 0x0020 | 0x0200;
+ csr[4] |= v & ~(0x0002 | 0x0008 | 0x0020 | 0x0200);
+ v = csr[4];
+ break;
+ // logical address filter
case 8:
am_ladrf &= 0x0000ffffffffffff;
am_ladrf |= (uae_u64)v << 48;
if (!receive_buffer) {
receive_buffer = xcalloc(uae_u8, MAX_PACKET_SIZE * RECEIVE_QUEUE_SIZE);
}
- receive_queue_clear();
if (!aci) {
return false;
}
- device_add_reset(a2065_reset);
-
if (aci->postinit) {
configured = expamem_board_pointer >> 16;
return true;
aci->addrbank = &a2065_bank;
aci->autoconfig_automatic = true;
aci->autoconfigp = aci->autoconfig_bytes;
+
if (!aci->doinit)
return true;
+ configured = 0;
+
alloc_expansion_bank(&a2065_bank, aci);
boardram = a2065_bank.baseaddr + RAM_OFFSET;
+ receive_queue_clear();
device_add_hsync(a2065_hsync_handler);
device_add_rethink(rethink_a2065);
device_add_exit(a2065_free, NULL);
+ device_add_reset(a2065_reset);
return true;
}