Uthernet II card: support save/load state. (PR #1054)

NB. do not attempt to restore a UDP / TCP socket.
This commit is contained in:
Andrea 2022-03-07 21:08:31 +00:00 committed by GitHub
parent 10337aa95c
commit bbe2a7f8ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 342 additions and 211 deletions

View File

@ -465,6 +465,7 @@ void Snapshot_LoadState()
return;
}
LogFileOutput("Loading Save-State from %s\n", g_strSaveStatePathname.c_str());
Snapshot_LoadState_v2();
}
@ -472,6 +473,7 @@ void Snapshot_LoadState()
void Snapshot_SaveState(void)
{
LogFileOutput("Saving Save-State to %s\n", g_strSaveStatePathname.c_str());
try
{
YamlSaveHelper yamlSaveHelper(g_strSaveStatePathname);

View File

@ -26,8 +26,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Tfe/PCapBackend.h"
#include "W5100.h"
#include <cstdint>
// Linux uses EINPROGRESS while Windows returns WSAEWOULDBLOCK
// when the connect() calls is ongoing
//
@ -145,7 +143,7 @@ namespace
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 == SN_SR_SOCK_UDP)
if (socket.sn_sr == W5100_SN_SR_SOCK_UDP)
{
// these are already in network order
writeAny(socket, memory, source.sin_addr);
@ -161,7 +159,16 @@ namespace
}
Socket::Socket()
: sn_sr(SN_SR_CLOSED), myFD(INVALID_SOCKET), myErrno(0)
: transmitBase(0)
, transmitSize(0)
, receiveBase(0)
, receiveSize(0)
, registerAddress(0)
, sn_rx_wr(0)
, sn_rx_rsr(0)
, sn_sr(W5100_SN_SR_CLOSED)
, myFD(INVALID_SOCKET)
, myErrno(0)
{
}
@ -176,7 +183,7 @@ void Socket::clearFD()
#endif
}
myFD = INVALID_SOCKET;
sn_sr = SN_SR_CLOSED;
sn_sr = W5100_SN_SR_CLOSED;
}
void Socket::setFD(const socket_t fd, const int status)
@ -194,7 +201,7 @@ Socket::~Socket()
void Socket::process()
{
if (myFD != INVALID_SOCKET && sn_sr == SN_SR_SOCK_INIT && (myErrno == SOCK_EINPROGRESS || myErrno == SOCK_EWOULDBLOCK))
if (myFD != INVALID_SOCKET && sn_sr == W5100_SN_SR_SOCK_INIT && (myErrno == SOCK_EINPROGRESS || myErrno == SOCK_EWOULDBLOCK))
{
#ifdef _MSC_VER
FD_SET writefds;
@ -214,7 +221,7 @@ void Socket::process()
if (err == 0)
{
myErrno = 0;
sn_sr = SN_SR_ESTABLISHED;
sn_sr = W5100_SN_SR_ESTABLISHED;
#ifdef U2_LOG_STATE
LogFileOutput("U2: TCP[]: Connected\n");
#endif
@ -239,15 +246,45 @@ uint16_t Socket::getFreeRoom() const
return size - rsr;
}
#define SS_YAML_KEY_SOCKET_RX_WRITE_REGISTER "RX Write Register"
#define SS_YAML_KEY_SOCKET_RX_SIZE_REGISTER "RX Size Register"
#define SS_YAML_KEY_SOCKET_REGISTER "Socket Register"
void Socket::SaveSnapshot(YamlSaveHelper &yamlSaveHelper)
{
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SOCKET_RX_WRITE_REGISTER, sn_rx_wr);
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_SOCKET_RX_SIZE_REGISTER, sn_rx_rsr);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SOCKET_REGISTER, sn_sr);
}
bool Socket::LoadSnapshot(YamlLoadHelper &yamlLoadHelper)
{
sn_rx_wr = yamlLoadHelper.LoadUint(SS_YAML_KEY_SOCKET_RX_WRITE_REGISTER);
sn_rx_rsr = yamlLoadHelper.LoadUint(SS_YAML_KEY_SOCKET_RX_SIZE_REGISTER);
sn_sr = yamlLoadHelper.LoadUint(SS_YAML_KEY_SOCKET_REGISTER);
// transmit and receive sizes are restored from the card common registers
if (sn_sr != W5100_SN_SR_SOCK_MACRAW)
{
// 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
}
return true;
}
const std::string& Uthernet2::GetSnapshotCardName()
{
static const std::string name("Uthernet2");
static const std::string name("Uthernet II");
return name;
}
Uthernet2::Uthernet2(UINT slot) : Card(CT_Uthernet2, slot)
{
myNetworkBackend = GetFrame().CreateNetworkBackend();
Reset(true);
}
@ -259,30 +296,30 @@ void Uthernet2::Destroy()
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;
const uint8_t protocol = value & W5100_SN_MR_PROTO_MASK;
switch (protocol)
{
case SN_MR_CLOSED:
case W5100_SN_MR_CLOSED:
#ifdef U2_LOG_STATE
LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: closed\n", i);
#endif
break;
case SN_MR_TCP:
case W5100_SN_MR_TCP:
#ifdef U2_LOG_STATE
LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: TCP\n", i);
#endif
break;
case SN_MR_UDP:
case W5100_SN_MR_UDP:
#ifdef U2_LOG_STATE
LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: UDP\n", i);
#endif
break;
case SN_MR_IPRAW:
case W5100_SN_MR_IPRAW:
#ifdef U2_LOG_STATE
LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: IPRAW\n", i);
#endif
break;
case SN_MR_MACRAW:
case W5100_SN_MR_MACRAW:
#ifdef U2_LOG_STATE
LogFileOutput("U2: Mode[%" SIZE_T_FMT "]: MACRAW\n", i);
#endif
@ -297,8 +334,8 @@ void Uthernet2::setSocketModeRegister(const size_t i, const uint16_t address, co
void Uthernet2::setTXSizes(const uint16_t address, uint8_t value)
{
myMemory[address] = value;
uint16_t base = TX_BASE;
const uint16_t end = RX_BASE;
uint16_t base = W5100_TX_BASE;
const uint16_t end = W5100_RX_BASE;
for (Socket &socket : mySockets)
{
socket.transmitBase = base;
@ -320,8 +357,8 @@ void Uthernet2::setTXSizes(const uint16_t address, uint8_t value)
void Uthernet2::setRXSizes(const uint16_t address, uint8_t value)
{
myMemory[address] = value;
uint16_t base = RX_BASE;
const uint16_t end = MEM_SIZE;
uint16_t base = W5100_RX_BASE;
const uint16_t end = W5100_MEM_SIZE;
for (Socket &socket : mySockets)
{
socket.receiveBase = base;
@ -346,8 +383,8 @@ uint16_t Uthernet2::getTXDataSize(const size_t i) const
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;
const int sn_tx_rd = readNetworkWord(myMemory.data() + socket.registerAddress + W5100_SN_TX_RD0) & mask;
const int sn_tx_wr = readNetworkWord(myMemory.data() + socket.registerAddress + W5100_SN_TX_WR0) & mask;
int dataPresent = sn_tx_wr - sn_tx_rd;
if (dataPresent < 0)
@ -380,7 +417,7 @@ void Uthernet2::updateRSR(const size_t 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_rd = readNetworkWord(myMemory.data() + socket.registerAddress + W5100_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)
@ -404,7 +441,7 @@ void Uthernet2::updateRSR(const size_t i)
int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_t * data)
{
const uint8_t * mac = myMemory.data() + SHAR0;
const uint8_t * mac = myMemory.data() + W5100_SHAR0;
// loop until we receive a valid frame, or there is nothing to receive
int len;
@ -451,8 +488,8 @@ void Uthernet2::receiveOnePacketMacRaw(const size_t i)
uint8_t buffer[MAX_RXLENGTH];
const uint8_t mr = myMemory[socket.registers + SN_MR];
const bool filterMAC = mr & SN_MR_MF;
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)
@ -490,7 +527,7 @@ void Uthernet2::receiveOnePacketFromSocket(const size_t i)
socklen_t len = sizeof(sockaddr_in);
const ssize_t data = recvfrom(socket.myFD, reinterpret_cast<char *>(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";
const char *proto = socket.sn_sr == W5100_SN_SR_SOCK_UDP ? "UDP" : "TCP";
#endif
if (data > 0)
{
@ -524,14 +561,14 @@ void Uthernet2::receiveOnePacket(const size_t i)
const Socket &socket = mySockets[i];
switch (socket.sn_sr)
{
case SN_SR_SOCK_MACRAW:
case W5100_SN_SR_SOCK_MACRAW:
receiveOnePacketMacRaw(i);
break;
case SN_SR_ESTABLISHED:
case SN_SR_SOCK_UDP:
case W5100_SN_SR_ESTABLISHED:
case W5100_SN_SR_SOCK_UDP:
receiveOnePacketFromSocket(i);
break;
case SN_SR_CLOSED:
case W5100_SN_SR_CLOSED:
break; // nothing to do
#ifdef U2_LOG_UNKNOWN
default:
@ -567,13 +604,13 @@ void Uthernet2::sendDataToSocket(const size_t i, std::vector<uint8_t> &data)
// 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;
const uint8_t *dest = myMemory.data() + socket.registerAddress + W5100_SN_DIPR0;
destination.sin_addr.s_addr = *reinterpret_cast<const uint32_t *>(dest);
destination.sin_port = *reinterpret_cast<const uint16_t *>(myMemory.data() + socket.registers + SN_DPORT0);
destination.sin_port = *reinterpret_cast<const uint16_t *>(myMemory.data() + socket.registerAddress + W5100_SN_DPORT0);
const ssize_t res = sendto(socket.myFD, reinterpret_cast<const char *>(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";
const char *proto = socket.sn_sr == W5100_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)
@ -596,8 +633,8 @@ void Uthernet2::sendData(const size_t 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 int sn_tx_rr = readNetworkWord(myMemory.data() + socket.registerAddress + W5100_SN_TX_RD0) & mask;
const int sn_tx_wr = readNetworkWord(myMemory.data() + socket.registerAddress + W5100_SN_TX_WR0) & mask;
const uint16_t base = socket.transmitBase;
const uint16_t rr_address = base + sn_tx_rr;
@ -616,16 +653,16 @@ void Uthernet2::sendData(const size_t i)
}
// 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);
myMemory[socket.registerAddress + W5100_SN_TX_RD0] = getIByte(sn_tx_wr, 8);
myMemory[socket.registerAddress + W5100_SN_TX_RD1] = getIByte(sn_tx_wr, 0);
switch (socket.sn_sr)
{
case SN_SR_SOCK_MACRAW:
case W5100_SN_SR_SOCK_MACRAW:
sendDataMacRaw(i, data);
break;
case SN_SR_ESTABLISHED:
case SN_SR_SOCK_UDP:
case W5100_SN_SR_ESTABLISHED:
case W5100_SN_SR_SOCK_UDP:
sendDataToSocket(i, data);
break;
#ifdef U2_LOG_UNKNOWN
@ -640,12 +677,12 @@ 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;
myMemory[socket.registerAddress + W5100_SN_TX_RD0] = 0x00;
myMemory[socket.registerAddress + W5100_SN_TX_RD1] = 0x00;
myMemory[socket.registerAddress + W5100_SN_TX_WR0] = 0x00;
myMemory[socket.registerAddress + W5100_SN_TX_WR1] = 0x00;
myMemory[socket.registerAddress + W5100_SN_RX_RD0] = 0x00;
myMemory[socket.registerAddress + W5100_SN_RX_RD1] = 0x00;
}
void Uthernet2::openSystemSocket(const size_t i, const int type, const int protocol, const int state)
@ -659,7 +696,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 == SN_SR_SOCK_UDP ? "UDP" : "TCP";
const char *proto = state == 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();
@ -677,22 +714,22 @@ void Uthernet2::openSystemSocket(const size_t i, const int type, const int proto
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;
const uint8_t mr = myMemory[socket.registerAddress + W5100_SN_MR];
const uint8_t protocol = mr & W5100_SN_MR_PROTO_MASK;
uint8_t &sr = socket.sn_sr;
switch (protocol)
{
case SN_MR_IPRAW:
sr = SN_SR_SOCK_IPRAW;
case W5100_SN_MR_IPRAW:
sr = W5100_SN_SR_SOCK_IPRAW;
break;
case SN_MR_MACRAW:
sr = SN_SR_SOCK_MACRAW;
case W5100_SN_MR_MACRAW:
sr = W5100_SN_SR_SOCK_MACRAW;
break;
case SN_MR_TCP:
openSystemSocket(i, SOCK_STREAM, IPPROTO_TCP, SN_SR_SOCK_INIT);
case W5100_SN_MR_TCP:
openSystemSocket(i, SOCK_STREAM, IPPROTO_TCP, W5100_SN_SR_SOCK_INIT);
break;
case SN_MR_UDP:
openSystemSocket(i, SOCK_DGRAM, IPPROTO_UDP, SN_SR_SOCK_UDP);
case W5100_SN_MR_UDP:
openSystemSocket(i, SOCK_DGRAM, IPPROTO_UDP, W5100_SN_SR_SOCK_UDP);
break;
#ifdef U2_LOG_UNKNOWN
default:
@ -717,23 +754,23 @@ void Uthernet2::closeSocket(const size_t i)
void Uthernet2::connectSocket(const size_t i)
{
Socket &socket = mySockets[i];
const uint8_t *dest = myMemory.data() + socket.registers + SN_DIPR0;
const uint8_t *dest = myMemory.data() + socket.registerAddress + W5100_SN_DIPR0;
sockaddr_in destination = {};
destination.sin_family = AF_INET;
// already in network order
destination.sin_port = *reinterpret_cast<const uint16_t *>(myMemory.data() + socket.registers + SN_DPORT0);
destination.sin_port = *reinterpret_cast<const uint16_t *>(myMemory.data() + socket.registerAddress + W5100_SN_DPORT0);
destination.sin_addr.s_addr = *reinterpret_cast<const uint32_t *>(dest);
const int res = connect(socket.myFD, (struct sockaddr *)&destination, sizeof(destination));
if (res == 0)
{
socket.sn_sr = SN_SR_ESTABLISHED;
socket.sn_sr = W5100_SN_SR_ESTABLISHED;
socket.myErrno = 0;
#ifdef U2_LOG_STATE
const uint16_t port = readNetworkWord(myMemory.data() + socket.registers + SN_DPORT0);
const uint16_t port = readNetworkWord(myMemory.data() + socket.registerAddress + W5100_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
}
@ -757,20 +794,20 @@ void Uthernet2::setCommandRegister(const size_t i, const uint8_t value)
{
switch (value)
{
case SN_CR_OPEN:
case W5100_SN_CR_OPEN:
openSocket(i);
break;
case SN_CR_CONNECT:
case W5100_SN_CR_CONNECT:
connectSocket(i);
break;
case SN_CR_CLOSE:
case SN_CR_DISCON:
case W5100_SN_CR_CLOSE:
case W5100_SN_CR_DISCON:
closeSocket(i);
break;
case SN_CR_SEND:
case W5100_SN_CR_SEND:
sendData(i);
break;
case SN_CR_RECV:
case W5100_SN_CR_RECV:
updateRSR(i);
break;
#ifdef U2_LOG_UNKNOWN
@ -787,37 +824,37 @@ uint8_t Uthernet2::readSocketRegister(const uint16_t address)
uint8_t value;
switch (loc)
{
case SN_MR:
case SN_CR:
case W5100_SN_MR:
case W5100_SN_CR:
value = myMemory[address];
break;
case SN_SR:
case W5100_SN_SR:
value = mySockets[i].sn_sr;
break;
case SN_TX_FSR0:
case W5100_SN_TX_FSR0:
value = getTXFreeSizeRegister(i, 8);
break;
case SN_TX_FSR1:
case W5100_SN_TX_FSR1:
value = getTXFreeSizeRegister(i, 0);
break;
case SN_TX_RD0:
case SN_TX_RD1:
case W5100_SN_TX_RD0:
case W5100_SN_TX_RD1:
value = myMemory[address];
break;
case SN_TX_WR0:
case SN_TX_WR1:
case W5100_SN_TX_WR0:
case W5100_SN_TX_WR1:
value = myMemory[address];
break;
case SN_RX_RSR0:
case W5100_SN_RX_RSR0:
receiveOnePacket(i);
value = getRXDataSizeRegister(i, 8);
break;
case SN_RX_RSR1:
case W5100_SN_RX_RSR1:
receiveOnePacket(i);
value = getRXDataSizeRegister(i, 0);
break;
case SN_RX_RD0:
case SN_RX_RD1:
case W5100_SN_RX_RD0:
case W5100_SN_RX_RD1:
value = myMemory[address];
break;
default:
@ -833,19 +870,19 @@ uint8_t Uthernet2::readSocketRegister(const uint16_t address)
uint8_t Uthernet2::readValueAt(const uint16_t address)
{
uint8_t value;
if (address == MR)
if (address == W5100_MR)
{
value = myModeRegister;
}
else if (address >= GAR0 && address <= UPORT1)
else if (address >= W5100_GAR0 && address <= W5100_UPORT1)
{
value = myMemory[address];
}
else if (address >= S0_BASE && address <= S3_MAX)
else if (address >= W5100_S0_BASE && address <= W5100_S3_MAX)
{
value = readSocketRegister(address);
}
else if (address >= TX_BASE && address <= MEM_MAX)
else if (address >= W5100_TX_BASE && address <= W5100_MEM_MAX)
{
value = myMemory[address];
}
@ -856,22 +893,22 @@ uint8_t Uthernet2::readValueAt(const uint16_t address)
#endif
// this might not be 100% correct if address >= 0x8000
// see top of page 13 Uthernet II
value = myMemory[address & MEM_MAX];
value = myMemory[address & W5100_MEM_MAX];
}
return value;
}
void Uthernet2::autoIncrement()
{
if (myModeRegister & MR_AI)
if (myModeRegister & W5100_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:
case W5100_RX_BASE:
case W5100_MEM_SIZE:
myDataAddress -= 0x2000;
break;
}
@ -915,43 +952,43 @@ void Uthernet2::writeSocketRegister(const uint16_t address, const uint8_t value)
const uint16_t loc = address & 0xFF;
switch (loc)
{
case SN_MR:
case W5100_SN_MR:
setSocketModeRegister(i, address, value);
break;
case SN_CR:
case W5100_SN_CR:
setCommandRegister(i, value);
break;
case SN_PORT0:
case SN_PORT1:
case SN_DPORT0:
case SN_DPORT1:
case W5100_SN_PORT0:
case W5100_SN_PORT1:
case W5100_SN_DPORT0:
case W5100_SN_DPORT1:
myMemory[address] = value;
break;
case SN_DIPR0:
case SN_DIPR1:
case SN_DIPR2:
case SN_DIPR3:
case W5100_SN_DIPR0:
case W5100_SN_DIPR1:
case W5100_SN_DIPR2:
case W5100_SN_DIPR3:
myMemory[address] = value;
break;
case SN_PROTO:
case W5100_SN_PROTO:
setIPProtocol(i, address, value);
break;
case SN_TOS:
case W5100_SN_TOS:
setIPTypeOfService(i, address, value);
break;
case SN_TTL:
case W5100_SN_TTL:
setIPTTL(i, address, value);
break;
case SN_TX_WR0:
case W5100_SN_TX_WR0:
myMemory[address] = value;
break;
case SN_TX_WR1:
case W5100_SN_TX_WR1:
myMemory[address] = value;
break;
case SN_RX_RD0:
case W5100_SN_RX_RD0:
myMemory[address] = value;
break;
case SN_RX_RD1:
case W5100_SN_RX_RD1:
myMemory[address] = value;
break;
#ifdef U2_LOG_UNKNOWN
@ -964,7 +1001,7 @@ void Uthernet2::writeSocketRegister(const uint16_t address, const uint8_t value)
void Uthernet2::setModeRegister(const uint16_t address, const uint8_t value)
{
if (value & MR_RST)
if (value & W5100_MR_RST)
{
Reset(false);
}
@ -976,22 +1013,22 @@ void Uthernet2::setModeRegister(const uint16_t address, const uint8_t value)
void Uthernet2::writeCommonRegister(const uint16_t address, const uint8_t value)
{
if (address == MR)
if (address == W5100_MR)
{
setModeRegister(address, value);
}
else if (address >= GAR0 && address <= GAR3 ||
address >= SUBR0 && address <= SUBR3 ||
address >= SHAR0 && address <= SHAR5 ||
address >= SIPR0 && address <= SIPR3)
else if (address >= W5100_GAR0 && address <= W5100_GAR3 ||
address >= W5100_SUBR0 && address <= W5100_SUBR3 ||
address >= W5100_SHAR0 && address <= W5100_SHAR5 ||
address >= W5100_SIPR0 && address <= W5100_SIPR3)
{
myMemory[address] = value;
}
else if (address == RMSR)
else if (address == W5100_RMSR)
{
setRXSizes(address, value);
}
else if (address == TMSR)
else if (address == W5100_TMSR)
{
setTXSizes(address, value);
}
@ -1005,15 +1042,15 @@ void Uthernet2::writeCommonRegister(const uint16_t address, const uint8_t value)
void Uthernet2::writeValueAt(const uint16_t address, const uint8_t value)
{
if (address >= MR && address <= UPORT1)
if (address >= W5100_MR && address <= W5100_UPORT1)
{
writeCommonRegister(address, value);
}
else if (address >= S0_BASE && address <= S3_MAX)
else if (address >= W5100_S0_BASE && address <= W5100_S3_MAX)
{
writeSocketRegister(address, value);
}
else if (address >= TX_BASE && address <= MEM_MAX)
else if (address >= W5100_TX_BASE && address <= W5100_MEM_MAX)
{
myMemory[address] = value;
}
@ -1040,23 +1077,27 @@ void Uthernet2::Reset(const bool powerCycle)
{
// dataAddress is NOT reset, see page 10 of Uthernet II
myDataAddress = 0;
myNetworkBackend.reset();
myNetworkBackend = GetFrame().CreateNetworkBackend();
}
mySockets.clear();
mySockets.resize(4);
myMemory.clear();
myMemory.resize(MEM_SIZE, 0);
myMemory.resize(W5100_MEM_SIZE, 0);
for (size_t i = 0; i < mySockets.size(); ++i)
{
resetRXTXBuffers(i);
mySockets[i].clearFD();
mySockets[i].registers = static_cast<uint16_t>(S0_BASE + (i << 8));
mySockets[i].registerAddress = static_cast<uint16_t>(W5100_S0_BASE + (i << 8));
}
// initial values
myMemory[RTR0] = 0x07;
myMemory[RTR1] = 0xD0;
setRXSizes(RMSR, 0x55);
setTXSizes(TMSR, 0x55);
myMemory[W5100_RTR0] = 0x07;
myMemory[W5100_RTR1] = 0xD0;
setRXSizes(W5100_RMSR, 0x55);
setTXSizes(W5100_TMSR, 0x55);
}
BYTE Uthernet2::IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
@ -1073,16 +1114,16 @@ BYTE Uthernet2::IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value,
{
switch (loc)
{
case C0X_MODE_REGISTER:
setModeRegister(MR, value);
case U2_C0X_MODE_REGISTER:
setModeRegister(W5100_MR, value);
break;
case C0X_ADDRESS_HIGH:
case U2_C0X_ADDRESS_HIGH:
myDataAddress = (value << 8) | (myDataAddress & 0x00FF);
break;
case C0X_ADDRESS_LOW:
case U2_C0X_ADDRESS_LOW:
myDataAddress = (value << 0) | (myDataAddress & 0xFF00);
break;
case C0X_DATA_PORT:
case U2_C0X_DATA_PORT:
writeValue(value);
break;
}
@ -1091,16 +1132,16 @@ BYTE Uthernet2::IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value,
{
switch (loc)
{
case C0X_MODE_REGISTER:
case U2_C0X_MODE_REGISTER:
res = myModeRegister;
break;
case C0X_ADDRESS_HIGH:
case U2_C0X_ADDRESS_HIGH:
res = getIByte(myDataAddress, 8);
break;
case C0X_ADDRESS_LOW:
case U2_C0X_ADDRESS_LOW:
res = getIByte(myDataAddress, 0);
break;
case C0X_DATA_PORT:
case U2_C0X_DATA_PORT:
res = readValue();
break;
}
@ -1141,27 +1182,110 @@ void Uthernet2::Update(const ULONG nExecutedCycles)
}
static const UINT kUNIT_VERSION = 1;
#define SS_YAML_KEY_ENABLED "Enabled"
#define SS_YAML_KEY_NETWORK_INTERFACE "Network Interface"
#define SS_YAML_KEY_COMMON_REGISTERS "Common Registers"
#define SS_YAML_KEY_MODE_REGISTER "Mode Register"
#define SS_YAML_KEY_DATA_ADDRESS "Data Address"
#define SS_YAML_KEY_SOCKETS_REGISTERS "Socket Registers"
#define SS_YAML_KEY_SOCKET "Socket"
#define SS_YAML_KEY_TX_MEMORY "TX Memory"
#define SS_YAML_KEY_RX_MEMORY "RX Memory"
void Uthernet2::SaveSnapshot(YamlSaveHelper &yamlSaveHelper)
{
YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_slot, kUNIT_VERSION);
YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
yamlSaveHelper.SaveBool(SS_YAML_KEY_ENABLED, myNetworkBackend->isValid() ? true : false);
yamlSaveHelper.SaveString(SS_YAML_KEY_NETWORK_INTERFACE, PCapBackend::tfe_interface);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_MODE_REGISTER, myModeRegister);
yamlSaveHelper.SaveHexUint16(SS_YAML_KEY_DATA_ADDRESS, myDataAddress);
// we skip the reserved areas as seen @ P.14 2.MemoryMap of the W5100 Manual
{
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_COMMON_REGISTERS);
yamlSaveHelper.SaveMemory(myMemory.data(), W5100_UPORT1 + 1);
}
// 0x0030 to 0x0400 RESERVED
{
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_SOCKETS_REGISTERS);
yamlSaveHelper.SaveMemory(myMemory.data() + W5100_S0_BASE, (W5100_S3_MAX + 1) - W5100_S0_BASE);
}
// 0x0800 to 0x4000 RESERVED
{
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_TX_MEMORY);
yamlSaveHelper.SaveMemory(myMemory.data() + W5100_TX_BASE, W5100_RX_BASE - W5100_TX_BASE);
}
{
YamlSaveHelper::Label state(yamlSaveHelper, "%s:\n", SS_YAML_KEY_RX_MEMORY);
yamlSaveHelper.SaveMemory(myMemory.data() + W5100_RX_BASE, W5100_MEM_SIZE - W5100_RX_BASE);
}
for (size_t i = 0; i < mySockets.size(); ++i)
{
YamlSaveHelper::Label state(yamlSaveHelper, "%s %" SIZE_T_FMT ":\n", SS_YAML_KEY_SOCKET, i);
mySockets[i].SaveSnapshot(yamlSaveHelper);
}
}
bool Uthernet2::LoadSnapshot(YamlLoadHelper &yamlLoadHelper, UINT version)
{
if (version < 1 || version > kUNIT_VERSION)
throw std::runtime_error("Card: wrong version");
ThrowErrorInvalidVersion(version);
yamlLoadHelper.LoadBool(SS_YAML_KEY_ENABLED); // FIXME: what is the point of this?
PCapBackend::tfe_interface = yamlLoadHelper.LoadString(SS_YAML_KEY_NETWORK_INTERFACE);
PCapBackend::tfe_SetRegistryInterface(m_slot, PCapBackend::tfe_interface);
Reset(true); // AFTER the interface name has been restored
myModeRegister = yamlLoadHelper.LoadUint(SS_YAML_KEY_MODE_REGISTER);
myDataAddress = yamlLoadHelper.LoadUint(SS_YAML_KEY_DATA_ADDRESS);
if (yamlLoadHelper.GetSubMap(SS_YAML_KEY_COMMON_REGISTERS))
{
yamlLoadHelper.LoadMemory(myMemory.data(), W5100_UPORT1 + 1);
yamlLoadHelper.PopMap();
}
if (yamlLoadHelper.GetSubMap(SS_YAML_KEY_SOCKETS_REGISTERS))
{
yamlLoadHelper.LoadMemory(myMemory.data() + W5100_S0_BASE, (W5100_S3_MAX + 1) - W5100_S0_BASE);
yamlLoadHelper.PopMap();
}
if (yamlLoadHelper.GetSubMap(SS_YAML_KEY_TX_MEMORY))
{
yamlLoadHelper.LoadMemory(myMemory.data() + W5100_TX_BASE, W5100_RX_BASE - W5100_TX_BASE);
yamlLoadHelper.PopMap();
}
if (yamlLoadHelper.GetSubMap(SS_YAML_KEY_RX_MEMORY))
{
yamlLoadHelper.LoadMemory(myMemory.data() + W5100_RX_BASE, W5100_MEM_SIZE - W5100_RX_BASE);
yamlLoadHelper.PopMap();
}
setRXSizes(W5100_RMSR, myMemory[W5100_RMSR]);
setTXSizes(W5100_TMSR, myMemory[W5100_TMSR]);
for (size_t i = 0; i < mySockets.size(); ++i)
{
const std::string key = StrFormat("%s %" SIZE_T_FMT, SS_YAML_KEY_SOCKET, i);
if (yamlLoadHelper.GetSubMap(key))
{
mySockets[i].LoadSnapshot(yamlLoadHelper);
yamlLoadHelper.PopMap();
}
}
return true;
}

View File

@ -18,7 +18,7 @@ struct Socket
uint16_t transmitSize;
uint16_t receiveBase;
uint16_t receiveSize;
uint16_t registers;
uint16_t registerAddress;
uint16_t sn_rx_wr;
uint16_t sn_rx_rsr;
@ -35,6 +35,9 @@ struct Socket
bool isThereRoomFor(const size_t len, const size_t header) const;
uint16_t getFreeRoom() const;
void SaveSnapshot(YamlSaveHelper &yamlSaveHelper);
bool LoadSnapshot(YamlLoadHelper &yamlLoadHelper);
Socket();
~Socket();

View File

@ -2,85 +2,87 @@
// Uthernet II registers
#define C0X_MODE_REGISTER 0x04
#define C0X_ADDRESS_HIGH 0x05
#define C0X_ADDRESS_LOW 0x06
#define C0X_DATA_PORT 0x07
#define U2_C0X_MODE_REGISTER 0x04
#define U2_C0X_ADDRESS_HIGH 0x05
#define U2_C0X_ADDRESS_LOW 0x06
#define U2_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 W5100_MR 0x0000
#define W5100_GAR0 0x0001
#define W5100_GAR3 0x0004
#define W5100_SUBR0 0x0005
#define W5100_SUBR3 0x0008
#define W5100_SHAR0 0x0009
#define W5100_SHAR5 0x000E
#define W5100_SIPR0 0x000F
#define W5100_SIPR3 0x0012
#define W5100_RTR0 0x0017
#define W5100_RTR1 0x0018
#define W5100_RMSR 0x001A
#define W5100_TMSR 0x001B
#define W5100_UPORT1 0x002F
#define W5100_S0_BASE 0x0400
#define W5100_S3_MAX 0x07FF
#define W5100_TX_BASE 0x4000
#define W5100_RX_BASE 0x6000
#define W5100_MEM_MAX 0x7FFF
#define W5100_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 W5100_MR_IND 0x01 // 0
#define W5100_MR_AI 0x02 // 1
#define W5100_MR_PPOE 0x08 // 3
#define W5100_MR_PB 0x10 // 4
#define W5100_MR_RST 0x80 // 7
#define SN_MR_PROTO_MASK 0x0F
#define SN_MR_MF 0x40 // 6
#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 W5100_SN_MR_PROTO_MASK 0x0F
#define W5100_SN_MR_MF 0x40 // 6
#define W5100_SN_MR_CLOSED 0x00
#define W5100_SN_MR_TCP 0x01
#define W5100_SN_MR_UDP 0x02
#define W5100_SN_MR_IPRAW 0x03
#define W5100_SN_MR_MACRAW 0x04
#define W5100_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 W5100_SN_CR_OPEN 0x01
#define W5100_SN_CR_LISTENT 0x02
#define W5100_SN_CR_CONNECT 0x04
#define W5100_SN_CR_DISCON 0x08
#define W5100_SN_CR_CLOSE 0x10
#define W5100_SN_CR_SEND 0x20
#define W5100_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_DIPR1 0x0D
#define SN_DIPR2 0x0E
#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 W5100_SN_MR 0x00
#define W5100_SN_CR 0x01
#define W5100_SN_SR 0x03
#define W5100_SN_PORT0 0x04
#define W5100_SN_PORT1 0x05
#define W5100_SN_DIPR0 0x0C
#define W5100_SN_DIPR1 0x0D
#define W5100_SN_DIPR2 0x0E
#define W5100_SN_DIPR3 0x0F
#define W5100_SN_DPORT0 0x10
#define W5100_SN_DPORT1 0x11
#define W5100_SN_PROTO 0x14
#define W5100_SN_TOS 0x15
#define W5100_SN_TTL 0x16
#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
#define W5100_SN_TX_FSR0 0x20 // TX Free Size
#define W5100_SN_TX_FSR1 0x21 // TX Free Size
#define W5100_SN_TX_RD0 0x22 // TX Read Pointer
#define W5100_SN_TX_RD1 0x23 // TX Read Pointer
#define W5100_SN_TX_WR0 0x24 // TX Write Pointer
#define W5100_SN_TX_WR1 0x25 // TX Write Pointer
#define W5100_SN_RX_RSR0 0x26 // RX Receive Size
#define W5100_SN_RX_RSR1 0x27 // RX Receive Size
#define W5100_SN_RX_RD0 0x28 // RX Read Pointer
#define W5100_SN_RX_RD1 0x29 // RX Read Pointer
#define W5100_SN_SR_CLOSED 0x00
#define W5100_SN_SR_SOCK_INIT 0x13
#define W5100_SN_SR_ESTABLISHED 0x17
#define W5100_SN_SR_SOCK_UDP 0x22
#define W5100_SN_SR_SOCK_IPRAW 0x32
#define W5100_SN_SR_SOCK_MACRAW 0x42