Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Andrea Odetti 2022-03-23 09:50:40 +00:00
commit 49885bbecb
20 changed files with 566 additions and 75 deletions

View file

@ -114,6 +114,7 @@
<ClInclude Include="source\StrFormat.h" />
<ClInclude Include="source\SynchronousEventManager.h" />
<ClInclude Include="source\Tape.h" />
<ClInclude Include="source\Tfe\IPRaw.h" />
<ClInclude Include="source\Tfe\NetworkBackend.h" />
<ClInclude Include="source\Tfe\Bpf.h" />
<ClInclude Include="source\Tfe\Ip6_misc.h" />
@ -222,6 +223,7 @@
<ClCompile Include="source\StrFormat.cpp" />
<ClCompile Include="source\SynchronousEventManager.cpp" />
<ClCompile Include="source\Tape.cpp" />
<ClCompile Include="source\Tfe\IPRaw.cpp" />
<ClCompile Include="source\Tfe\NetworkBackend.cpp" />
<ClCompile Include="source\Tfe\PCapBackend.cpp" />
<ClCompile Include="source\Tfe\tfearch.cpp">
@ -467,7 +469,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
</Link>
@ -495,7 +497,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;ddraw_lib\x86\dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw_lib\x86\ddraw.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;ddraw_lib\x86\dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw_lib\x86\ddraw.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
</Link>
@ -522,7 +524,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
</Link>
@ -553,7 +555,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
@ -586,7 +588,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;ddraw_lib\x86\dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw_lib\x86\ddraw.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;ddraw_lib\x86\dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw_lib\x86\ddraw.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
@ -619,7 +621,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>

View file

@ -259,6 +259,9 @@
<ClCompile Include="source\Uthernet2.cpp">
<Filter>Source Files\Uthernet</Filter>
</ClCompile>
<ClCompile Include="source\Tfe\IPRaw.cpp">
<Filter>Source Files\Uthernet</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="source\CommonVICE\6510core.h">
@ -594,6 +597,9 @@
<ClInclude Include="source\Uthernet2.h">
<Filter>Source Files\Uthernet</Filter>
</ClInclude>
<ClInclude Include="source\Tfe\IPRaw.h">
<Filter>Source Files\Uthernet</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="resource\Applewin.bmp">

View file

