diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index b7814242..e53d8f50 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -31,9 +31,10 @@ endif() find_package(Boost REQUIRED) set(SOURCE_FILES - Tfe/tfe.cpp Tfe/tfearch.cpp Tfe/tfesupp.cpp + Tfe/NetworkBackend.cpp + Tfe/PCapBackend.cpp Debugger/Debug.cpp Debugger/Debugger_Help.cpp @@ -48,6 +49,8 @@ set(SOURCE_FILES Debugger/Debugger_Commands.cpp Debugger/Util_MemoryTextFile.cpp + Uthernet1.cpp + Uthernet2.cpp StrFormat.cpp 6522.cpp VidHD.cpp @@ -99,8 +102,6 @@ set(SOURCE_FILES linux/linuxframe.cpp linux/context.cpp linux/tape.cpp - linux/network/uthernet2.cpp - linux/network/tfe2.cpp linux/network/slirp2.cpp linux/duplicates/Debugger_Display.cpp @@ -119,6 +120,14 @@ set(SOURCE_FILES ) set(HEADER_FILES + Tfe/tfearch.h + Tfe/tfesupp.h + Tfe/NetworkBackend.h + Tfe/PCapBackend.h + + Uthernet1.h + Uthernet2.h + W5100.h 6522.h VidHD.h SSI263.h @@ -195,10 +204,7 @@ set(HEADER_FILES linux/keyboard.h linux/linuxframe.h linux/tape.h - linux/network/uthernet2.h - linux/network/tfe2.h linux/network/slirp2.h - linux/network/registers.h Z80VICE/z80.h Z80VICE/z80mem.h diff --git a/source/CardManager.cpp b/source/CardManager.cpp index c717ea53..f10d7daa 100644 --- a/source/CardManager.cpp +++ b/source/CardManager.cpp @@ -43,7 +43,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Uthernet1.h" #include "Uthernet2.h" #include "VidHD.h" -#include "linux/network/uthernet2.h" #include "LanguageCard.h" #include "Memory.h" @@ -96,9 +95,6 @@ void CardManager::InsertInternal(UINT slot, SS_CARDTYPE type) case CT_Uthernet: m_slot[slot] = new Uthernet1(slot); break; - case CT_Uthernet2: - m_slot[slot] = new Uthernet2(slot); - break; case CT_FourPlay: m_slot[slot] = new FourPlayCard(slot); break; diff --git a/source/StdAfx.h b/source/StdAfx.h index 50fa17e3..84143565 100644 --- a/source/StdAfx.h +++ b/source/StdAfx.h @@ -71,6 +71,7 @@ typedef UINT64 uint64_t; #include #include #include +#include #include "windows.h" diff --git a/source/Tfe/tfearch.cpp b/source/Tfe/tfearch.cpp index bdab39dc..75d0dc65 100644 --- a/source/Tfe/tfearch.cpp +++ b/source/Tfe/tfearch.cpp @@ -438,7 +438,7 @@ void TfePcapPacketHandler(u_char *param, const struct pcap_pkthdr *header, const /* determine the count of bytes which has been returned, * but make sure not to overrun the buffer */ - pinternal->rxlength = min(pinternal->size, header->caplen); + pinternal->rxlength = std::min(pinternal->size, header->caplen); memcpy(pinternal->buffer, pkt_data, pinternal->rxlength); } diff --git a/source/frontends/sdl/imgui/sdlsettings.cpp b/source/frontends/sdl/imgui/sdlsettings.cpp index 1b779648..c8fdb7c6 100644 --- a/source/frontends/sdl/imgui/sdlsettings.cpp +++ b/source/frontends/sdl/imgui/sdlsettings.cpp @@ -23,8 +23,8 @@ #include "Debugger/Debugger_Types.h" -#include "Tfe/tfe.h" #include "Tfe/tfesupp.h" +#include "Tfe/PCapBackend.h" namespace { @@ -359,22 +359,22 @@ namespace sa2 ImGui::Separator(); - const std::string current_interface = get_tfe_interface(); + const std::string current_interface = PCapBackend::tfe_interface; if (ImGui::BeginCombo("pcap", current_interface.c_str())) { std::vector ifaces; - if (tfe_enumadapter_open()) + if (PCapBackend::tfe_enumadapter_open()) { char *pname; char *pdescription; - while (tfe_enumadapter(&pname, &pdescription)) + while (PCapBackend::tfe_enumadapter(&pname, &pdescription)) { ifaces.push_back(pname); lib_free(pdescription); } - tfe_enumadapter_close(); + PCapBackend::tfe_enumadapter_close(); for (const auto & iface : ifaces) { @@ -382,8 +382,8 @@ namespace sa2 if (ImGui::Selectable(iface, isSelected)) { // the following line interacts with tfe_enumadapter, so we must run it outside the above loop - update_tfe_interface(iface); - tfe_SetRegistryInterface(SLOT3, iface); + PCapBackend::tfe_interface = iface; + PCapBackend::tfe_SetRegistryInterface(SLOT3, PCapBackend::tfe_interface); } if (isSelected) { diff --git a/source/frontends/sdl/imgui/settingshelper.cpp b/source/frontends/sdl/imgui/settingshelper.cpp index f9af8fd3..707d24e7 100644 --- a/source/frontends/sdl/imgui/settingshelper.cpp +++ b/source/frontends/sdl/imgui/settingshelper.cpp @@ -7,7 +7,6 @@ #include "Interface.h" #include "Debugger/Debug.h" -#include "Tfe/tfe.h" #include "frontends/sdl/imgui/settingshelper.h" #include "frontends/sdl/imgui/glselector.h" diff --git a/source/linux/context.cpp b/source/linux/context.cpp index d0b6c75d..7cad23c3 100644 --- a/source/linux/context.cpp +++ b/source/linux/context.cpp @@ -6,6 +6,8 @@ #include "linux/paddle.h" #include "linux/duplicates/PropertySheet.h" +#include "Debugger/Debug.h" + #include "Interface.h" #include "Log.h" #include "Utilities.h" @@ -17,8 +19,9 @@ #include "Memory.h" #include "Speaker.h" #include "MouseInterface.h" -#include "Debugger/Debug.h" #include "Mockingboard.h" +#include "Uthernet1.h" +#include "Uthernet2.h" namespace @@ -147,11 +150,20 @@ void DestroyEmulator() MB_Destroy(); DSUninit(); - tfe_shutdown(); - - if (cardManager.QuerySlot(SLOT7) == CT_GenericHDD) + for (UINT i = 0; i < NUM_SLOTS; ++i) { - dynamic_cast(cardManager.GetRef(SLOT7)).Destroy(); + switch (cardManager.QuerySlot(i)) + { + case CT_GenericHDD: + dynamic_cast(cardManager.GetRef(i)).Destroy(); + break; + case CT_Uthernet: + dynamic_cast(cardManager.GetRef(i)).Destroy(); + break; + case CT_Uthernet2: + dynamic_cast(cardManager.GetRef(i)).Destroy(); + break; + } } PrintDestroy(); diff --git a/source/linux/linuxframe.cpp b/source/linux/linuxframe.cpp index ad238efb..d1bec554 100644 --- a/source/linux/linuxframe.cpp +++ b/source/linux/linuxframe.cpp @@ -1,6 +1,8 @@ #include "StdAfx.h" #include "linux/linuxframe.h" #include "linux/context.h" +#include "linux/network/slirp2.h" +#include "Tfe/PCapBackend.h" #include "Interface.h" #include "Log.h" #include "Core.h" @@ -128,6 +130,15 @@ void LinuxFrame::Restart() Begin(); } +std::shared_ptr LinuxFrame::CreateNetworkBackend() +{ +#ifdef U2_USE_SLIRP + return std::make_shared(); +#else + return std::make_shared(PCapBackend::tfe_interface); +#endif +} + int MessageBox(HWND, LPCSTR lpText, LPCSTR lpCaption, UINT uType) { return GetFrame().FrameMessageBox(lpText, lpCaption, uType); diff --git a/source/linux/linuxframe.h b/source/linux/linuxframe.h index 97cea1e5..deed0281 100644 --- a/source/linux/linuxframe.h +++ b/source/linux/linuxframe.h @@ -27,6 +27,8 @@ public: void Restart() override; // calls End() - Begin() void GetBitmap(LPCSTR lpBitmapName, LONG cb, LPVOID lpvBits) override; + std::shared_ptr CreateNetworkBackend() override; + void CycleVideoType(); void Cycle50ScanLines(); diff --git a/source/linux/network/registers.h b/source/linux/network/registers.h deleted file mode 100644 index 0897902d..00000000 --- a/source/linux/network/registers.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -// Uthernet II registers - -#define C0X_MODE_REGISTER 0x04 -#define C0X_ADDRESS_HIGH 0x05 -#define C0X_ADDRESS_LOW 0x06 -#define C0X_DATA_PORT 0x07 - -// W5100 registers and values - -#define MR 0x0000 -#define GAR0 0x0001 -#define GAR3 0x0004 -#define SUBR0 0x0005 -#define SUBR3 0x0008 -#define SHAR0 0x0009 -#define SHAR5 0x000E -#define SIPR0 0x000F -#define SIPR3 0x0012 -#define RTR0 0x0017 -#define RTR1 0x0018 -#define RMSR 0x001A -#define TMSR 0x001B -#define UPORT1 0x002F -#define S0_BASE 0x0400 -#define S3_MAX 0x07FF -#define TX_BASE 0x4000 -#define RX_BASE 0x6000 -#define MEM_MAX 0x7FFF -#define MEM_SIZE 0x8000 - -#define MR_IND 0x01 // 0 -#define MR_AI 0x02 // 1 -#define MR_PPOE 0x08 // 3 -#define MR_PB 0x10 // 4 -#define MR_RST 0x80 // 7 - -#define SN_MR_PROTO_MASK 0x0F -#define SN_MR_CLOSED 0x00 -#define SN_MR_TCP 0x01 -#define SN_MR_UDP 0x02 -#define SN_MR_IPRAW 0x03 -#define SN_MR_MACRAW 0x04 -#define SN_MR_PPPOE 0x05 - -#define SN_CR_OPEN 0x01 -#define SN_CR_LISTENT 0x02 -#define SN_CR_CONNECT 0x04 -#define SN_CR_DISCON 0x08 -#define SN_CR_CLOSE 0x10 -#define SN_CR_SEND 0x20 -#define SN_CR_RECV 0x40 - -#define SN_MR 0x00 -#define SN_CR 0x01 -#define SN_SR 0x03 -#define SN_PORT0 0x04 -#define SN_PORT1 0x05 -#define SN_DIPR0 0x0C -#define SN_DIPR3 0x0F -#define SN_DPORT0 0x10 -#define SN_DPORT1 0x11 -#define SN_PROTO 0x14 -#define SN_TOS 0x15 -#define SN_TTL 0x16 -#define SN_TX_FSR0 0x20 -#define SN_TX_FSR1 0x21 -#define SN_TX_RD0 0x22 -#define SN_TX_RD1 0x23 -#define SN_TX_WR0 0x24 -#define SN_TX_WR1 0x25 -#define SN_RX_RSR0 0x26 -#define SN_RX_RSR1 0x27 -#define SN_RX_RD0 0x28 -#define SN_RX_RD1 0x29 - -#define SN_SR_CLOSED 0x00 -#define SN_SR_SOCK_INIT 0x13 -#define SN_SR_ESTABLISHED 0x17 -#define SN_SR_SOCK_UDP 0x22 -#define SN_SR_SOCK_IPRAW 0x32 -#define SN_SR_SOCK_MACRAW 0x42 diff --git a/source/linux/network/slirp2.cpp b/source/linux/network/slirp2.cpp index 01d13085..43048085 100644 --- a/source/linux/network/slirp2.cpp +++ b/source/linux/network/slirp2.cpp @@ -39,7 +39,7 @@ namespace ssize_t net_slirp_send_packet(const void *buf, size_t len, void *opaque) { - SlirpNet * slirp = reinterpret_cast(opaque); + SlirpBackend * slirp = reinterpret_cast(opaque); slirp->sendToGuest(reinterpret_cast(buf), len); return len; } @@ -88,19 +88,19 @@ namespace int net_slirp_add_poll(int fd, int events, void *opaque) { - SlirpNet * slirp = reinterpret_cast(opaque); + SlirpBackend * slirp = reinterpret_cast(opaque); return slirp->addPoll(fd, events); } int net_slirp_get_revents(int idx, void *opaque) { - const SlirpNet * slirp = reinterpret_cast(opaque); + const SlirpBackend * slirp = reinterpret_cast(opaque); return slirp->getREvents(idx); } } -SlirpNet::SlirpNet() +SlirpBackend::SlirpBackend() { const SlirpConfig cfg = { @@ -128,12 +128,33 @@ SlirpNet::SlirpNet() mySlirp.reset(slirp, slirp_cleanup); } -void SlirpNet::sendFromGuest(const uint8_t *pkt, const int pkt_len) +void SlirpBackend::transmit(const int txlength, uint8_t *txframe) { - slirp_input(mySlirp.get(), pkt, pkt_len); + slirp_input(mySlirp.get(), txframe, txlength); } -void SlirpNet::sendToGuest(const uint8_t *pkt, int pkt_len) +int SlirpBackend::receive(const int size, uint8_t * rxframe) +{ + if (!myQueue.empty()) + { + const std::vector & packet = myQueue.front(); + int received = std::min(static_cast(packet.size()), size); + memcpy(rxframe, packet.data(), received); + if (received & 1) + { + rxframe[received] = 0; + ++received; + } + myQueue.pop(); + return received; + } + else + { + return -1; + } +} + +void SlirpBackend::sendToGuest(const uint8_t *pkt, int pkt_len) { if (myQueue.size() < ourQueueSize) { @@ -145,8 +166,9 @@ void SlirpNet::sendToGuest(const uint8_t *pkt, int pkt_len) } } -void SlirpNet::process(uint32_t timeout) +void SlirpBackend::update(const ULONG /* nExecutedCycles */) { + uint32_t timeout = 0; myFDs.clear(); slirp_pollfds_fill(mySlirp.get(), &timeout, net_slirp_add_poll, this); int pollout; @@ -161,26 +183,21 @@ void SlirpNet::process(uint32_t timeout) slirp_pollfds_poll(mySlirp.get(), (pollout <= 0), net_slirp_get_revents, this); } -int SlirpNet::addPoll(const int fd, const int events) +int SlirpBackend::addPoll(const int fd, const int events) { const pollfd ff = { .fd = fd, .events = vdeslirp_slirp_to_poll(events) }; myFDs.push_back(ff); return myFDs.size() - 1; } -int SlirpNet::getREvents(const int idx) const +int SlirpBackend::getREvents(const int idx) const { return vdeslirp_poll_to_slirp(myFDs[idx].revents); } -std::queue> & SlirpNet::getQueue() +bool SlirpBackend::isValid() { - return myQueue; -} - -void SlirpNet::clearQueue() -{ - std::queue>().swap(myQueue); + return true; } #endif diff --git a/source/linux/network/slirp2.h b/source/linux/network/slirp2.h index b4a89b34..4d9684ea 100644 --- a/source/linux/network/slirp2.h +++ b/source/linux/network/slirp2.h @@ -1,5 +1,7 @@ #pragma once +#include "Tfe/NetworkBackend.h" + #include "linux/config.h" #ifdef SLIRP_FOUND @@ -17,19 +19,21 @@ struct Slirp; -class SlirpNet +class SlirpBackend : public NetworkBackend { public: - SlirpNet(); - void sendFromGuest(const uint8_t *pkt, int pkt_len); + SlirpBackend(); + + void transmit(const int txlength, uint8_t *txframe) override; + int receive(const int size, uint8_t * rxframe) override; + + void update(const ULONG nExecutedCycles) override; + bool isValid() override; + void sendToGuest(const uint8_t *pkt, int pkt_len); - void process(const uint32_t timeout); int addPoll(const int fd, const int events); int getREvents(const int idx) const; - - std::queue> & getQueue(); - void clearQueue(); private: static constexpr size_t ourQueueSize = 10; diff --git a/source/linux/network/tfe2.cpp b/source/linux/network/tfe2.cpp deleted file mode 100644 index e299af62..00000000 --- a/source/linux/network/tfe2.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "StdAfx.h" -#include "linux/network/tfe2.h" - -#include "Tfe/tfearch.h" -#include "Tfe/tfe.h" - -namespace -{ - - bool shouldAccept(const uint8_t * mac, const BYTE *buffer, const int len) - { - if (len < 6) - { - return false; - } - - if (buffer[0] == mac[0] && - buffer[1] == mac[1] && - buffer[2] == mac[2] && - buffer[3] == mac[3] && - buffer[4] == mac[4] && - buffer[5] == mac[5]) - { - return true; - } - - if (buffer[0] == 0xFF && - buffer[1] == 0xFF && - buffer[2] == 0xFF && - buffer[3] == 0xFF && - buffer[4] == 0xFF && - buffer[5] == 0xFF) - { - return true; - } - - return false; - } - -} - -void tfeTransmitOnePacket(const BYTE * buffer, const int len) -{ - if (tfe_enabled) - { - tfe_arch_transmit(0, 0, 0, 0, len, const_cast(buffer)); - } -} - -bool tfeReceiveOnePacket(const uint8_t * mac, const int size, BYTE * buffer, int & len) -{ - if (!tfe_enabled) - { - return false; - } - - bool done; - - do - { - done = true; - int hashed; - int hash_index; - int rx_ok; - int correct_mac; - int broadcast; - int multicast = 0; - int crc_error; - - len = size; - const int newframe = tfe_arch_receive( - buffer, /* where to store a frame */ - &len, /* length of received frame */ - &hashed, /* set if the dest. address is accepted by the hash filter */ - &hash_index, /* hash table index if hashed == TRUE */ - &rx_ok, /* set if good CRC and valid length */ - &correct_mac, /* set if dest. address is exactly our IA */ - &broadcast, /* set if dest. address is a broadcast address */ - &crc_error /* set if received frame had a CRC error */ - ); - - if (newframe) - { - /* determine ourself the type of frame */ - if (shouldAccept(mac, buffer, len)) - { - return true; - } - else - { - done = false; /* try another frame */ - } - } - } while (!done); - return false; -} diff --git a/source/linux/network/tfe2.h b/source/linux/network/tfe2.h deleted file mode 100644 index c6d19d1c..00000000 --- a/source/linux/network/tfe2.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -bool tfeReceiveOnePacket(const uint8_t * mac, const int size, BYTE * buffer, int & len); -void tfeTransmitOnePacket(const BYTE * buffer, const int len); diff --git a/source/linux/network/uthernet2.cpp b/source/linux/network/uthernet2.cpp deleted file mode 100644 index 50d11487..00000000 --- a/source/linux/network/uthernet2.cpp +++ /dev/null @@ -1,1054 +0,0 @@ -#include -#include "linux/network/uthernet2.h" -#include "linux/network/slirp2.h" -#include "linux/network/registers.h" - -#include -#include -#include -#include -#include -#include - -// fix SOCK_NONBLOCK for e.g. macOS -#ifndef SOCK_NONBLOCK -// DISCALIMER -// totally untested, use at your own risk -#include -#define SOCK_NONBLOCK O_NONBLOCK -#endif - -#define MAX_RXLENGTH 1518 - -// #define U2_LOG_VERBOSE -// #define U2_LOG_TRAFFIC -// #define U2_LOG_STATE -// #define U2_LOG_UNKNOWN - -#ifndef U2_USE_SLIRP -#include "linux/network/tfe2.h" -#include "Tfe/tfe.h" -#endif - -#include "Memory.h" -#include "Log.h" - -namespace -{ - - uint16_t readNetworkWord(const uint8_t * address) - { - const uint16_t network = *reinterpret_cast(address); - const uint16_t host = ntohs(network); - return host; - } - - uint8_t getIByte(const uint16_t value, const size_t shift) - { - return (value >> shift) & 0xFF; - } - - void write8(Socket & socket, std::vector & memory, const uint8_t value) - { - const uint16_t base = socket.receiveBase; - const uint16_t address = base + socket.sn_rx_wr; - memory[address] = value; - socket.sn_rx_wr = (socket.sn_rx_wr + 1) % socket.receiveSize; - ++socket.sn_rx_rsr; - } - - // reverses the byte order - void write16(Socket & socket, std::vector & memory, const uint16_t value) - { - write8(socket, memory, getIByte(value, 8)); // high - write8(socket, memory, getIByte(value, 0)); // low - } - - void writeData(Socket & socket, std::vector & memory, const uint8_t * data, const size_t len) - { - for (size_t c = 0; c < len; ++c) - { - write8(socket, memory, data[c]); - } - } - - // no byte reversal - template - void writeAny(Socket & socket, std::vector & memory, const T & t) - { - const uint8_t * data = reinterpret_cast(&t); - const uint16_t len = sizeof(T); - writeData(socket, memory, data, len); - } - - void writeDataMacRaw(Socket & socket, std::vector & memory, const uint8_t * data, const size_t len) - { - // size includes sizeof(size) - const uint16_t size = len + sizeof(uint16_t); - write16(socket, memory, size); - writeData(socket, memory, data, len); - } - - void writeDataForProtocol(Socket & socket, std::vector & memory, const uint8_t * data, const size_t len, const sockaddr_in & source) - { - if (socket.sn_sr == SN_SR_SOCK_UDP) - { - // these are already in network order - writeAny(socket, memory, source.sin_addr); - writeAny(socket, memory, source.sin_port); - - // size does not include sizeof(size) - write16(socket, memory, len); - } // no header for TCP - - writeData(socket, memory, data, len); - } - -} - -Socket::Socket() - : sn_sr(SN_SR_CLOSED) - , myFD(-1) - , myErrno(0) -{ - -} - -void Socket::clearFD() -{ - if (myFD != -1) - { - close(myFD); - } - myFD = -1; - sn_sr = SN_SR_CLOSED; -} - -void Socket::setFD(const int fd, const int status) -{ - clearFD(); - myFD = fd; - myErrno = 0; - sn_sr = status; -} - -Socket::~Socket() -{ - clearFD(); -} - -void Socket::process() -{ - if (myFD != -1 && sn_sr == SN_SR_SOCK_INIT && myErrno == EINPROGRESS) - { - pollfd pfd = {.fd = myFD, .events = POLLOUT}; - if (poll(&pfd, 1, 0) > 0) - { - int err = 0; - socklen_t elen = sizeof err; - getsockopt(myFD, SOL_SOCKET, SO_ERROR, &err, &elen); - - if (err == 0) - { - myErrno = 0; - sn_sr = SN_SR_ESTABLISHED; -#ifdef U2_LOG_STATE - LogFileOutput("U2: TCP[]: CONNECTED\n"); -#endif - } - } - } -} - -bool Socket::isThereRoomFor(const size_t len, const size_t header) const -{ - const uint16_t rsr = sn_rx_rsr; // already present - const uint16_t size = receiveSize; // total size - -return rsr + len + header < size; // "not =": we do not want to fill the buffer. -} - -uint16_t Socket::getFreeRoom() const -{ - const uint16_t rsr = sn_rx_rsr; // already present - const uint16_t size = receiveSize; // total size - - return size - rsr; -} - -Uthernet2::Uthernet2(UINT slot) : Card(CT_Uthernet2, slot) -{ - #ifdef U2_USE_SLIRP - mySlirp = std::make_shared(); -#else - const int check = tfe_enabled; - tfe_init(true); - if (tfe_enabled != check) - { - // tfe initialisation failed - return; - } -#endif - Reset(true); -} - -void Uthernet2::setSocketModeRegister(const size_t i, const uint16_t address, const uint8_t value) -{ - myMemory[address] = value; - const uint8_t protocol = value & SN_MR_PROTO_MASK; - switch (protocol) - { - case SN_MR_CLOSED: -#ifdef U2_LOG_STATE - LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: CLOSED\n", i); -#endif - break; - case SN_MR_TCP: -#ifdef U2_LOG_STATE - LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: TCP\n", i); -#endif - break; - case SN_MR_UDP: -#ifdef U2_LOG_STATE - LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: UDP\n", i); -#endif - break; - case SN_MR_IPRAW: -#ifdef U2_LOG_STATE - LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: IPRAW\n", i); -#endif - break; - case SN_MR_MACRAW: -#ifdef U2_LOG_STATE - LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: MACRAW\n", i); -#endif - break; -#ifdef U2_LOG_UNKNOWN - default: - LogFileOutput("U2: Unknown protocol: %02x\n", protocol); -#endif - } -} - -void Uthernet2::setTXSizes(const uint16_t address, uint8_t value) -{ - myMemory[address] = value; - uint16_t base = TX_BASE; - const uint16_t end = RX_BASE; - for (Socket & socket : mySockets) - { - socket.transmitBase = base; - - const uint8_t bits = value & 0x03; - value >>= 2; - - const uint16_t size = 1 << (10 + bits); - base += size; - - if (base > end) - { - base = end; - } - socket.transmitSize = base - socket.transmitBase; - } -} - -void Uthernet2::setRXSizes(const uint16_t address, uint8_t value) -{ - myMemory[address] = value; - uint16_t base = RX_BASE; - const uint16_t end = MEM_SIZE; - for (Socket & socket : mySockets) - { - socket.receiveBase = base; - - const uint8_t bits = value & 0x03; - value >>= 2; - - const uint16_t size = 1 << (10 + bits); - base += size; - - if (base > end) - { - base = end; - } - socket.receiveSize = base - socket.receiveBase; - } -} - -uint16_t Uthernet2::getTXDataSize(const size_t i) const -{ - const Socket & socket = mySockets[i]; - const uint16_t size = socket.transmitSize; - const uint16_t mask = size - 1; - - const int sn_tx_rd = readNetworkWord(myMemory.data() + socket.registers + SN_TX_RD0) & mask; - const int sn_tx_wr = readNetworkWord(myMemory.data() + socket.registers + SN_TX_WR0) & mask; - - int dataPresent = sn_tx_wr - sn_tx_rd; - if (dataPresent < 0) - { - dataPresent += size; - } - return dataPresent; -} - -uint8_t Uthernet2::getTXFreeSizeRegister(const size_t i, const size_t shift) const -{ - const int size = mySockets[i].transmitSize; - const uint16_t present = getTXDataSize(i); - const uint16_t free = size - present; - const uint8_t reg = getIByte(free, shift); - return reg; -} - -uint8_t Uthernet2::getRXDataSizeRegister(const size_t i, const size_t shift) const -{ - const uint16_t rsr = mySockets[i].sn_rx_rsr; - const uint8_t reg = getIByte(rsr, shift); - return reg; -} - -void Uthernet2::updateRSR(const size_t i) -{ - Socket & socket = mySockets[i]; - - const int size = socket.receiveSize; - const uint16_t mask = size - 1; - - const int sn_rx_rd = readNetworkWord(myMemory.data() + socket.registers + SN_RX_RD0) & mask; - const int sn_rx_wr = socket.sn_rx_wr & mask; - int dataPresent = sn_rx_wr - sn_rx_rd; - if (dataPresent < 0) - { - dataPresent += size; - } - // is this logic correct? - // here we are re-synchronising the size with the pointers - // elsewhere I have seen people updating this value - // by the amount of how much 0x28 has moved forward - // but then we need to keep track of where it was - // the final result should be the same -#ifdef U2_LOG_TRAFFIC - if (socket.sn_rx_rsr != dataPresent) - { - LogFileOutput("U2: RECV[%" SIZE_T_FMT "]: %d -> %d bytes\n", i, socket.sn_rx_rsr, dataPresent); - } -#endif - socket.sn_rx_rsr = dataPresent; -} - -void Uthernet2::receiveOnePacketMacRaw(const size_t i) -{ - Socket & socket = mySockets[i]; - const uint16_t rsr = socket.sn_rx_rsr; - -#ifdef U2_USE_SLIRP - { - std::queue> & queue = mySlirp->getQueue(); - while (!queue.empty()) - { - const std::vector & packet = queue.front(); - if (socket.isThereRoomFor(packet.size(), sizeof(uint16_t))) - { - writeDataMacRaw(socket, myMemory, packet.data(), packet.size()); - queue.pop(); -#ifdef U2_LOG_TRAFFIC - LogFileOutput("U2: READ MACRAW[%" SIZE_T_FMT "]: +%" SIZE_T_FMT " -> %d bytes (%04x)\n", i, packet.size(), socket.sn_rx_rsr, socket.sn_rx_wr); -#endif - } - else - { - break; - } - } - } -#else - { - BYTE buffer[MAX_RXLENGTH]; - int len; - if (tfeReceiveOnePacket(myMemory.data() + SHAR0, sizeof(buffer), buffer, len)) - { - if (socket.isThereRoomFor(len, sizeof(uint16_t))) - { - writeDataMacRaw(socket, myMemory, buffer, len); -#ifdef U2_LOG_TRAFFIC - LogFileOutput("U2: READ MACRAW[%" SIZE_T_FMT "]: +%d -> %d bytes\n", i, len, socket.sn_rx_rsr); -#endif - } - else - { - // drop it -#ifdef U2_LOG_TRAFFIC - LogFileOutput("U2: SKIP MACRAW[%" SIZE_T_FMT "]: %d bytes\n", i, len); -#endif - } - } - } -#endif -} - -// UDP & TCP -void Uthernet2::receiveOnePacketFromSocket(const size_t i) -{ - Socket & socket = mySockets[i]; - if (socket.myFD != -1) - { - const uint16_t freeRoom = socket.getFreeRoom(); - if (freeRoom > 32) // avoid meaningless reads - { - std::vector buffer(freeRoom - 1); // do not fill the buffer completely - sockaddr_in source = {0}; - socklen_t len = sizeof(sockaddr_in); - const ssize_t data = recvfrom(socket.myFD, buffer.data(), buffer.size(), 0, (struct sockaddr *) &source, &len); -#ifdef U2_LOG_TRAFFIC - const char * proto = socket.sn_sr == SN_SR_SOCK_UDP ? "UDP" : "TCP"; -#endif - if (data > 0) - { - writeDataForProtocol(socket, myMemory, buffer.data(), data, source); -#ifdef U2_LOG_TRAFFIC - LogFileOutput("U2: READ %s[%" SIZE_T_FMT "]: +%" SIZE_T_FMT " -> %d bytes\n", proto, i, data, socket.sn_rx_rsr); -#endif - } - else if (data == 0) - { - // gracefull termination - socket.clearFD(); - } - else // data < 0; - { - const int error = errno; - if (error != EAGAIN && error != EWOULDBLOCK) - { -#ifdef U2_LOG_TRAFFIC - LogFileOutput("U2: ERROR %s[%" SIZE_T_FMT "]: %d\n", proto, i, error); -#endif - socket.clearFD(); - } - } - } - } -} - -void Uthernet2::receiveOnePacket(const size_t i) -{ - const Socket & socket = mySockets[i]; - switch (socket.sn_sr) - { - case SN_SR_SOCK_MACRAW: - receiveOnePacketMacRaw(i); - break; - case SN_SR_ESTABLISHED: - case SN_SR_SOCK_UDP: - receiveOnePacketFromSocket(i); - break; - case SN_SR_CLOSED: - break; // nothing to do -#ifdef U2_LOG_UNKNOWN - default: - LogFileOutput("U2: READ[%" SIZE_T_FMT "]: unknown mode: %02x\n", i, socket.sn_sr); -#endif - }; -} - -void Uthernet2::sendDataMacRaw(const size_t i, const std::vector & data) const -{ -#ifdef U2_LOG_TRAFFIC - LogFileOutput("U2: SEND MACRAW[%" SIZE_T_FMT "]: %" SIZE_T_FMT " bytes\n", i, data.size()); -#endif -#ifdef U2_USE_SLIRP - mySlirp->sendFromGuest(data.data(), data.size()); -#else - tfeTransmitOnePacket(data.data(), data.size()); -#endif -} - -void Uthernet2::sendDataToSocket(const size_t i, std::vector & data) -{ - Socket & socket = mySockets[i]; - if (socket.myFD != -1) - { - sockaddr_in destination = {}; - destination.sin_family = AF_INET; - - // already in network order - // this seems to be ignored for TCP, and so we reuse the same code - const uint8_t * dest = myMemory.data() + socket.registers + SN_DIPR0; - destination.sin_addr.s_addr = *reinterpret_cast(dest); - destination.sin_port = *reinterpret_cast(myMemory.data() + socket.registers + SN_DPORT0); - - const ssize_t res = sendto(socket.myFD, data.data(), data.size(), 0, (const struct sockaddr *) &destination, sizeof(destination)); -#ifdef U2_LOG_TRAFFIC - const char * proto = socket.sn_sr == SN_SR_SOCK_UDP ? "UDP" : "TCP"; - LogFileOutput("U2: SEND %s[%" SIZE_T_FMT "]: %" SIZE_T_FMT " of %" SIZE_T_FMT " bytes\n", proto, i, res, data.size()); -#endif - if (res < 0) - { - const int error = errno; - if (error != EAGAIN && error != EWOULDBLOCK) - { -#ifdef U2_LOG_TRAFFIC - LogFileOutput("U2: ERROR %s[%" SIZE_T_FMT "]: %d\n", proto, i, error); -#endif - socket.clearFD(); - } - } - } -} - -void Uthernet2::sendData(const size_t i) -{ - const Socket & socket = mySockets[i]; - const uint16_t size = socket.transmitSize; - const uint16_t mask = size - 1; - - const int sn_tx_rr = readNetworkWord(myMemory.data() + socket.registers + SN_TX_RD0) & mask; - const int sn_tx_wr = readNetworkWord(myMemory.data() + socket.registers + SN_TX_WR0) & mask; - - const uint16_t base = socket.transmitBase; - const uint16_t rr_address = base + sn_tx_rr; - const uint16_t wr_address = base + sn_tx_wr; - - std::vector data; - if (rr_address < wr_address) - { - data.assign(myMemory.begin() + rr_address, myMemory.begin() + wr_address); - } - else - { - const uint16_t end = base + size; - data.assign(myMemory.begin() + rr_address, myMemory.begin() + end); - data.insert(data.end(), myMemory.begin() + base, myMemory.begin() + wr_address); - } - - // move read pointer to writer - myMemory[socket.registers + SN_TX_RD0] = getIByte(sn_tx_wr, 8); - myMemory[socket.registers + SN_TX_RD1] = getIByte(sn_tx_wr, 0); - - switch (socket.sn_sr) - { - case SN_SR_SOCK_MACRAW: - sendDataMacRaw(i, data); - break; - case SN_SR_ESTABLISHED: - case SN_SR_SOCK_UDP: - sendDataToSocket(i, data); - break; -#ifdef U2_LOG_UNKNOWN - default: - LogFileOutput("U2: SEND[%" SIZE_T_FMT "]: unknown mode: %02x\n", i, socket.sn_sr); -#endif - } -} - -void Uthernet2::resetRXTXBuffers(const size_t i) -{ - Socket & socket = mySockets[i]; - socket.sn_rx_wr = 0x00; - socket.sn_rx_rsr = 0x00; - myMemory[socket.registers + SN_TX_RD0] = 0x00; - myMemory[socket.registers + SN_TX_RD1] = 0x00; - myMemory[socket.registers + SN_TX_WR0] = 0x00; - myMemory[socket.registers + SN_TX_WR1] = 0x00; - myMemory[socket.registers + SN_RX_RD0] = 0x00; - myMemory[socket.registers + SN_RX_RD1] = 0x00; -} - -void Uthernet2::openSystemSocket(const size_t i, const int type, const int protocol, const int state) -{ - Socket & s = mySockets[i]; - const int fd = socket(AF_INET, type | SOCK_NONBLOCK, protocol); - if (fd < -1) - { -#ifdef U2_LOG_STATE - const char * proto = state == SN_SR_SOCK_UDP ? "UDP" : "TCP"; - LogFileOutput("U2: %s[%" SIZE_T_FMT "]: %s\n", proto, i, strerror(errno)); -#endif - s.clearFD(); - } - else - { - s.setFD(fd, state); - } -} - -void Uthernet2::openSocket(const size_t i) -{ - Socket & socket = mySockets[i]; - const uint8_t mr = myMemory[socket.registers + SN_MR]; - const uint8_t protocol = mr & SN_MR_PROTO_MASK; - uint8_t & sr = socket.sn_sr; - switch (protocol) - { - case SN_MR_IPRAW: - sr = SN_SR_SOCK_IPRAW; - break; - case SN_MR_MACRAW: - sr = SN_SR_SOCK_MACRAW; - break; - case SN_MR_TCP: - openSystemSocket(i, SOCK_STREAM, IPPROTO_TCP, SN_SR_SOCK_INIT); - break; - case SN_MR_UDP: - openSystemSocket(i, SOCK_DGRAM, IPPROTO_UDP, SN_SR_SOCK_UDP); - break; -#ifdef U2_LOG_UNKNOWN - default: - LogFileOutput("U2: OPEN[%" SIZE_T_FMT "]: unknown mode: %02x\n", i, mr); -#endif - } - resetRXTXBuffers(i); // needed? -#ifdef U2_LOG_STATE - LogFileOutput("U2: OPEN[%" SIZE_T_FMT "]: %02x\n", i, sr); -#endif -} - -void Uthernet2::closeSocket(const size_t i) -{ - Socket & socket = mySockets[i]; - socket.clearFD(); -#ifdef U2_LOG_STATE - LogFileOutput("U2: CLOSE[%" SIZE_T_FMT "]\n", i); -#endif -} - -void Uthernet2::connectSocket(const size_t i) -{ - Socket & socket = mySockets[i]; - const uint8_t * dest = myMemory.data() + socket.registers + SN_DIPR0; - - sockaddr_in destination = {}; - destination.sin_family = AF_INET; - - // already in network order - destination.sin_port = *reinterpret_cast(myMemory.data() + socket.registers + SN_DPORT0); - destination.sin_addr.s_addr = *reinterpret_cast(dest); - - const int res = connect(socket.myFD, (struct sockaddr *)&destination, sizeof(destination)); - - if (res == 0) - { - socket.sn_sr = SN_SR_ESTABLISHED; - socket.myErrno = 0; -#ifdef U2_LOG_STATE - const uint16_t port = readNetworkWord(myMemory.data() + socket.registers + SN_DPORT0); - LogFileOutput("U2: TCP[%" SIZE_T_FMT "]: CONNECT to %d.%d.%d.%d:%d\n", i, dest[0], dest[1], dest[2], dest[3], port); -#endif - } - else - { - const int error = errno; - if (error == EINPROGRESS) - { - socket.myErrno = error; - } -#ifdef U2_LOG_STATE - LogFileOutput("U2: TCP[%" SIZE_T_FMT "]: connect: %s\n", i, strerror(error)); -#endif - } -} - -void Uthernet2::setCommandRegister(const size_t i, const uint8_t value) -{ - switch (value) - { - case SN_CR_OPEN: - openSocket(i); - break; - case SN_CR_CONNECT: - connectSocket(i); - break; - case SN_CR_CLOSE: - case SN_CR_DISCON: - closeSocket(i); - break; - case SN_CR_SEND: - sendData(i); - break; - case SN_CR_RECV: - updateRSR(i); - break; -#ifdef U2_LOG_UNKNOWN - default: - LogFileOutput("U2: Unknown command[%" SIZE_T_FMT "]: %02x\n", i, value); -#endif - } -} - -uint8_t Uthernet2::readSocketRegister(const uint16_t address) -{ - const uint16_t i = (address >> 8) - 0x04; - const uint16_t loc = address & 0xFF; - uint8_t value; - switch (loc) - { - case SN_MR: - case SN_CR: - value = myMemory[address]; - break; - case SN_SR: - value = mySockets[i].sn_sr; - break; - case SN_TX_FSR0: - value = getTXFreeSizeRegister(i, 8); - break; - case SN_TX_FSR1: - value = getTXFreeSizeRegister(i, 0); - break; - case SN_TX_RD0: - case SN_TX_RD1: - value = myMemory[address]; - break; - case SN_TX_WR0: - case SN_TX_WR1: - value = myMemory[address]; - break; - case SN_RX_RSR0: - receiveOnePacket(i); - value = getRXDataSizeRegister(i, 8); - break; - case SN_RX_RSR1: - receiveOnePacket(i); - value = getRXDataSizeRegister(i, 0); - break; - case SN_RX_RD0: - case SN_RX_RD1: - value = myMemory[address]; - break; - default: -#ifdef U2_LOG_UNKNOWN - LogFileOutput("U2: Get unknown socket register[%d]: %04x\n", i, address); -#endif - value = myMemory[address]; - break; - } - return value; -} - -uint8_t Uthernet2::readValueAt(const uint16_t address) -{ - uint8_t value; - switch (address) - { - case MR: - value = myModeRegister; - break; - case GAR0 ... UPORT1: - value = myMemory[address]; - break; - case S0_BASE ... S3_MAX: - value = readSocketRegister(address); - break; - case TX_BASE ... MEM_MAX: - value = myMemory[address]; - break; - default: -#ifdef U2_LOG_UNKNOWN - LogFileOutput("U2: Read unknown location: %04x\n", address); -#endif - // this might not be 100% correct if address >= 0x8000 - // see top of page 13 Uthernet II - value = myMemory[address & MEM_MAX]; - break; - } - return value; -} - -void Uthernet2::autoIncrement() -{ - if (myModeRegister & MR_AI) - { - ++myDataAddress; - // Read bottom of Uthernet II page 12 - // Setting the address to values >= 0x8000 is not really supported - switch (myDataAddress) - { - case RX_BASE: - case MEM_SIZE: - myDataAddress -= 0x2000; - break; - } - } -} - -uint8_t Uthernet2::readValue() -{ - const uint8_t value = readValueAt(myDataAddress); - autoIncrement(); - return value; -} - -void Uthernet2::setIPProtocol(const size_t i, const uint16_t address, const uint8_t value) -{ - myMemory[address] = value; -#ifdef U2_LOG_STATE - LogFileOutput("U2: IP PROTO[%" SIZE_T_FMT "] = %d\n", i, value); -#endif -} - -void Uthernet2::setIPTypeOfService(const size_t i, const uint16_t address, const uint8_t value) -{ - myMemory[address] = value; -#ifdef U2_LOG_STATE - LogFileOutput("U2: IP TOS[%" SIZE_T_FMT "] = %d\n", i, value); -#endif -} - -void Uthernet2::setIPTTL(const size_t i, const uint16_t address, const uint8_t value) -{ - myMemory[address] = value; -#ifdef U2_LOG_STATE - LogFileOutput("U2: IP TTL[%" SIZE_T_FMT "] = %d\n", i, value); -#endif -} - -void Uthernet2::writeSocketRegister(const uint16_t address, const uint8_t value) -{ - const uint16_t i = (address >> 8) - 0x04; - const uint16_t loc = address & 0xFF; - switch (loc) - { - case SN_MR: - setSocketModeRegister(i, address, value); - break; - case SN_CR: - setCommandRegister(i, value); - break; - case SN_PORT0: - case SN_PORT1: - case SN_DPORT0: - case SN_DPORT1: - myMemory[address] = value; - break; - case SN_DIPR0 ... SN_DIPR3: - myMemory[address] = value; - break; - case SN_PROTO: - setIPProtocol(i, address, value); - break; - case SN_TOS: - setIPTypeOfService(i, address, value); - break; - case SN_TTL: - setIPTTL(i, address, value); - break; - case SN_TX_WR0: - myMemory[address] = value; - break; - case SN_TX_WR1: - myMemory[address] = value; - break; - case SN_RX_RD0: - myMemory[address] = value; - break; - case SN_RX_RD1: - myMemory[address] = value; - break; -#ifdef U2_LOG_UNKNOWN - default: - LogFileOutput("U2: Set unknown socket register[%d]: %04x\n", i, address); - break; -#endif - }; -} - -void Uthernet2::setModeRegister(const uint16_t address, const uint8_t value) -{ - if (value & MR_RST) - { - Reset(false); - } - else - { - myModeRegister = value; - } -} - -void Uthernet2::writeCommonRegister(const uint16_t address, const uint8_t value) -{ - switch (address) - { - case MR: - setModeRegister(address, value); - break; - case GAR0 ... GAR3: - case SUBR0 ... SUBR3: - case SHAR0 ... SHAR5: - case SIPR0 ... SIPR3: - myMemory[address] = value; - break; - case RMSR: - setRXSizes(address, value); - break; - case TMSR: - setTXSizes(address, value); - break; -#ifdef U2_LOG_UNKNOWN - default: - LogFileOutput("U2: Set unknown common register: %04x\n", address); - break; -#endif - }; -} - -void Uthernet2::writeValueAt(const uint16_t address, const uint8_t value) -{ - switch (address) - { - case MR ... UPORT1: - writeCommonRegister(address, value); - break; - case S0_BASE ... S3_MAX: - writeSocketRegister(address, value); - break; - case TX_BASE ... MEM_MAX: - myMemory[address] = value; - break; -#ifdef U2_LOG_UNKNOWN - default: - LogFileOutput("U2: Write to unknown location: %02x to %04x\n", value, address); - break; -#endif - } -} - -void Uthernet2::writeValue(const uint8_t value) -{ - writeValueAt(myDataAddress, value); - autoIncrement(); -} - -void Uthernet2::Reset(const bool powerCycle) -{ - LogFileOutput("U2: Uthernet 2 initialisation\n"); - myModeRegister = 0; - - if (powerCycle) - { - // dataAddress is NOT reset, see page 10 of Uthernet II - myDataAddress = 0; - } - - mySockets.resize(4); - myMemory.clear(); - myMemory.resize(MEM_SIZE, 0); - - for (size_t i = 0; i < mySockets.size(); ++i) - { - mySockets[i].clearFD(); - mySockets[i].registers = S0_BASE + (i << 8); - } - - // initial values - myMemory[RTR0] = 0x07; - myMemory[RTR1] = 0xD0; - setRXSizes(RMSR, 0x55); - setTXSizes(TMSR, 0x55); - -#ifdef U2_USE_SLIRP - mySlirp->clearQueue(); -#endif -} - -BYTE Uthernet2::IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles) -{ - BYTE res = write ? 0 : MemReadFloatingBus(nCycles); - -#ifdef U2_LOG_VERBOSE - const uint16_t oldAddress = myDataAddress; -#endif - - const uint8_t loc = address & 0x0F; - - if (write) - { - switch (loc) - { - case C0X_MODE_REGISTER: - setModeRegister(MR, value); - break; - case C0X_ADDRESS_HIGH: - myDataAddress = (value << 8) | (myDataAddress & 0x00FF); - break; - case C0X_ADDRESS_LOW: - myDataAddress = (value << 0) | (myDataAddress & 0xFF00); - break; - case C0X_DATA_PORT: - writeValue(value); - break; - } - } - else - { - switch (loc) - { - case C0X_MODE_REGISTER: - res = myModeRegister; - break; - case C0X_ADDRESS_HIGH: - res = getIByte(myDataAddress, 8); - break; - case C0X_ADDRESS_LOW: - res = getIByte(myDataAddress, 0); - break; - case C0X_DATA_PORT: - res = readValue(); - break; - } - } - -#ifdef U2_LOG_VERBOSE - const char * mode = write ? "WRITE " : "READ "; - const char c = std::isprint(res) ? res : '.'; - LogFileOutput("U2: %04x: %s %04x[%04x] %02x = %02x, %c [%3d = %3d]\n", programcounter, mode, address, oldAddress, value, res, c, value, res); -#endif - - return res; -} - -BYTE u2_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles) -{ - UINT uSlot = ((address & 0xff) >> 4) - 8; - Uthernet2* pCard = (Uthernet2*) MemGetSlotParameters(uSlot); - return pCard->IO_C0(programcounter, address, write, value, nCycles); -} - -void Uthernet2::processEvents(uint32_t timeout) -{ -#ifdef U2_USE_SLIRP - if (mySlirp) - { - mySlirp->process(timeout); - } -#endif - for (Socket & socket : mySockets) - { - socket.process(); - } -} - -void Uthernet2::InitializeIO(LPBYTE pCxRomPeripheral) -{ - RegisterIoHandler(m_slot, u2_C0, u2_C0, nullptr, nullptr, this, nullptr); -} - -void Uthernet2::Init() -{ - -} - -void Uthernet2::Update(const ULONG nExecutedCycles) -{ - processEvents(0); -} - -void Uthernet2::SaveSnapshot(YamlSaveHelper& yamlSaveHelper) -{ - -} - -bool Uthernet2::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version) -{ - return true; -} diff --git a/source/linux/network/uthernet2.h b/source/linux/network/uthernet2.h deleted file mode 100644 index e0a952c1..00000000 --- a/source/linux/network/uthernet2.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -#include "Card.h" - -#include - -class SlirpNet; - -struct Socket -{ - uint16_t transmitBase; - uint16_t transmitSize; - uint16_t receiveBase; - uint16_t receiveSize; - uint16_t registers; - - uint16_t sn_rx_wr; - uint16_t sn_rx_rsr; - - uint8_t sn_sr; - - int myFD; - int myErrno; - - void clearFD(); - void setFD(const int fd, const int status); - void process(); - - bool isThereRoomFor(const size_t len, const size_t header) const; - uint16_t getFreeRoom() const; - - Socket(); - - ~Socket(); -}; - -class Uthernet2 : public Card -{ -public: - Uthernet2(UINT slot); - - virtual void InitializeIO(LPBYTE pCxRomPeripheral); - virtual void Init(); - virtual void Reset(const bool powerCycle); - virtual void Update(const ULONG nExecutedCycles); - virtual void SaveSnapshot(YamlSaveHelper& yamlSaveHelper); - virtual bool LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version); - - BYTE IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles); - -private: - std::vector myMemory; - std::vector mySockets; - uint8_t myModeRegister; - uint16_t myDataAddress; - std::shared_ptr mySlirp; - - void setSocketModeRegister(const size_t i, const uint16_t address, const uint8_t value); - void setTXSizes(const uint16_t address, uint8_t value); - void setRXSizes(const uint16_t address, uint8_t value); - uint16_t getTXDataSize(const size_t i) const; - uint8_t getTXFreeSizeRegister(const size_t i, const size_t shift) const; - uint8_t getRXDataSizeRegister(const size_t i, const size_t shift) const; - - void receiveOnePacketMacRaw(const size_t i); - void receiveOnePacketFromSocket(const size_t i); - void receiveOnePacket(const size_t i); - - void sendDataMacRaw(const size_t i, const std::vector & data) const; - void sendDataToSocket(const size_t i, std::vector & data); - void sendData(const size_t i); - - void resetRXTXBuffers(const size_t i); - void updateRSR(const size_t i); - - void openSystemSocket(const size_t i, const int type, const int protocol, const int state); - void openSocket(const size_t i); - void closeSocket(const size_t i); - void connectSocket(const size_t i); - - void setCommandRegister(const size_t i, const uint8_t value); - - uint8_t readSocketRegister(const uint16_t address); - uint8_t readValueAt(const uint16_t address); - - void autoIncrement(); - uint8_t readValue(); - - void setIPProtocol(const size_t i, const uint16_t address, const uint8_t value); - void setIPTypeOfService(const size_t i, const uint16_t address, const uint8_t value); - void setIPTTL(const size_t i, const uint16_t address, const uint8_t value); - void writeSocketRegister(const uint16_t address, const uint8_t value); - - void setModeRegister(const uint16_t address, const uint8_t value); - void writeCommonRegister(const uint16_t address, const uint8_t value); - void writeValueAt(const uint16_t address, const uint8_t value); - void writeValue(const uint8_t value); - - void processEvents(uint32_t timeout); -};