From 9e52736370621a208e63cf1f42fbe46c51a0de90 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sat, 27 Jun 2026 15:07:57 +0300 Subject: [PATCH] Emulate TDMD/DPOLL correctly (Fixes Linux Ariadne driver), add full packet logging, option to disable mac replacement, b8 fix. --- a2065.cpp | 152 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 103 insertions(+), 49 deletions(-) diff --git a/a2065.cpp b/a2065.cpp index 13b51dc4..33e9813f 100644 --- a/a2065.cpp +++ b/a2065.cpp @@ -32,6 +32,7 @@ int log_a2065 = 0; 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 @@ -167,12 +168,12 @@ static int dofakemac (uae_u8 *packet) 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; @@ -182,29 +183,32 @@ static int dofakemac (uae_u8 *packet) // 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]; @@ -218,7 +222,7 @@ static int mungepacket (uae_u8 *packet, int len) 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; @@ -240,14 +244,14 @@ static int mungepacket (uae_u8 *packet, int len) 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; } @@ -259,10 +263,15 @@ static void rethink_a2065(void) 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) { @@ -282,6 +291,12 @@ static int mcfilter (const uae_u8 *data) 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]; @@ -300,6 +315,15 @@ static void put_ram_word(uae_u32 offset, uae_u16 v) 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; @@ -316,10 +340,11 @@ static void gotfunc2(void *devv, const uae_u8 *databuf, int len) srcmac = databuf + 6; if (log_a2065 > 1 && log_receive) { - write_log (_T("7790 0) + if (!(tmd1 & TX_ENP) && log_a2065 > 0) { write_log (_T("7990: chained transmit!?\n")); + } add_fcs = tmd1 & TX_ADD_FCS; @@ -625,6 +657,7 @@ static void do_transmit (void) 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 { @@ -643,6 +676,7 @@ static void do_transmit (void) } } tdr_offset++; + found = true; } put_ram_word(off + 2, tmd1); put_ram_word(off + 6, tmd3); @@ -664,36 +698,52 @@ static void do_transmit (void) 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) @@ -703,8 +753,8 @@ 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; } } @@ -869,18 +919,12 @@ static void chip_wput (uaecptr addr, uae_u16 v) 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; @@ -914,7 +958,15 @@ static void chip_wput (uaecptr addr, uae_u16 v) // 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; @@ -1186,14 +1238,11 @@ static bool a2065_config (struct autoconfig_info *aci) 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; @@ -1262,15 +1311,20 @@ static bool a2065_config (struct autoconfig_info *aci) 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; } -- 2.47.3