@ -5,7 +5,7 @@ AppleWin
AppleWin is a fully-featured emulator supporting different Apple II models and clones. A variety of peripheral cards and video display modes are supported (eg. NTSC, RGB); and there's an extensive built-in symbolic debugger.
Peripheral cards supported:
Peripheral cards and add-on hardware supported:
- Mockingboard, Phasor and SAM sound cards
- Disk II interface for floppy disk drives
- Hard disk controller
@ -17,6 +17,8 @@ Peripheral cards supported:
- CP/M SoftCard
- Uthernet I (ethernet card)
- Language Card and Saturn 64/128K for Apple II/II+
- 4Play and SNES MAX joystick cards
- VidHD card (functionality limited to IIgs' Super Hi-Res video modes)
- No Slot Clock (NSC)

View file

@ -21,7 +21,7 @@
<p style="MARGIN-LEFT: 40px">Bob Sander-Cederlof: Applesoft Symbols (<a href="http://www.txbobsc.com/scsc/scdocumentor/index.html">http://www.txbobsc.com/scsc/scdocumentor/</a> S-C DocuMentor: Applesoft)</p>
<p style="MARGIN-LEFT: 40px">David Schmidt: Updates to this help file</p>
<p style="MARGIN-LEFT: 40px">Mike Harvey, Founder &amp; Editor of Nibble Magazine: For providing us Apple fans the pleasure of eagerly awaiting each next month's issue to learn about the Apple! (<a href="http://www.nibblemagazine.com/">http://www.nibblemagazine.com/</a>)</p>
<p style="MARGIN-LEFT: 40px">Andrea Odetti: working on making the source code more portable</p>
<p style="MARGIN-LEFT: 40px">Andrea Odetti: working on making the source code more portable & Uthernet II card support</p>
<p style="MARGIN-LEFT: 40px">Iván Izaguirre: Taiwanese Copam Base64A Apple II clone</p>
<p style="MARGIN-LEFT: 40px">Arnaud C: debugger suggestions and help with 6502/6522/video timing issues</p>
<p style="MARGIN-LEFT: 40px">Cyril Lambin: RGB card/monitor rendering, debugger improvements</p>

View file

@ -78,7 +78,7 @@
<strong>Ethernet Settings...:</strong><br>
This allows to choose which network interface card (NIC) you want to
use with the Uthernet card.<br>
use with the Uthernet or Uthernet II card.<br>
<br>
<strong>Emulation Speed Control:</strong><br>

View file

@ -32,7 +32,7 @@
<li>Parallel Printer card</li>
<li>Super Serial card</li>
<li>No-Slot clock</li>
<li>Uthernet card</li>
<li>Uthernet & Uthernet II cards</li>
<li>4Play & SNES MAX joystick cards</li>
<li>VidHD card</li>
</ul>

View file

@ -31,7 +31,7 @@
<li><a href="sound.html">Sound</a>
<li><a href="clock.html">Clock</a>
<li><a href="card-ssc.html">Super Serial card</a>
<li><a href="uthernet.html">Uthernet network card</a>
<li><a href="uthernet.html">Uthernet network cards</a>
<li><a href="configuration.html">AppleWin Configuration</a>
<li><a href="dbg-toc-intro.html">Using the Debugger</a>
<li><a href="resources.html">Resources</a></li>

View file

@ -1,22 +1,23 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Uthernet network card</title>
<title>Uthernet network cards</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
</head>
<body style="FONT-FAMILY: verdana; BACKGROUND-COLOR: rgb(255,255,255)" alink="#008000"
link="#008000" vlink="#008000">
<h2 style="COLOR: rgb(0,128,0)">Uthernet network card</h2>
<h2 style="COLOR: rgb(0,128,0)">Uthernet network cards</h2>
<hr size="4">
<p style="FONT-WEIGHT: bold">Overview:
</p>
<P>The Uthernet network card coupled with the Contiki OS allows you to browse the
<P>The Uthernet network cards coupled with the Contiki OS allow you to browse the
internet on your Apple.</P>
<P style="FONT-WEIGHT: bold">Acknowledgment:
</P>
<P>Uthernet (TFE) support in Applewin was made possible by implementing the GPL
<P>Uthernet (TFE) support in AppleWin was made possible by implementing the GPL
source written by Spiro Trikaliotis for the Vice emulator - <A href="http://vice-emu.sourceforge.net/index.html#developers">
http://vice-emu.sourceforge.net/index.html#developers</A></P>
<P><A href="https://a2retrosystems.com/">Uthernet II</A> support in AppleWin has been contributed by Andrea (audetto) Odetti.</P>
<P style="FONT-WEIGHT: bold">Details:
</P>
<P>To enable ethernet support in AppleWin you must first download and install
@ -35,15 +36,15 @@
<P>After AppleWin starts, select the settings icon and then select the ethernet
settings button.
</P>
<P>Uthernet will be disabled. Select Uthernet from the list of available ethernet
emulations (currently the only one).
<P>Uthernet will be disabled. Select Uthernet or Uthernet II from the list of available ethernet
emulations.
</P>
<P>Select the ethernet interface you want to work with. This must be a physical
ethernet interface.
</P>
<P>If you have more than one interface you may need to select them in turn in order
to get the text description for each interface vs what Npcap likes to use for
a reference. Select Ok. and then close AppleWin.
a reference.
</P>
<P><span style="font-weight: bold;">Note:</span> Wireless does not work
with WinPcap (but see <A href="uthernet-wifi-workaround.html">WiFi Workaround</A>).
@ -56,7 +57,7 @@
also grab a copy of the Uthernet/Contiki getting started guide <A href="http://www.a2retrosystems.com/a2UtherManual.pdf">
http://www.a2retrosystems.com/a2UtherManual.pdf</A>
</P>
<P>When you run AppleWin again, select the contiki80pri.dsk image. Boot AppleWin.
<P>Select the contiki80pri.dsk image. Boot AppleWin.
</P>
<P>Once Contiki is loaded then press Enter to clear the welcome screen and press
ESC for a menu.
@ -87,5 +88,14 @@
if you are still having difficulty then you should refer to the VICE network
support page for additional information - <A href="http://vicekb.trikaliotis.net/13-005.shtml">
http://vicekb.trikaliotis.net/13-005.shtml</A></P>
</body>
<P style="FONT-WEIGHT: bold">Uthernet II:
</P>
<P>Most features of the Uthernet II are emulated, with the following caveats:
<ul>
<li>PPPoE, interrupts and SPI are not implemented</li>
<li>server side is not well tested</li>
<li>after loading a save-state file, TCP and UDP sockets are closed</li>
</ul>
</P>
</body>
</html>

View file

@ -443,7 +443,7 @@ bool Saturn128K::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
}
// "Memory Bankxx"
std::string memName = GetSnapshotMemStructName() + StrFormat("%02X", uBank);
std::string memName = GetSnapshotMemStructName() + ByteToHexStr(uBank);
if (!yamlLoadHelper.GetSubMap(memName))
throw std::runtime_error("Memory: Missing map name: " + memName);

View file

@ -2443,7 +2443,7 @@ static void MemLoadSnapshotAuxCommon(YamlLoadHelper& yamlLoadHelper, const std::
}
// "Auxiliary Memory Bankxx"
std::string auxMemName = MemGetSnapshotAuxMemStructName() + StrFormat("%02X", uBank-1);
std::string auxMemName = MemGetSnapshotAuxMemStructName() + ByteToHexStr(uBank-1);
if (!yamlLoadHelper.GetSubMap(auxMemName))
throw std::runtime_error("Memory: Missing map name: " + auxMemName);

View file

@ -86,7 +86,7 @@ void SSI_Output(void)
LogOutput("SSI: ");
for (int i = 0; i <= 4; i++)
{
std::string r = (ssiRegs[i] >= 0) ? StrFormat("%02X", ssiRegs[i]) : "--";
std::string r = (ssiRegs[i] >= 0) ? ByteToHexStr(ssiRegs[i]) : "--";
LogOutput("%s ", r.c_str());
ssiRegs[i] = -1;
}

View file

@ -6,6 +6,7 @@
#if defined(_MSC_VER) && _MSC_VER < 1600
#include <basetsd.h>
typedef UINT8 uint8_t;
typedef UINT16 uint16_t;
#else
#include <cstdint>
#endif
@ -19,10 +20,59 @@ typedef UINT8 uint8_t;
std::string StrFormat(const char* format, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
std::string StrFormatV(const char* format, va_list va);
namespace {
const char g_aHexDigits[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
};
// No buffer overflow check or null termination. Use with caution.
inline char* StrBufferAppendByteAsHex(char* cp, uint8_t n)
{
*cp++ = g_aHexDigits[(n >> 4) & 0x0f];
*cp++ = g_aHexDigits[(n >> 0) & 0x0f];
return cp;
}
// No buffer overflow check or null termination. Use with caution.
inline char* StrBufferAppendWordAsHex(char* cp, uint16_t n)
{
*cp++ = g_aHexDigits[(n >> 12) & 0x0f];
*cp++ = g_aHexDigits[(n >> 8) & 0x0f];
*cp++ = g_aHexDigits[(n >> 4) & 0x0f];
*cp++ = g_aHexDigits[(n >> 0) & 0x0f];
return cp;
}
inline std::string& StrAppendByteAsHex(std::string& s, uint8_t n)
{
const char szHex[] = "0123456789ABCDEF";
s += szHex[(n >> 4) & 0x0f];
s += szHex[n & 0x0f];
const char hex[2] = { g_aHexDigits[(n >> 4) & 0x0f],
g_aHexDigits[(n >> 0) & 0x0f] };
return s.append(hex, 2);
}
inline std::string& StrAppendWordAsHex(std::string& s, uint16_t n)
{
const char hex[4] = { g_aHexDigits[(n >> 12) & 0x0f],
g_aHexDigits[(n >> 8) & 0x0f],
g_aHexDigits[(n >> 4) & 0x0f],
g_aHexDigits[(n >> 0) & 0x0f] };
return s.append(hex, 4);
}
inline std::string ByteToHexStr(uint8_t n)
{
std::string s;
StrAppendByteAsHex(s, n);
return s;
}
inline std::string WordToHexStr(uint16_t n)
{
std::string s;
StrAppendWordAsHex(s, n);
return s;
}
} // namespace

162
source/Tfe/IPRaw.cpp Normal file
View file

@ -0,0 +1,162 @@
/*
AppleWin : An Apple //e emulator for Windows
Copyright (C) 2022, Andrea Odetti
AppleWin is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
AppleWin is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with AppleWin; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "StdAfx.h"
#include "IPRaw.h"
#ifndef _MSC_VER
#include <arpa/inet.h>
#endif
#define IPV4 0x04
namespace
{
#pragma pack(push)
#pragma pack(1) // Ensure struct is packed
struct IP4Header
{
uint8_t ihl : 4;
uint8_t version : 4;
uint8_t tos;
uint16_t len;
uint16_t id;
uint16_t flags : 3;
uint16_t fragmentOffset : 13;
uint8_t ttl;
uint8_t proto;
uint16_t checksum;
uint32_t sourceAddress;
uint32_t destinationAddress;
};
struct ETH2Frame
{
uint8_t destinationMac[6];
uint8_t sourceMac[6];
uint16_t type;
};
#pragma pack(pop)
uint32_t sum_every_16bits(const void *addr, int count)
{
uint32_t sum = 0;
const uint16_t *ptr = reinterpret_cast<const uint16_t *>(addr);
while (count > 1)
{
/* This is the inner loop */
sum += *ptr++;
count -= 2;
}
/* Add left-over byte, if any */
if (count > 0)
sum += *reinterpret_cast<const uint8_t *>(ptr);
return sum;
}
uint16_t checksum(const void *addr, int count)
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
* Taken from https://tools.ietf.org/html/rfc1071
*/
uint32_t sum = sum_every_16bits(addr, count);
/* Fold 32-bit sum to 16 bits */
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
return ~sum;
}
// get the minimum size of a ETH Frame that contains a IP payload
// 34 = 14 bytes for ETH2 + 20 bytes IPv4 (minimum)
int getIPMinimumSize()
{
const int minimumSize = sizeof(ETH2Frame) + sizeof(IP4Header) + 0; // 0 len
return minimumSize;
}
}
std::vector<uint8_t> createETH2Frame(const std::vector<uint8_t> &data,
const MACAddress *sourceMac, const MACAddress *destinationMac,
const uint8_t ttl, const uint8_t tos, const uint8_t protocol,
const uint32_t sourceAddress, const uint32_t destinationAddress)
{
const size_t total = sizeof(ETH2Frame) + sizeof(IP4Header) + data.size();
std::vector<uint8_t> frame(total);
ETH2Frame *eth2frame = reinterpret_cast<ETH2Frame *>(frame.data() + 0);
memcpy(eth2frame->destinationMac, destinationMac, sizeof(eth2frame->destinationMac));
memcpy(eth2frame->sourceMac, sourceMac, sizeof(eth2frame->destinationMac));
eth2frame->type = htons(0x0800);
IP4Header *ip4header = reinterpret_cast<IP4Header *>(frame.data() + sizeof(ETH2Frame));
ip4header->version = IPV4;
ip4header->ihl = 0x05; // minimum size = 20 bytes, without any extra option
ip4header->tos = tos;
ip4header->len = htons(static_cast<uint16_t>(sizeof(IP4Header) + data.size()));
ip4header->id = 0;
ip4header->fragmentOffset = 0;
ip4header->ttl = ttl;
ip4header->proto = protocol;
ip4header->sourceAddress = sourceAddress;
ip4header->destinationAddress = destinationAddress;
ip4header->checksum = checksum(ip4header, sizeof(IP4Header));
memcpy(frame.data() + sizeof(ETH2Frame) + sizeof(IP4Header), data.data(), data.size());
return frame;
}
void getIPPayload(const int lengthOfFrame, const uint8_t *frame,
size_t &lengthOfPayload, const uint8_t *&payload, uint32_t &destination, uint8_t &protocol)
{
const int minimumSize = getIPMinimumSize();
if (lengthOfFrame > minimumSize)
{
const ETH2Frame *eth2Frame = reinterpret_cast<const ETH2Frame *>(frame);
const IP4Header *ip4header = reinterpret_cast<const IP4Header *>(frame + sizeof(ETH2Frame));
if (eth2Frame->type == htons(0x0800) && ip4header->version == IPV4)
{
const uint16_t ipv4HeaderSize = ip4header->ihl * 4;
const uint16_t ipPacketSize = ntohs(ip4header->len);
const int expectedSize = sizeof(ETH2Frame) + ipPacketSize;
if (ipPacketSize > ipv4HeaderSize && lengthOfFrame >= expectedSize)
{
protocol = ip4header->proto;
payload = frame + sizeof(ETH2Frame) + ipv4HeaderSize;
lengthOfPayload = ipPacketSize - ipv4HeaderSize;
destination = ip4header->destinationAddress;
return;
}
}
}
// not a good packet
protocol = 0xFF; // reserved protocol
payload = nullptr;
lengthOfPayload = 0;
destination = 0;
}

