// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team // SPDX-License-Identifier: GPL-3.0+ #ifdef _WIN32 #include "common/RedtapeWindows.h" #include #endif #include #include #include #include #include #include #include "smap.h" #include "net.h" #include "pcap_io.h" bool has_link = true; volatile bool fireIntR = false; std::mutex frame_counter_mutex; std::mutex reset_mutex; /* #define SMAP_BASE 0xb0000000 #define SMAP_REG8(Offset) (*(u8 volatile*)(SMAP_BASE+(Offset))) #define SMAP_REG16(Offset) (*(u16 volatile*)(SMAP_BASE+(Offset))) #define SMAP_REG32(Offset) (*(u32 volatile*)(SMAP_BASE+(Offset))) u32 EMAC3REG_READ(u32 u32Offset) { u32 hi=SMAP_REG16(u32Offset); u32 lo=SMAP_REG16(u32Offset+2); return (hi<<16)|lo; } void EMAC3REG_WRITE(u32 u32Offset,u32 u32V) { SMAP_REG16(u32Offset)=((u32V>>16)&0xFFFF); SMAP_REG16(u32Offset+2)=(u32V&0xFFFF); } #define SMAP_EMAC3_BASE 0x2000 #define SMAP_EMAC3_STA_CTRL (SMAP_EMAC3_BASE+0x5C) void test() { printf ("EMAC3R 0x%08X raw read 0x%08X\n",EMAC3REG_READ(SMAP_EMAC3_STA_CTRL),SMAP_REG32(SMAP_EMAC3_STA_CTRL)); }*/ //this can return a false positive, but its not problem since it may say it cant recv while it can (no harm done, just delay on packets) bool rx_fifo_can_rx() { //check if RX is on & stuff like that here //Check if there is space on RXBD if (dev9Ru8(SMAP_R_RXFIFO_FRAME_CNT) == 64) return false; //Check if there is space on fifo const int rd_ptr = dev9Ru32(SMAP_R_RXFIFO_RD_PTR); int space = sizeof(dev9.rxfifo) - ((dev9.rxfifo_wr_ptr - rd_ptr) & 16383); if (space == 0) space = sizeof(dev9.rxfifo); if (space < 1514) return false; //we can recv a packet ! return true; } void rx_process(NetPacket* pk) { smap_bd_t* pbd = ((smap_bd_t*)&dev9.dev9R[SMAP_BD_RX_BASE & 0xffff]) + dev9.rxbdi; const int bytes = (pk->size + 3) & (~3); if (!(pbd->ctrl_stat & SMAP_BD_RX_EMPTY)) { Console.Error("DEV9: ERROR : Discarding %d bytes (RX%d not ready)", bytes, dev9.rxbdi); return; } const int pstart = (dev9.rxfifo_wr_ptr) & 16383; int i = 0; while (i < bytes) { dev9_rxfifo_write(pk->buffer[i++]); dev9.rxfifo_wr_ptr &= 16383; } //increase RXBD std::unique_lock reset_lock(reset_mutex); dev9.rxbdi++; dev9.rxbdi &= (SMAP_BD_SIZE / 8) - 1; //Fill the BD with info ! pbd->length = pk->size; pbd->pointer = 0x4000 + pstart; pbd->ctrl_stat &= ~SMAP_BD_RX_EMPTY; //increase frame count std::unique_lock counter_lock(frame_counter_mutex); dev9Ru8(SMAP_R_RXFIFO_FRAME_CNT)++; counter_lock.unlock(); reset_lock.unlock(); //spams// emu_printf("Got packet, %d bytes (%d fifo)\n", pk->size,bytes); fireIntR = true; //_DEV9irq(SMAP_INTR_RXEND,0);//now ? or when the fifo is full ? i guess now atm //note that this _is_ wrong since the IOP interrupt system is not thread safe.. but nothing i can do about that } u32 wswap(u32 d) { return (d >> 16) | (d << 16); } void tx_process() { NetPacket pk; // We will loop though TX_BD, sending any that are ready // stopping once we reach one that isn't ready // SMAP_R_TXFIFO_FRAME_CNT is decremented, but otherwise isn't used // This seems to match HW behaviour u32 cnt = 0; while (true) { smap_bd_t* pbd = ((smap_bd_t*)&dev9.dev9R[SMAP_BD_TX_BASE & 0xffff]) + dev9.txbdi; if (!(pbd->ctrl_stat & SMAP_BD_TX_READY)) { break; } if (pbd->length & 3) { //spams// emu_printf("WARN : pbd->length not aligned %u\n",pbd->length); } if (pbd->length > 1514) { Console.Error("DEV9: SMAP: ERROR : Trying to send packet too big."); } else { const u32 base = (pbd->pointer - 0x1000) & 16383; DevCon.WriteLn("DEV9: Sending Packet from base %x, size %d", base, pbd->length); pk.size = pbd->length; if (!(pbd->pointer >= 0x1000)) { Console.Error("DEV9: SMAP: ERROR: odd , !pbd->pointer>0x1000 | 0x%X %u", pbd->pointer, pbd->length); } // SMAP drivers send a very specfic frame during init, then check SPD_R_INTR_STAT for SMAP_INTR_RXEND | SMAP_INTR_TXEND | SMAP_INTR_TXDNV. // SMAP_INTR_TXEND is set normally, SMAP_INTR_RXEND is supposed to be set here, but we currently don't emulate that. // SMAP_INTR_TXDNV is set somewhere, unsure where, we only set it in failure (instead of SMAP_INTR_TXEND), but is included in the hack here. if (pbd->length == 0x5EA && pbd->pointer == 0x1000) { u32* ptr = (u32*)&dev9.txfifo[base]; bool test = true; for (u32 i = 0; i < 0x5EA; i += 4) { if (*ptr++ != i) { test = false; break; } } if (test) { Console.WriteLn("DEV9: Adapter Detection Hack - Resetting RX/TX"); _DEV9irq(SMAP_INTR_RXEND | SMAP_INTR_TXDNV, 100); } } //increase fifo pointer(s) //uh does that even exist on real h/w ? /* if(dev9.txfifo_rd_ptr+pbd->length >= 16383) { //warp around ! //first part u32 was=16384-dev9.txfifo_rd_ptr; memcpy(pk.buffer,dev9.txfifo+dev9.txfifo_rd_ptr,was); //warp dev9.txfifo_rd_ptr+=pbd->length; dev9.txfifo_rd_ptr&=16383; if (pbd->length!=was+dev9.txfifo_rd_ptr) { emu_printf("ERROR ON TX FIFO HANDLING, %x\n", dev9.txfifo_rd_ptr); } //second part memcpy(pk.buffer+was,dev9.txfifo,pbd->length-was); } else { //no warp or 'perfect' warp (reads end, resets to start memcpy(pk.buffer,dev9.txfifo+dev9.txfifo_rd_ptr,pbd->length); dev9.txfifo_rd_ptr+=pbd->length; if (dev9.txfifo_rd_ptr==16384) dev9.txfifo_rd_ptr=0; } if (dev9.txfifo_rd_ptr&(~16383)) { emu_printf("ERROR ON TX FIFO HANDLING, %x\n", dev9.txfifo_rd_ptr); } */ if (base + pbd->length > 16384) { u32 was = 16384 - base; memcpy(pk.buffer, dev9.txfifo + base, was); memcpy(pk.buffer + was, dev9.txfifo, pbd->length - was); DevCon.WriteLn("DEV9: Warped read, was=%u, sz=%u, sz-was=%u", was, pbd->length, pbd->length - was); } else { memcpy(pk.buffer, dev9.txfifo + base, pbd->length); } tx_put(&pk); } pbd->ctrl_stat &= ~SMAP_BD_TX_READY; //increase TXBD dev9.txbdi++; dev9.txbdi &= (SMAP_BD_SIZE / 8) - 1; //decrease frame count -- this is not thread safe dev9Ru8(SMAP_R_TXFIFO_FRAME_CNT)--; cnt++; } // if we actualy send something set TXEND if (cnt != 0) { _DEV9irq(SMAP_INTR_TXEND, 100); //now ? or when the fifo is empty ? i guess now atm } else { Console.Error("DEV9: SMAP: WARN : Current BD_TX was not ready, but packet send request was made"); _DEV9irq(SMAP_INTR_TXDNV, 0); } } void emac3_write(u32 addr) { u32 value = wswap(dev9Ru32(addr)); switch (addr) { case SMAP_R_EMAC3_MODE0_L: //DevCon.WriteLn("DEV9: SMAP: SMAP_R_EMAC3_MODE0 write %x", value); value = (value & (~SMAP_E3_SOFT_RESET)) | SMAP_E3_TXMAC_IDLE | SMAP_E3_RXMAC_IDLE; dev9Ru16(SMAP_R_EMAC3_STA_CTRL_H) |= SMAP_E3_PHY_OP_COMP; break; case SMAP_R_EMAC3_TxMODE0_L: //DevCon.WriteLn("DEV9: SMAP: SMAP_R_EMAC3_TxMODE0_L write %x", value); //Process TX here ? if (!(value & SMAP_E3_TX_GNP_0)) Console.Error("DEV9: SMAP_R_EMAC3_TxMODE0_L: SMAP_E3_TX_GNP_0 not set"); tx_process(); value = value & ~SMAP_E3_TX_GNP_0; if (value) Console.Error("DEV9: SMAP_R_EMAC3_TxMODE0_L: extra bits set !"); break; case SMAP_R_EMAC3_TxMODE1_L: //DevCon.WriteLn("DEV9: SMAP_R_EMAC3_TxMODE1_L 32bit write %x", value); break; case SMAP_R_EMAC3_STA_CTRL_L: //DevCon.WriteLn("DEV9: SMAP: SMAP_R_EMAC3_STA_CTRL write %x", value); { if (value & (SMAP_E3_PHY_READ)) { value |= SMAP_E3_PHY_OP_COMP; const int reg = value & (SMAP_E3_PHY_REG_ADDR_MSK); u16 val = dev9.phyregs[reg]; switch (reg) { case SMAP_DsPHYTER_BMSR: if (has_link) val |= SMAP_PHY_BMSR_LINK | SMAP_PHY_BMSR_ANCP; break; case SMAP_DsPHYTER_PHYSTS: if (has_link) val |= SMAP_PHY_STS_LINK | SMAP_PHY_STS_100M | SMAP_PHY_STS_FDX | SMAP_PHY_STS_ANCP; break; } //DevCon.WriteLn("DEV9: phy_read %d: %x", reg, val); value = (value & 0xFFFF) | (val << 16); } if (value & (SMAP_E3_PHY_WRITE)) { value |= SMAP_E3_PHY_OP_COMP; int reg = value & (SMAP_E3_PHY_REG_ADDR_MSK); u16 val = value >> 16; if (reg == SMAP_DsPHYTER_BMCR) { if (val & SMAP_PHY_BMCR_RST) { ad_reset(); } val &= ~SMAP_PHY_BMCR_RST; val |= 0x1; } //DevCon.WriteLn("DEV9: phy_write %d: %x", reg, val); dev9.phyregs[reg] = val; } } break; default: DevCon.WriteLn("DEV9: SMAP: emac3 write %x=%x", addr, value); break; } dev9Ru32(addr) = wswap(value); } u8 smap_read8(u32 addr) { switch (addr) { case SMAP_R_TXFIFO_FRAME_CNT: DevCon.WriteLn("DEV9: SMAP_R_TXFIFO_FRAME_CNT read 8"); break; case SMAP_R_RXFIFO_FRAME_CNT: DevCon.WriteLn("DEV9: SMAP_R_RXFIFO_FRAME_CNT read 8"); break; case SMAP_R_BD_MODE: return dev9.bd_swap; default: DevCon.WriteLn("DEV9: SMAP : Unknown 8 bit read @ %X,v=%X", addr, dev9Ru8(addr)); return dev9Ru8(addr); } DevCon.WriteLn("DEV9: SMAP : error , 8 bit read @ %X,v=%X", addr, dev9Ru8(addr)); return dev9Ru8(addr); } u16 smap_read16(u32 addr) { const int rv = dev9Ru16(addr); if (addr >= SMAP_BD_TX_BASE && addr < (SMAP_BD_TX_BASE + SMAP_BD_SIZE)) { if (dev9.bd_swap) return (rv << 8) | (rv >> 8); return rv; /* switch (addr & 0x7) { case 0: // ctrl_stat hard = dev9Ru16(addr); //DevCon.WriteLn("DEV9: TX_CTRL_STAT[%d]: read %x", (addr - SMAP_BD_TX_BASE) / 8, hard); if(dev9.bd_swap) return (hard<<8)|(hard>>8); return hard; case 2: // unknown hard = dev9Ru16(addr); //DevCon.WriteLn("DEV9: TX_UNKNOWN[%d]: read %x", (addr - SMAP_BD_TX_BASE) / 8, hard); if(dev9.bd_swap) return (hard<<8)|(hard>>8); return hard; case 4: // length hard = dev9Ru16(addr); DevCon.WriteLn("DEV9: TX_LENGTH[%d]: read %x", (addr - SMAP_BD_TX_BASE) / 8, hard); if(dev9.bd_swap) return (hard<<8)|(hard>>8); return hard; case 6: // pointer hard = dev9Ru16(addr); DevCon.WriteLn("DEV9: TX_POINTER[%d]: read %x", (addr - SMAP_BD_TX_BASE) / 8, hard); if(dev9.bd_swap) return (hard<<8)|(hard>>8); return hard; } */ } else if (addr >= SMAP_BD_RX_BASE && addr < (SMAP_BD_RX_BASE + SMAP_BD_SIZE)) { if (dev9.bd_swap) return (rv << 8) | (rv >> 8); return rv; /* switch (addr & 0x7) { case 0: // ctrl_stat hard = dev9Ru16(addr); //DevCon.WriteLn("DEV9: RX_CTRL_STAT[%d]: read %x", (addr - SMAP_BD_RX_BASE) / 8, hard); if(dev9.bd_swap) return (hard<<8)|(hard>>8); return hard; case 2: // unknown hard = dev9Ru16(addr); //DevCon.WriteLn("DEV9: RX_UNKNOWN[%d]: read %x", (addr - SMAP_BD_RX_BASE) / 8, hard); if(dev9.bd_swap) return (hard<<8)|(hard>>8); return hard; case 4: // length hard = dev9Ru16(addr); DevCon.WriteLn("DEV9: RX_LENGTH[%d]: read %x", (addr - SMAP_BD_RX_BASE) / 8, hard); if(dev9.bd_swap) return (hard<<8)|(hard>>8); return hard; case 6: // pointer hard = dev9Ru16(addr); DevCon.WriteLn("DEV9: RX_POINTER[%d]: read %x", (addr - SMAP_BD_RX_BASE) / 8, hard); if(dev9.bd_swap) return (hard<<8)|(hard>>8); return hard; } */ } #if (0) switch (addr) { case SMAP_R_TXFIFO_FRAME_CNT: DevCon.WriteLn("DEV9: SMAP_R_TXFIFO_FRAME_CNT read 16"); return dev9Ru16(addr); case SMAP_R_RXFIFO_FRAME_CNT: DevCon.WriteLn("DEV9: SMAP_R_RXFIFO_FRAME_CNT read 16"); return dev9Ru16(addr); case SMAP_R_EMAC3_MODE0_L: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_MODE0_L 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_MODE0_H: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_MODE0_H 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_MODE1_L: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_MODE1_L 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_MODE1_H: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_MODE1_H 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_RxMODE_L: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_RxMODE_L 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_RxMODE_H: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_RxMODE_H 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_INTR_STAT_L: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_INTR_STAT_L 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_INTR_STAT_H: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_INTR_STAT_H 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_INTR_ENABLE_L: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_INTR_ENABLE_L 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_INTR_ENABLE_H: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_INTR_ENABLE_H 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_TxMODE0_L: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_TxMODE0_L 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_TxMODE0_H: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_TxMODE0_H 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_TxMODE1_L: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_TxMODE1_L 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_TxMODE1_H: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_TxMODE1_H 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_STA_CTRL_L: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_STA_CTRL_L 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); case SMAP_R_EMAC3_STA_CTRL_H: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_STA_CTRL_H 16bit read %x", dev9Ru16(addr)); return dev9Ru16(addr); default: DevCon.WriteLn("DEV9: SMAP : Unknown 16 bit read @ %X,v=%X", addr, dev9Ru16(addr)); return dev9Ru16(addr); } #endif return rv; } u32 smap_read32(u32 addr) { if (addr >= SMAP_EMAC3_REGBASE && addr < SMAP_EMAC3_REGEND) { const u32 hi = smap_read16(addr); const u32 lo = smap_read16(addr + 2) << 16; return hi | lo; } switch (addr) { case SMAP_R_TXFIFO_FRAME_CNT: DevCon.WriteLn("DEV9: SMAP_R_TXFIFO_FRAME_CNT read 32"); return dev9Ru32(addr); case SMAP_R_RXFIFO_FRAME_CNT: DevCon.WriteLn("DEV9: SMAP_R_RXFIFO_FRAME_CNT read 32"); return dev9Ru32(addr); case SMAP_R_EMAC3_STA_CTRL_L: DevCon.WriteLn("DEV9: SMAP_R_EMAC3_STA_CTRL_L 32bit read value %x", dev9Ru32(addr)); return dev9Ru32(addr); case SMAP_R_RXFIFO_DATA: { int rd_ptr = dev9Ru32(SMAP_R_RXFIFO_RD_PTR) & 16383; const int rv = *((u32*)(dev9.rxfifo + rd_ptr)); dev9Ru32(SMAP_R_RXFIFO_RD_PTR) = ((rd_ptr + 4) & 16383); //DevCon.WriteLn("DEV9: SMAP_R_RXFIFO_DATA 32bit read %x", rv); return rv; } default: DevCon.WriteLn("DEV9: SMAP : Unknown 32 bit read @ %X,v=%X", addr, dev9Ru32(addr)); return dev9Ru32(addr); } } void smap_write8(u32 addr, u8 value) { std::unique_lock reset_lock(reset_mutex, std::defer_lock); std::unique_lock counter_lock(frame_counter_mutex, std::defer_lock); switch (addr) { case SMAP_R_TXFIFO_FRAME_INC: //DevCon.WriteLn("DEV9: SMAP_R_TXFIFO_FRAME_INC 8bit write %x", value); { dev9Ru8(SMAP_R_TXFIFO_FRAME_CNT)++; } return; case SMAP_R_RXFIFO_FRAME_DEC: //DevCon.WriteLn("DEV9: SMAP_R_RXFIFO_FRAME_DEC 8bit write %x", value); counter_lock.lock(); dev9Ru8(addr) = value; { dev9Ru8(SMAP_R_RXFIFO_FRAME_CNT)--; } counter_lock.unlock(); return; case SMAP_R_TXFIFO_CTRL: //DevCon.WriteLn("DEV9: SMAP_R_TXFIFO_CTRL 8bit write %x", value); if (value & SMAP_TXFIFO_RESET) { dev9.txbdi = 0; dev9.txfifo_rd_ptr = 0; dev9Ru8(SMAP_R_TXFIFO_FRAME_CNT) = 0; //this actualy needs to be atomic (lock mov ...) dev9Ru32(SMAP_R_TXFIFO_WR_PTR) = 0; dev9Ru32(SMAP_R_TXFIFO_SIZE) = 16384; } value &= ~SMAP_TXFIFO_RESET; dev9Ru8(addr) = value; return; case SMAP_R_RXFIFO_CTRL: //DevCon.WriteLn("DEV9: SMAP_R_RXFIFO_CTRL 8bit write %x", value); if (value & SMAP_RXFIFO_RESET) { std::scoped_lock lock(reset_lock, counter_lock); dev9.rxbdi = 0; dev9.rxfifo_wr_ptr = 0; dev9Ru8(SMAP_R_RXFIFO_FRAME_CNT) = 0; dev9Ru32(SMAP_R_RXFIFO_RD_PTR) = 0; dev9Ru32(SMAP_R_RXFIFO_SIZE) = 16384; } value &= ~SMAP_RXFIFO_RESET; dev9Ru8(addr) = value; return; case SMAP_R_BD_MODE: if (value & SMAP_BD_SWAP) { DevCon.WriteLn("DEV9: SMAP_R_BD_MODE: Byteswapping enabled."); dev9.bd_swap = 1; } else { DevCon.WriteLn("DEV9: SMAP_R_BD_MODE: Byteswapping disabled."); dev9.bd_swap = 0; } return; default: DevCon.WriteLn("DEV9: SMAP : Unknown 8 bit write @ %X,v=%X", addr, value); dev9Ru8(addr) = value; return; } } void smap_write16(u32 addr, u16 value) { if (addr >= SMAP_BD_TX_BASE && addr < (SMAP_BD_TX_BASE + SMAP_BD_SIZE)) { if (dev9.bd_swap) value = (value >> 8) | (value << 8); dev9Ru16(addr) = value; /* switch (addr & 0x7) { case 0: // ctrl_stat DevCon.WriteLn("DEV9: TX_CTRL_STAT[%d]: write %x", (addr - SMAP_BD_TX_BASE) / 8, value); //hacky dev9Ru16(addr) = value; return; case 2: // unknown //DevCon.WriteLn("DEV9: TX_UNKNOWN[%d]: write %x", (addr - SMAP_BD_TX_BASE) / 8, value); dev9Ru16(addr) = value; return; case 4: // length DevCon.WriteLn("DEV9: TX_LENGTH[%d]: write %x", (addr - SMAP_BD_TX_BASE) / 8, value); dev9Ru16(addr) = value; return; case 6: // pointer DevCon.WriteLn("DEV9: TX_POINTER[%d]: write %x", (addr - SMAP_BD_TX_BASE) / 8, value); dev9Ru16(addr) = value; return; } */ return; } else if (addr >= SMAP_BD_RX_BASE && addr < (SMAP_BD_RX_BASE + SMAP_BD_SIZE)) { //int rx_index=(addr - SMAP_BD_RX_BASE)>>3; if (dev9.bd_swap) value = (value >> 8) | (value << 8); dev9Ru16(addr) = value; /* switch (addr & 0x7) { case 0: // ctrl_stat DevCon.WriteLn("DEV9: RX_CTRL_STAT[%d]: write %x", rx_index, value); dev9Ru16(addr) = value; if(value&0x8000) { DevCon.WriteLn("DEV9: * * PACKET READ COMPLETE: rd_ptr=%d, wr_ptr=%d", dev9Ru32(SMAP_R_RXFIFO_RD_PTR), dev9.rxfifo_wr_ptr); } return; case 2: // unknown //DevCon.WriteLn("DEV9: RX_UNKNOWN[%d]: write %x", rx_index, value); dev9Ru16(addr) = value; return; case 4: // length DevCon.WriteLn("DEV9: RX_LENGTH[%d]: write %x", rx_index, value); dev9Ru16(addr) = value; return; case 6: // pointer DevCon.WriteLn("DEV9: RX_POINTER[%d]: write %x", rx_index, value); dev9Ru16(addr) = value; return; } */ return; } switch (addr) { case SMAP_R_INTR_CLR: //DevCon.WriteLn("DEV9: SMAP: SMAP_R_INTR_CLR 16bit write %x", value); dev9.irqcause &= ~value; return; case SMAP_R_TXFIFO_WR_PTR: DevCon.WriteLn("DEV9: SMAP: SMAP_R_TXFIFO_WR_PTR 16bit write %x", value); dev9Ru16(addr) = value; return; #define EMAC3_L_WRITE(name) \ case name: \ /* DevCon.WriteLn("DEV9: SMAP: " #name " 16 bit write %x", value);*/ \ dev9Ru16(addr) = value; \ return; // clang-format off //handle L writes EMAC3_L_WRITE(SMAP_R_EMAC3_MODE0_L) EMAC3_L_WRITE(SMAP_R_EMAC3_MODE1_L) EMAC3_L_WRITE(SMAP_R_EMAC3_TxMODE0_L) EMAC3_L_WRITE(SMAP_R_EMAC3_TxMODE1_L) EMAC3_L_WRITE(SMAP_R_EMAC3_RxMODE_L) EMAC3_L_WRITE(SMAP_R_EMAC3_INTR_STAT_L) EMAC3_L_WRITE(SMAP_R_EMAC3_INTR_ENABLE_L) EMAC3_L_WRITE(SMAP_R_EMAC3_ADDR_HI_L) EMAC3_L_WRITE(SMAP_R_EMAC3_ADDR_LO_L) EMAC3_L_WRITE(SMAP_R_EMAC3_VLAN_TPID) EMAC3_L_WRITE(SMAP_R_EMAC3_PAUSE_TIMER_L) EMAC3_L_WRITE(SMAP_R_EMAC3_INDIVID_HASH1) EMAC3_L_WRITE(SMAP_R_EMAC3_INDIVID_HASH2) EMAC3_L_WRITE(SMAP_R_EMAC3_INDIVID_HASH3) EMAC3_L_WRITE(SMAP_R_EMAC3_INDIVID_HASH4) EMAC3_L_WRITE(SMAP_R_EMAC3_GROUP_HASH1) EMAC3_L_WRITE(SMAP_R_EMAC3_GROUP_HASH2) EMAC3_L_WRITE(SMAP_R_EMAC3_GROUP_HASH3) EMAC3_L_WRITE(SMAP_R_EMAC3_GROUP_HASH4) EMAC3_L_WRITE(SMAP_R_EMAC3_LAST_SA_HI) EMAC3_L_WRITE(SMAP_R_EMAC3_LAST_SA_LO) EMAC3_L_WRITE(SMAP_R_EMAC3_INTER_FRAME_GAP_L) EMAC3_L_WRITE(SMAP_R_EMAC3_STA_CTRL_L) EMAC3_L_WRITE(SMAP_R_EMAC3_TX_THRESHOLD_L) EMAC3_L_WRITE(SMAP_R_EMAC3_RX_WATERMARK_L) EMAC3_L_WRITE(SMAP_R_EMAC3_TX_OCTETS) EMAC3_L_WRITE(SMAP_R_EMAC3_RX_OCTETS) // clang-format on #define EMAC3_H_WRITE(name) \ case name: \ /* DevCon.WriteLn("DEV9: SMAP: " #name " 16 bit write %x", value);*/ \ dev9Ru16(addr) = value; \ emac3_write(addr - 2); \ return; // clang-format off //handle H writes EMAC3_H_WRITE(SMAP_R_EMAC3_MODE0_H) EMAC3_H_WRITE(SMAP_R_EMAC3_MODE1_H) EMAC3_H_WRITE(SMAP_R_EMAC3_TxMODE0_H) EMAC3_H_WRITE(SMAP_R_EMAC3_TxMODE1_H) EMAC3_H_WRITE(SMAP_R_EMAC3_RxMODE_H) EMAC3_H_WRITE(SMAP_R_EMAC3_INTR_STAT_H) EMAC3_H_WRITE(SMAP_R_EMAC3_INTR_ENABLE_H) EMAC3_H_WRITE(SMAP_R_EMAC3_ADDR_HI_H) EMAC3_H_WRITE(SMAP_R_EMAC3_ADDR_LO_H) EMAC3_H_WRITE(SMAP_R_EMAC3_VLAN_TPID + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_PAUSE_TIMER_H) EMAC3_H_WRITE(SMAP_R_EMAC3_INDIVID_HASH1 + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_INDIVID_HASH2 + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_INDIVID_HASH3 + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_INDIVID_HASH4 + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_GROUP_HASH1 + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_GROUP_HASH2 + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_GROUP_HASH3 + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_GROUP_HASH4 + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_LAST_SA_HI + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_LAST_SA_LO + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_INTER_FRAME_GAP_H) EMAC3_H_WRITE(SMAP_R_EMAC3_STA_CTRL_H) EMAC3_H_WRITE(SMAP_R_EMAC3_TX_THRESHOLD_H) EMAC3_H_WRITE(SMAP_R_EMAC3_RX_WATERMARK_H) EMAC3_H_WRITE(SMAP_R_EMAC3_TX_OCTETS + 2) EMAC3_H_WRITE(SMAP_R_EMAC3_RX_OCTETS + 2) // clang-format on /* case SMAP_R_EMAC3_MODE0_L: DevCon.WriteLn("DEV9: SMAP: SMAP_R_EMAC3_MODE0 write %x", value); dev9Ru16(addr) = value; return; case SMAP_R_EMAC3_TxMODE0_L: DevCon.WriteLn("DEV9: SMAP: SMAP_R_EMAC3_TxMODE0_L 16bit write %x", value); dev9Ru16(addr) = value; return; case SMAP_R_EMAC3_TxMODE1_L: emu_printf("SMAP: SMAP_R_EMAC3_TxMODE1_L 16bit write %x\n", value); dev9Ru16(addr) = value; return; case SMAP_R_EMAC3_TxMODE0_H: emu_printf("SMAP: SMAP_R_EMAC3_TxMODE0_H 16bit write %x\n", value); dev9Ru16(addr) = value; return; case SMAP_R_EMAC3_TxMODE1_H: emu_printf("SMAP: SMAP_R_EMAC3_TxMODE1_H 16bit write %x\n", value); dev9Ru16(addr) = value; return; case SMAP_R_EMAC3_STA_CTRL_H: DevCon.WriteLn("DEV9: SMAP: SMAP_R_EMAC3_STA_CTRL_H 16bit write %x", value); dev9Ru16(addr) = value; return; */ default: DevCon.WriteLn("DEV9: SMAP : Unknown 16 bit write @ %X,v=%X", addr, value); dev9Ru16(addr) = value; return; } } void smap_write32(u32 addr, u32 value) { if (addr >= SMAP_EMAC3_REGBASE && addr < SMAP_EMAC3_REGEND) { smap_write16(addr, value & 0xFFFF); smap_write16(addr + 2, value >> 16); return; } switch (addr) { case SMAP_R_TXFIFO_DATA: //DevCon.WriteLn("DEV9: SMAP_R_TXFIFO_DATA 32bit write %x", value); *((u32*)(dev9.txfifo + dev9Ru32(SMAP_R_TXFIFO_WR_PTR))) = value; dev9Ru32(SMAP_R_TXFIFO_WR_PTR) = (dev9Ru32(SMAP_R_TXFIFO_WR_PTR) + 4) & 16383; return; default: DevCon.WriteLn("DEV9: SMAP : Unknown 32 bit write @ %X,v=%X", addr, value); dev9Ru32(addr) = value; return; } } void smap_readDMA8Mem(u32* pMem, int size) { if (dev9Ru16(SMAP_R_RXFIFO_CTRL) & SMAP_RXFIFO_DMAEN) { dev9Ru32(SMAP_R_RXFIFO_RD_PTR) &= 16383; DevCon.WriteLn("DEV9: * * SMAP DMA READ START: rd_ptr=%d, wr_ptr=%d", dev9Ru32(SMAP_R_RXFIFO_RD_PTR), dev9.rxfifo_wr_ptr); while (size > 0) { *pMem = *((u32*)(dev9.rxfifo + dev9Ru32(SMAP_R_RXFIFO_RD_PTR))); pMem++; dev9Ru32(SMAP_R_RXFIFO_RD_PTR) = (dev9Ru32(SMAP_R_RXFIFO_RD_PTR) + 4) & 16383; size -= 4; } DevCon.WriteLn("DEV9: * * SMAP DMA READ END: rd_ptr=%d, wr_ptr=%d", dev9Ru32(SMAP_R_RXFIFO_RD_PTR), dev9.rxfifo_wr_ptr); dev9Ru16(SMAP_R_RXFIFO_CTRL) &= ~SMAP_RXFIFO_DMAEN; } } void smap_writeDMA8Mem(u32* pMem, int size) { if (dev9Ru16(SMAP_R_TXFIFO_CTRL) & SMAP_TXFIFO_DMAEN) { dev9Ru32(SMAP_R_TXFIFO_WR_PTR) &= 16383; DevCon.WriteLn("DEV9: * * SMAP DMA WRITE START: wr_ptr=%d, rd_ptr=%d", dev9Ru32(SMAP_R_TXFIFO_WR_PTR), dev9.txfifo_rd_ptr); while (size > 0) { int value = *pMem; // value=(value<<24)|(value>>24)|((value>>8)&0xFF00)|((value<<8)&0xFF0000); pMem++; *((u32*)(dev9.txfifo + dev9Ru32(SMAP_R_TXFIFO_WR_PTR))) = value; dev9Ru32(SMAP_R_TXFIFO_WR_PTR) = (dev9Ru32(SMAP_R_TXFIFO_WR_PTR) + 4) & 16383; size -= 4; } DevCon.WriteLn("DEV9: * * SMAP DMA WRITE END: wr_ptr=%d, rd_ptr=%d", dev9Ru32(SMAP_R_TXFIFO_WR_PTR), dev9.txfifo_rd_ptr); dev9Ru16(SMAP_R_TXFIFO_CTRL) &= ~SMAP_TXFIFO_DMAEN; } } void smap_async(u32 cycles) { if (fireIntR) { fireIntR = false; //Is this used to signal each individual packet, or just when there are packets in the RX fifo? //I think it just signals when there are packets in the RX fifo _DEV9irq(SMAP_INTR_RXEND, 0); //Make the call to _DEV9irq in a thread safe way } }