11
source/Tfe/IPRaw.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
struct MACAddress;
std::vector<uint8_t> createETH2Frame(const std::vector<uint8_t> &data,
const MACAddress *sourceMac, const MACAddress *destinationMac,
const uint8_t ttl, const uint8_t tos, const uint8_t protocol,
const uint32_t sourceAddress, const uint32_t destinationAddress);
void getIPPayload(const int lengthOfFrame, const uint8_t *frame,
size_t &lengthOfPayload, const uint8_t *&payload, uint32_t &destination, uint8_t &protocol);

View file

@ -6,6 +6,14 @@
#define MAX_RXLENGTH 1518
#define MIN_RXLENGTH 64
#pragma pack(push)
#pragma pack(1) // Ensure struct is packed
struct MACAddress
{
uint8_t address[6];
};
#pragma pack(pop)
class NetworkBackend
{
public:
@ -26,6 +34,9 @@ public:
// process pending packets
virtual void update(const ULONG nExecutedCycles) = 0;
// get MAC for IPRAW (it is only supposed to handle addresses on the local network)
virtual void getMACAddress(const uint32_t address, MACAddress & mac) = 0;
// if the backend is usable
virtual bool isValid() = 0;
};

View file

@ -25,6 +25,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../Common.h"
#include "../Registry.h"
#ifdef _MSC_VER
#include <iphlpapi.h>
#endif
std::string PCapBackend::tfe_interface;
PCapBackend::PCapBackend(const std::string & pcapInterface)
@ -71,6 +75,16 @@ void PCapBackend::update(const ULONG /* nExecutedCycles */)
// nothing to do
}
void PCapBackend::getMACAddress(const uint32_t address, MACAddress & mac)
{
// this is only expected to be called for IP addresses on the same network
#ifdef _MSC_VER
const DWORD dwSourceAddress = INADDR_ANY;
ULONG len = sizeof(MACAddress::address);
SendARP(address, dwSourceAddress, mac.address, &len);
#endif
}
int PCapBackend::tfe_enumadapter_open(void)
{
return tfe_arch_enumadapter_open();

View file

@ -29,6 +29,9 @@ public:
// process pending packets
virtual bool isValid();
// get MAC for IPRAW (it is only supposed to handle addresses on the local network)
virtual void getMACAddress(const uint32_t address, MACAddress & mac);
static void tfe_SetRegistryInterface(UINT slot, const std::string& name);
static void get_disabled_state(int * param);

View file

@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Interface.h"
#include "Tfe/NetworkBackend.h"
#include "Tfe/PCapBackend.h"
#include "Tfe/IPRaw.h"
#include "W5100.h"
// Linux uses EINPROGRESS while Windows returns WSAEWOULDBLOCK
@ -73,6 +74,9 @@ typedef int socklen_t;
#define SOCK_NONBLOCK O_NONBLOCK
#endif
// Dest MAC + Source MAC + Ether Type
#define ETH_MINIMUM_SIZE (6 + 6 + 2)
// #define U2_LOG_VERBOSE
// #define U2_LOG_TRAFFIC
// #define U2_LOG_STATE
@ -95,6 +99,12 @@ namespace
return host;
}
uint32_t readAddress(const uint8_t *ptr)
{
const uint32_t address = *reinterpret_cast<const uint32_t *>(ptr);
return address;
}
uint8_t getIByte(const uint16_t value, const size_t shift)
{
return (value >> shift) & 0xFF;
@ -141,6 +151,13 @@ namespace
writeData(socket, memory, data, len);
}
void writeDataIPRaw(Socket &socket, std::vector<uint8_t> &memory, const uint8_t *data, const size_t len, const uint32_t destination)
{
writeAny(socket, memory, destination);
write16(socket, memory, static_cast<uint16_t>(len));
writeData(socket, memory, data, len);
}
void writeDataForProtocol(Socket &socket, std::vector<uint8_t> &memory, const uint8_t *data, const size_t len, const sockaddr_in &source)
{
if (socket.sn_sr == W5100_SN_SR_SOCK_UDP)
@ -199,31 +216,46 @@ Socket::~Socket()
clearFD();
}
bool Socket::isOpen() const
{
return (myFD != INVALID_SOCKET) &&
((sn_sr == W5100_SN_SR_ESTABLISHED) || (sn_sr == W5100_SN_SR_SOCK_UDP));
}
void Socket::process()
{
if (myFD != INVALID_SOCKET && sn_sr == W5100_SN_SR_SOCK_INIT && (myErrno == SOCK_EINPROGRESS || myErrno == SOCK_EWOULDBLOCK))
{
#ifdef _MSC_VER
FD_SET writefds;
FD_SET writefds, exceptfds;
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
FD_SET(myFD, &writefds);
FD_SET(myFD, &exceptfds);
const timeval timeout = {0, 0};
if (select(0, NULL, &writefds, NULL, &timeout) > 0)
if (select(0, NULL, &writefds, &exceptfds, &timeout) > 0)
#else
pollfd pfd = {.fd = myFD, .events = POLLOUT};
if (poll(&pfd, 1, 0) > 0)
#endif
{
int err = 0;
socklen_t elen = sizeof err;
getsockopt(myFD, SOL_SOCKET, SO_ERROR, reinterpret_cast<char *>(&err), &elen);
socklen_t elen = sizeof(err);
const int res = getsockopt(myFD, SOL_SOCKET, SO_ERROR, reinterpret_cast<char *>(&err), &elen);
if (err == 0)
if (res == 0 && err == 0)
{
myErrno = 0;
sn_sr = W5100_SN_SR_ESTABLISHED;
#ifdef U2_LOG_STATE
LogFileOutput("U2: TCP[]: Connected\n");
#endif
}
else
{
clearFD();
#ifdef U2_LOG_STATE
LogFileOutput("U2: TCP[]: Connection error: %d - %" ERROR_FMT "\n", res, STRERROR(err));
#endif
}
}
@ -266,12 +298,18 @@ bool Socket::LoadSnapshot(YamlLoadHelper &yamlLoadHelper)
// transmit and receive sizes are restored from the card common registers
if (sn_sr != W5100_SN_SR_SOCK_MACRAW)
switch (sn_sr)
{
case W5100_SN_SR_SOCK_MACRAW:
case W5100_SN_SR_SOCK_IPRAW:
// we can restore RAW sockets
break;
default:
// no point in restoring a broken UDP or TCP connection
// just reset the socket
sn_sr = W5100_SN_SR_CLOSED;
// for the same reason there is no point in saving myFD and myErrno
break;
}
return true;
@ -434,7 +472,7 @@ void Uthernet2::updateRSR(const size_t i)
socket.sn_rx_rsr = dataPresent;
}
int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_t * data)
int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_t * data, PacketDestination & packetDestination)
{
const uint8_t * mac = myMemory.data() + W5100_SHAR0;
@ -442,15 +480,9 @@ int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_
int len;
while ((len = myNetworkBackend->receive(size, data)) > 0)
{
// minimum valid Ethernet frame is actually 64 bytes
// 12 is the minimum to ensure valid MAC Address logging later
if (len >= 12)
// smaller frames are not good anyway
if (len >= ETH_MINIMUM_SIZE)
{
if (acceptAll)
{
return len;
}
if (data[0] == mac[0] &&
data[1] == mac[1] &&
data[2] == mac[2] &&
@ -458,6 +490,7 @@ int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_
data[4] == mac[4] &&
data[5] == mac[5])
{
packetDestination = HOST;
return len;
}
@ -468,8 +501,16 @@ int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_
data[4] == 0xFF &&
data[5] == 0xFF)
{
packetDestination = BROADCAST;
return len;
}
if (acceptAll)
{
packetDestination = OTHER;
return len;
}
}
// skip this frame and try with another one
}
@ -477,34 +518,110 @@ int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_
return len;
}
void Uthernet2::receiveOnePacketMacRaw(const size_t i)
void Uthernet2::receiveOnePacketRaw()
{
bool acceptAll = false;
int macRawSocket = -1; // to which IPRaw soccket to send to (can only be 0)
Socket & socket0 = mySockets[0];
if (socket0.sn_sr == W5100_SN_SR_SOCK_MACRAW)
{
macRawSocket = 0; // the only MAC Raw socket is open, packet will go there as a fallback
const uint8_t mr = myMemory[socket0.registerAddress + W5100_SN_MR];
// see if MAC RAW filters or not
const bool filterMAC = mr & W5100_SN_MR_MF;
if (!filterMAC)
{
acceptAll = true;
}
}
uint8_t buffer[MAX_RXLENGTH];
PacketDestination packetDestination;
const int len = receiveForMacAddress(acceptAll, sizeof(buffer), buffer, packetDestination);
if (len > 0)
{
const uint8_t * payload;
size_t lengthOfPayload;
uint32_t destination;
uint8_t packetProtocol;
getIPPayload(len, buffer, lengthOfPayload, payload, destination, packetProtocol);
// see if there is a IPRAW socket that should accept thi spacket
int ipRawSocket = -1;
if (packetDestination != OTHER) // IPRaw always filters (HOST or BROADCAST, never OTHER)
{
for (size_t i = 0; i < mySockets.size(); ++i)
{
Socket & socket = mySockets[i];
if (socket.sn_sr == W5100_SN_SR_SOCK_IPRAW)
{
// IP only accepts by protocol & always filters MAC
const uint8_t socketProtocol = myMemory[socket.registerAddress + W5100_SN_PROTO];
if (payload && packetProtocol == socketProtocol)
{
ipRawSocket = i;
break; // a valid IPRAW socket has been found
}
}
// we should probably check for UDP & TCP sockets and filter these packets too
}
}
// priority to IPRAW
if (ipRawSocket >= 0)
{
receiveOnePacketIPRaw(ipRawSocket, lengthOfPayload, payload, destination, packetProtocol, len);
}
// fallback to MACRAW (if open)
else if (macRawSocket >= 0)
{
receiveOnePacketMacRaw(macRawSocket, len, buffer);
}
// else packet is dropped
}
}
void Uthernet2::receiveOnePacketMacRaw(const size_t i, const int size, uint8_t * data)
{
Socket &socket = mySockets[i];
uint8_t buffer[MAX_RXLENGTH];
const uint8_t mr = myMemory[socket.registerAddress + W5100_SN_MR];
const bool filterMAC = mr & W5100_SN_MR_MF;
const int len = receiveForMacAddress(!filterMAC, sizeof(buffer), buffer);
if (len > 0)
if (socket.isThereRoomFor(size, sizeof(uint16_t)))
{
// we know the packet is at least 12 bytes, and logging is ok
if (socket.isThereRoomFor(len, sizeof(uint16_t)))
{
writeDataMacRaw(socket, myMemory, buffer, len);
writeDataMacRaw(socket, myMemory, data, size);
#ifdef U2_LOG_TRAFFIC
LogFileOutput("U2: Read MACRAW[%" SIZE_T_FMT "]: " MAC_FMT " -> " MAC_FMT ": +%d -> %d bytes\n", i, MAC_SOURCE(buffer), MAC_DEST(buffer),
len, socket.sn_rx_rsr);
LogFileOutput("U2: Read MACRAW[%" SIZE_T_FMT "]: " MAC_FMT " -> " MAC_FMT ": +%d -> %d bytes\n", i, MAC_SOURCE(data), MAC_DEST(data),
size, socket.sn_rx_rsr);
#endif
}
else
{
// drop it
}
else
{
// drop it
#ifdef U2_LOG_TRAFFIC
LogFileOutput("U2: Skip MACRAW[%" SIZE_T_FMT "]: %d bytes\n", i, len);
LogFileOutput("U2: Skip MACRAW[%" SIZE_T_FMT "]: %d bytes\n", i, size);
#endif
}
}
void Uthernet2::receiveOnePacketIPRaw(const size_t i, const size_t lengthOfPayload, const uint8_t * payload, const uint32_t destination, const uint8_t protocol, const int len)
{
Socket &socket = mySockets[i];
if (socket.isThereRoomFor(lengthOfPayload, 4 + sizeof(uint16_t)))
{
writeDataIPRaw(socket, myMemory, payload, lengthOfPayload, destination);
#ifdef U2_LOG_TRAFFIC
LogFileOutput("U2: Read IPRAW[%" SIZE_T_FMT "]: +%" SIZE_T_FMT " (%d) -> %d bytes\n", i, lengthOfPayload, len, socket.sn_rx_rsr);
#endif
}
else
{
// drop it
#ifdef U2_LOG_TRAFFIC
LogFileOutput("U2: Skip IPRAW[%" SIZE_T_FMT "]: %" SIZE_T_FMT " (%d) bytes \n", i, lengthOfPayload, len);
#endif
}
}
}
@ -512,7 +629,7 @@ void Uthernet2::receiveOnePacketMacRaw(const size_t i)
void Uthernet2::receiveOnePacketFromSocket(const size_t i)
{
Socket &socket = mySockets[i];
if (socket.myFD != INVALID_SOCKET)
if (socket.isOpen())
{
const uint16_t freeRoom = socket.getFreeRoom();
if (freeRoom > 32) // avoid meaningless reads
@ -557,7 +674,8 @@ void Uthernet2::receiveOnePacket(const size_t i)
switch (socket.sn_sr)
{
case W5100_SN_SR_SOCK_MACRAW:
receiveOnePacketMacRaw(i);
case W5100_SN_SR_SOCK_IPRAW:
receiveOnePacketRaw();
break;
case W5100_SN_SR_ESTABLISHED:
case W5100_SN_SR_SOCK_UDP:
@ -572,6 +690,29 @@ void Uthernet2::receiveOnePacket(const size_t i)
};
}
void Uthernet2::sendDataIPRaw(const size_t i, std::vector<uint8_t> &payload)
{
const Socket &socket = mySockets[i];
const uint8_t ttl = myMemory[socket.registerAddress + W5100_SN_TTL];
const uint8_t tos = myMemory[socket.registerAddress + W5100_SN_TOS];
const uint8_t protocol = myMemory[socket.registerAddress + W5100_SN_PROTO];
const uint32_t source = readAddress(myMemory.data() + W5100_SIPR0);
const uint32_t destination = readAddress(myMemory.data() + socket.registerAddress + W5100_SN_DIPR0);
const MACAddress * sourceMac = reinterpret_cast<const MACAddress *>(myMemory.data() + W5100_SHAR0);
const MACAddress * destinationMac;
getMACAddress(destination, destinationMac);
std::vector<uint8_t> packet = createETH2Frame(payload, sourceMac, destinationMac, ttl, tos, protocol, source, destination);
#ifdef U2_LOG_TRAFFIC
LogFileOutput("U2: Send IPRAW[%" SIZE_T_FMT "]: %" SIZE_T_FMT " (%" SIZE_T_FMT ") bytes\n", i, payload.size(), packet.size());
#endif
myNetworkBackend->transmit(packet.size(), packet.data());
}
void Uthernet2::sendDataMacRaw(const size_t i, std::vector<uint8_t> &packet) const
{
#ifdef U2_LOG_TRAFFIC
@ -592,7 +733,7 @@ void Uthernet2::sendDataMacRaw(const size_t i, std::vector<uint8_t> &packet) con
void Uthernet2::sendDataToSocket(const size_t i, std::vector<uint8_t> &data)
{
Socket &socket = mySockets[i];
if (socket.myFD != INVALID_SOCKET)
if (socket.isOpen())
{
sockaddr_in destination = {};
destination.sin_family = AF_INET;
@ -656,6 +797,9 @@ void Uthernet2::sendData(const size_t i)
case W5100_SN_SR_SOCK_MACRAW:
sendDataMacRaw(i, data);
break;
case W5100_SN_SR_SOCK_IPRAW:
sendDataIPRaw(i, data);
break;
case W5100_SN_SR_ESTABLISHED:
case W5100_SN_SR_SOCK_UDP:
sendDataToSocket(i, data);
@ -680,7 +824,7 @@ void Uthernet2::resetRXTXBuffers(const size_t i)
myMemory[socket.registerAddress + W5100_SN_RX_RD1] = 0x00;
}
void Uthernet2::openSystemSocket(const size_t i, const int type, const int protocol, const int state)
void Uthernet2::openSystemSocket(const size_t i, const int type, const int protocol, const int status)
{
Socket &s = mySockets[i];
#ifdef _MSC_VER
@ -691,7 +835,7 @@ void Uthernet2::openSystemSocket(const size_t i, const int type, const int proto
if (fd == INVALID_SOCKET)
{
#ifdef U2_LOG_STATE
const char *proto = state == W5100_SN_SR_SOCK_UDP ? "UDP" : "TCP";
const char *proto = (status == W5100_SN_SR_SOCK_UDP) ? "UDP" : "TCP";
LogFileOutput("U2: %s[%" SIZE_T_FMT "]: socket error: %" ERROR_FMT "\n", proto, i, STRERROR(sock_error()));
#endif
s.clearFD();
@ -702,7 +846,7 @@ void Uthernet2::openSystemSocket(const size_t i, const int type, const int proto
u_long on = 1;
ioctlsocket(fd, FIONBIO, &on);
#endif
s.setFD(fd, state);
s.setFD(fd, status);
}
}
@ -854,7 +998,7 @@ uint8_t Uthernet2::readSocketRegister(const uint16_t address)
break;
default:
#ifdef U2_LOG_UNKNOWN
LogFileOutput("U2: Get unknown socket register[%" SIZE_T_FMT "]: %04x\n", i, address);
LogFileOutput("U2: Get unknown socket register[%d]: %04x\n", i, address);
#endif
value = myMemory[address];
break;
@ -988,7 +1132,7 @@ void Uthernet2::writeSocketRegister(const uint16_t address, const uint8_t value)
break;
#ifdef U2_LOG_UNKNOWN
default:
LogFileOutput("U2: Set unknown socket register[%" SIZE_T_FMT "]: %04x\n", i, address);
LogFileOutput("U2: Set unknown socket register[%d]: %04x\n", i, address);
break;
#endif
};
@ -1073,6 +1217,7 @@ void Uthernet2::Reset(const bool powerCycle)
// dataAddress is NOT reset, see page 10 of Uthernet II
myDataAddress = 0;
myNetworkBackend = GetFrame().CreateNetworkBackend();
myARPCache.clear();
}
mySockets.clear();
@ -1084,14 +1229,25 @@ void Uthernet2::Reset(const bool powerCycle)
{
resetRXTXBuffers(i);
mySockets[i].clearFD();
mySockets[i].registerAddress = static_cast<uint16_t>(W5100_S0_BASE + (i << 8));
const uint16_t registerAddress = static_cast<uint16_t>(W5100_S0_BASE + (i << 8));
mySockets[i].registerAddress = registerAddress;
myMemory[registerAddress + W5100_SN_DHAR0] = 0xFF;
myMemory[registerAddress + W5100_SN_DHAR1] = 0xFF;
myMemory[registerAddress + W5100_SN_DHAR2] = 0xFF;
myMemory[registerAddress + W5100_SN_DHAR3] = 0xFF;
myMemory[registerAddress + W5100_SN_DHAR4] = 0xFF;
myMemory[registerAddress + W5100_SN_DHAR5] = 0xFF;
myMemory[registerAddress + W5100_SN_TTL] = 0x80;
}
// initial values
myMemory[W5100_RTR0] = 0x07;
myMemory[W5100_RTR1] = 0xD0;
myMemory[W5100_RTR0] = 0x07;
myMemory[W5100_RTR1] = 0xD0;
myMemory[W5100_RCR] = 0x08;
setRXSizes(W5100_RMSR, 0x55);
setTXSizes(W5100_TMSR, 0x55);
myMemory[W5100_PTIMER] = 0x28;
}
BYTE Uthernet2::IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
@ -1162,6 +1318,46 @@ void Uthernet2::InitializeIO(LPBYTE pCxRomPeripheral)
RegisterIoHandler(m_slot, u2_C0, u2_C0, nullptr, nullptr, this, nullptr);
}
void Uthernet2::getMACAddress(const uint32_t address, const MACAddress * & mac)
{
const auto it = myARPCache.find(address);
if (it != myARPCache.end())
{
mac = &it->second;
}
else
{
MACAddress & macAddr = myARPCache[address];
const uint32_t source = readAddress(myMemory.data() + W5100_SIPR0);
if (address == source)
{
const uint8_t * sourceMac = myMemory.data() + W5100_SHAR0;
memcpy(macAddr.address, sourceMac, sizeof(macAddr.address));
}
else
{
memset(macAddr.address, 0xFF, sizeof(macAddr.address)); // fallback to broadcast
if (address != INADDR_BROADCAST)
{
const uint32_t subnet = readAddress(myMemory.data() + W5100_SUBR0);
if ((address & subnet) == (source & subnet))
{
// same network: send ARP request
myNetworkBackend->getMACAddress(address, macAddr);
}
else
{
const uint32_t gateway = readAddress(myMemory.data() + W5100_GAR0);
// different network: go via gateway
myNetworkBackend->getMACAddress(gateway, macAddr);
}
}
}
mac = &macAddr;
}
}
void Uthernet2::Update(const ULONG nExecutedCycles)
{
myNetworkBackend->update(nExecutedCycles);

View file

@ -3,8 +3,10 @@
#include "Card.h"
#include <vector>
#include <map>
class NetworkBackend;
struct MACAddress;
struct Socket
{
@ -28,6 +30,7 @@ struct Socket
socket_t myFD;
int myErrno;
bool isOpen() const;
void clearFD();
void setFD(const socket_t fd, const int status);
void process();
@ -47,6 +50,7 @@ struct Socket
* Documentation from
* http://dserver.macgui.com/Uthernet%20II%20manual%2017%20Nov%2018.pdf
* https://www.wiznet.io/wp-content/uploads/wiznethome/Chip/W5100/Document/W5100_DS_V128E.pdf
* https://www.wiznet.io/wp-content/uploads/wiznethome/Chip/W5100/Document/3150Aplus_5100_ES_V260E.pdf
*/
class Uthernet2 : public Card
@ -54,6 +58,8 @@ class Uthernet2 : public Card
public:
static const std::string& GetSnapshotCardName();
enum PacketDestination { HOST, BROADCAST, OTHER };
Uthernet2(UINT slot);
virtual void Destroy(void) {}
@ -72,6 +78,13 @@ private:
uint16_t myDataAddress;
std::shared_ptr<NetworkBackend> myNetworkBackend;
// the real Uthernet II card does not have a ARP Cache
// but in the interest of speeding up the emulator
// we introduce one
std::map<uint32_t, MACAddress> myARPCache;
void getMACAddress(const uint32_t address, const MACAddress * & mac);
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);
@ -79,11 +92,14 @@ private:
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 receiveOnePacketRaw();
void receiveOnePacketIPRaw(const size_t i, const size_t lengthOfPayload, const uint8_t * payload, const uint32_t destination, const uint8_t protocol, const int len);
void receiveOnePacketMacRaw(const size_t i, const int size, uint8_t * data);
void receiveOnePacketFromSocket(const size_t i);
void receiveOnePacket(const size_t i);
int receiveForMacAddress(const bool acceptAll, const int size, uint8_t * data);
int receiveForMacAddress(const bool acceptAll, const int size, uint8_t * data, PacketDestination & packetDestination);
void sendDataIPRaw(const size_t i, std::vector<uint8_t> &data);
void sendDataMacRaw(const size_t i, std::vector<uint8_t> &data) const;
void sendDataToSocket(const size_t i, std::vector<uint8_t> &data);
void sendData(const size_t i);
@ -91,7 +107,7 @@ private:
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 openSystemSocket(const size_t i, const int type, const int protocol, const int status);
void openSocket(const size_t i);
void closeSocket(const size_t i);
void connectSocket(const size_t i);

View file

@ -20,8 +20,10 @@
#define W5100_SIPR3 0x0012
#define W5100_RTR0 0x0017
#define W5100_RTR1 0x0018
#define W5100_RCR 0x0019
#define W5100_RMSR 0x001A
#define W5100_TMSR 0x001B
#define W5100_PTIMER 0x0028
#define W5100_UPORT1 0x002F
#define W5100_S0_BASE 0x0400
#define W5100_S3_MAX 0x07FF
@ -58,6 +60,12 @@
#define W5100_SN_SR 0x03
#define W5100_SN_PORT0 0x04
#define W5100_SN_PORT1 0x05
#define W5100_SN_DHAR0 0x06
#define W5100_SN_DHAR1 0x07
#define W5100_SN_DHAR2 0x08
#define W5100_SN_DHAR3 0x09
#define W5100_SN_DHAR4 0x0A
#define W5100_SN_DHAR5 0x0B
#define W5100_SN_DIPR0 0x0C
#define W5100_SN_DIPR1 0x0D
#define W5100_SN_DIPR2 0x0E