2021-04-23 11:49:19 +01:00
|
|
|
#include <StdAfx.h>
|
2021-04-30 20:10:30 +01:00
|
|
|
|
|
|
|
#define MAX_RXLENGTH 1518
|
2021-05-01 19:31:23 +01:00
|
|
|
|
2021-04-30 20:10:30 +01:00
|
|
|
// #define U2_LOG_VERBOSE
|
|
|
|
// #define U2_LOG_TRAFFIC
|
|
|
|
#define U2_LOG_UNKNOWN
|
2021-05-01 19:31:23 +01:00
|
|
|
|
|
|
|
// if this is defined, libslirp is used as opposed to libpcap
|
2021-04-30 20:10:30 +01:00
|
|
|
#define U2_USE_SLIRP
|
|
|
|
|
2021-04-28 20:32:01 +01:00
|
|
|
#include "linux/network/uthernet2.h"
|
|
|
|
#include "linux/network/tfe2.h"
|
2021-05-01 19:31:23 +01:00
|
|
|
#include "linux/network/registers.h"
|
2021-04-23 11:49:19 +01:00
|
|
|
|
2021-04-30 20:10:30 +01:00
|
|
|
#ifdef U2_USE_SLIRP
|
|
|
|
#include "linux/network/slirp2.h"
|
|
|
|
#endif
|
|
|
|
|
2021-04-23 11:49:19 +01:00
|
|
|
#include "Memory.h"
|
2021-04-25 18:29:48 +01:00
|
|
|
#include "Log.h"
|
2021-04-23 11:49:19 +01:00
|
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
struct Socket
|
|
|
|
{
|
|
|
|
uint16_t transmitBase;
|
|
|
|
uint16_t transmitSize;
|
|
|
|
uint16_t receiveBase;
|
|
|
|
uint16_t receiveSize;
|
|
|
|
uint16_t registers;
|
|
|
|
|
2021-04-23 20:10:25 +01:00
|
|
|
uint16_t sn_rx_wr;
|
|
|
|
uint16_t sn_rx_rsr;
|
2021-04-23 11:49:19 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<uint8_t> memory;
|
|
|
|
std::vector<Socket> sockets;
|
|
|
|
uint8_t modeRegister = 0;
|
|
|
|
uint16_t dataAddress = 0;
|
|
|
|
|
2021-04-30 20:10:30 +01:00
|
|
|
#ifdef U2_USE_SLIRP
|
|
|
|
std::shared_ptr<SlirpNet> slirp;
|
|
|
|
#endif
|
|
|
|
|
2021-04-23 11:49:19 +01:00
|
|
|
void initialise();
|
|
|
|
|
2021-04-30 20:10:30 +01:00
|
|
|
bool isThereRoomFor(const size_t i, const size_t len)
|
|
|
|
{
|
|
|
|
const Socket & socket = sockets[i];
|
|
|
|
const uint16_t rsr = socket.sn_rx_rsr; // already present
|
|
|
|
const int size = socket.receiveSize; // total size
|
|
|
|
|
|
|
|
return rsr + len + sizeof(uint16_t) < size; // "not =": we do not want to fill the buffer.
|
|
|
|
}
|
|
|
|
|
2021-04-23 20:10:25 +01:00
|
|
|
uint8_t getIByte(const uint16_t value, const size_t shift)
|
|
|
|
{
|
|
|
|
return (value >> shift) & 0xFF;
|
|
|
|
}
|
|
|
|
|
2021-04-23 11:49:19 +01:00
|
|
|
void write8(const size_t i, const uint8_t value)
|
|
|
|
{
|
|
|
|
Socket & socket = sockets[i];
|
|
|
|
const uint16_t base = socket.receiveBase;
|
2021-04-23 20:10:25 +01:00
|
|
|
const uint16_t address = base + socket.sn_rx_wr;
|
2021-04-23 11:49:19 +01:00
|
|
|
memory[address] = value;
|
2021-04-23 20:10:25 +01:00
|
|
|
socket.sn_rx_wr = (socket.sn_rx_wr + 1) % socket.receiveSize;
|
|
|
|
++socket.sn_rx_rsr;
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void write16(const size_t i, const uint16_t value)
|
|
|
|
{
|
2021-04-23 20:10:25 +01:00
|
|
|
write8(i, getIByte(value, 8)); // high
|
|
|
|
write8(i, getIByte(value, 0)); // low
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void writeData(const size_t i, const BYTE * data, const size_t len)
|
|
|
|
{
|
|
|
|
const uint16_t size = len + sizeof(uint16_t);
|
|
|
|
write16(i, size);
|
|
|
|
for (size_t c = 0; c < len; ++c)
|
|
|
|
{
|
|
|
|
write8(i, data[c]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void writePacketString(const size_t i, const std::string & s)
|
|
|
|
{
|
|
|
|
const uint16_t size = s.size() + sizeof(uint16_t); // no NULL
|
|
|
|
write16(i, size);
|
|
|
|
for (size_t c = 0; c < s.size(); ++c)
|
|
|
|
{
|
|
|
|
write8(i, s[c]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void setSocketModeRegister(const size_t i, const uint16_t address, const uint8_t value)
|
|
|
|
{
|
|
|
|
memory[address] = value;
|
2021-05-01 19:31:23 +01:00
|
|
|
const uint8_t protocol = value & SN_MR_PROTO_MASK;
|
2021-04-23 11:49:19 +01:00
|
|
|
switch (protocol)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_MR_CLOSED:
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: Mode[%d]: CLOSED\n", i);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 20:39:09 +01:00
|
|
|
case SN_MR_TCP:
|
|
|
|
LogFileOutput("U2: Mode[%d]: TCP\n", i);
|
|
|
|
break;
|
|
|
|
case SN_MR_UDP:
|
|
|
|
LogFileOutput("U2: Mode[%d]: UDP\n", i);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_MR_IPRAW:
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: Mode[%d]: IPRAW\n", i);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_MR_MACRAW:
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: Mode[%d]: MACRAW\n", i);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_UNKNOWN
|
2021-04-23 11:49:19 +01:00
|
|
|
default:
|
2021-05-01 20:39:09 +01:00
|
|
|
LogFileOutput("U2: Unknown protocol: %02x\n", protocol);
|
2021-04-23 11:49:19 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void setTXSizes(const uint16_t address, uint8_t value)
|
|
|
|
{
|
|
|
|
memory[address] = value;
|
2021-05-01 19:31:23 +01:00
|
|
|
uint16_t base = TX_BASE;
|
|
|
|
const uint16_t end = RX_BASE;
|
2021-04-23 11:49:19 +01:00
|
|
|
for (size_t i = 0; i < 4; ++i)
|
|
|
|
{
|
|
|
|
sockets[i].transmitBase = base;
|
|
|
|
|
|
|
|
const uint8_t bits = value & 0x03;
|
|
|
|
value >>= 2;
|
|
|
|
|
|
|
|
const uint16_t size = 1 << (10 + bits);
|
|
|
|
base += size;
|
|
|
|
|
2021-05-01 19:31:23 +01:00
|
|
|
if (base > end)
|
2021-04-23 11:49:19 +01:00
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
base = end;
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
sockets[i].transmitSize = base - sockets[i].transmitBase;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void setRXSizes(const uint16_t address, uint8_t value)
|
|
|
|
{
|
|
|
|
memory[address] = value;
|
2021-05-01 19:31:23 +01:00
|
|
|
uint16_t base = RX_BASE;
|
|
|
|
const uint16_t end = MEM_SIZE;
|
2021-04-23 11:49:19 +01:00
|
|
|
for (size_t i = 0; i < 4; ++i)
|
|
|
|
{
|
|
|
|
sockets[i].receiveBase = base;
|
|
|
|
|
|
|
|
const uint8_t bits = value & 0x03;
|
|
|
|
value >>= 2;
|
|
|
|
|
|
|
|
const uint16_t size = 1 << (10 + bits);
|
|
|
|
base += size;
|
|
|
|
|
2021-05-01 19:31:23 +01:00
|
|
|
if (base > end)
|
2021-04-23 11:49:19 +01:00
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
base = end;
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
sockets[i].receiveSize = base - sockets[i].receiveBase;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t getTXDataSize(const size_t i)
|
|
|
|
{
|
2021-04-28 20:27:43 +01:00
|
|
|
const Socket & socket = sockets[i];
|
|
|
|
const uint16_t size = socket.transmitSize;
|
2021-04-23 11:49:19 +01:00
|
|
|
const uint16_t mask = size - 1;
|
|
|
|
|
2021-05-01 19:31:23 +01:00
|
|
|
const int sn_tx_rd = readNetworkWord(memory.data() + socket.registers + SN_TX_RD0) & mask;
|
|
|
|
const int sn_tx_wr = readNetworkWord(memory.data() + socket.registers + SN_TX_WR0) & mask;
|
2021-04-23 11:49:19 +01:00
|
|
|
|
2021-05-01 19:31:23 +01:00
|
|
|
int dataPresent = sn_tx_wr - sn_tx_rd;
|
2021-04-23 11:49:19 +01:00
|
|
|
if (dataPresent < 0)
|
|
|
|
{
|
|
|
|
dataPresent += size;
|
|
|
|
}
|
|
|
|
return dataPresent;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t getTXFreeSizeRegister(const size_t i, const size_t shift)
|
|
|
|
{
|
|
|
|
const int size = sockets[i].transmitSize;
|
|
|
|
const uint16_t present = getTXDataSize(i);
|
|
|
|
const uint16_t free = size - present;
|
2021-04-23 20:10:25 +01:00
|
|
|
const uint8_t reg = getIByte(free, shift);
|
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t getRXDataSizeRegister(const size_t i, const size_t shift)
|
|
|
|
{
|
|
|
|
const uint16_t rsr = sockets[i].sn_rx_rsr;
|
|
|
|
const uint8_t reg = getIByte(rsr, shift);
|
2021-04-23 11:49:19 +01:00
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
2021-04-23 20:10:25 +01:00
|
|
|
void updateRSR(const size_t i)
|
2021-04-23 11:49:19 +01:00
|
|
|
{
|
2021-04-23 20:10:25 +01:00
|
|
|
Socket & socket = sockets[i];
|
|
|
|
|
2021-04-23 11:49:19 +01:00
|
|
|
const int size = sockets[i].receiveSize;
|
|
|
|
const uint16_t mask = size - 1;
|
|
|
|
|
2021-05-01 19:31:23 +01:00
|
|
|
const int sn_rx_rd = readNetworkWord(memory.data() + socket.registers + SN_RX_RD0) & mask;
|
2021-04-28 20:27:43 +01:00
|
|
|
const int sn_rx_wr = socket.sn_rx_wr & mask;
|
2021-04-23 20:10:25 +01:00
|
|
|
int dataPresent = sn_rx_wr - sn_rx_rd;
|
2021-04-23 11:49:19 +01:00
|
|
|
if (dataPresent < 0)
|
|
|
|
{
|
|
|
|
dataPresent += size;
|
|
|
|
}
|
2021-04-23 20:10:25 +01:00
|
|
|
// 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
|
|
|
|
socket.sn_rx_rsr = dataPresent;
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void receiveOnePacketMacRaw(const size_t i)
|
|
|
|
{
|
2021-04-30 20:10:30 +01:00
|
|
|
const Socket & socket = sockets[i];
|
2021-04-23 20:10:25 +01:00
|
|
|
const uint16_t rsr = socket.sn_rx_rsr;
|
2021-04-23 11:49:19 +01:00
|
|
|
|
2021-04-30 20:10:30 +01:00
|
|
|
#ifdef U2_USE_SLIRP
|
2021-04-23 11:49:19 +01:00
|
|
|
{
|
2021-04-30 20:10:30 +01:00
|
|
|
std::queue<std::vector<uint8_t>> & queue = slirp->getQueue();
|
|
|
|
if (!queue.empty())
|
2021-04-23 11:49:19 +01:00
|
|
|
{
|
2021-04-30 20:10:30 +01:00
|
|
|
const std::vector<uint8_t> & packet = queue.front();
|
|
|
|
if (isThereRoomFor(i, packet.size()))
|
|
|
|
{
|
|
|
|
writeData(i, packet.data(), packet.size());
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_TRAFFIC
|
2021-04-30 20:10:30 +01:00
|
|
|
LogFileOutput("U2: READ MACRAW[%d]: +%d -> %d bytes\n", i, packet.size(), socket.sn_rx_rsr);
|
2021-04-25 18:29:48 +01:00
|
|
|
#endif
|
2021-04-30 20:10:30 +01:00
|
|
|
}
|
|
|
|
// maybe we should wait?
|
|
|
|
queue.pop();
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
2021-04-30 20:10:30 +01:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
{
|
|
|
|
BYTE buffer[MAX_RXLENGTH];
|
|
|
|
int len = sizeof(buffer);
|
2021-05-01 19:31:23 +01:00
|
|
|
if (tfeReceiveOnePacket(memory.data() + SHAR0, buffer, len))
|
2021-04-23 11:49:19 +01:00
|
|
|
{
|
2021-04-30 20:10:30 +01:00
|
|
|
if (isThereRoomFor(i, len))
|
|
|
|
{
|
|
|
|
writeData(i, buffer, len);
|
|
|
|
#ifdef U2_LOG_TRAFFIC
|
|
|
|
LogFileOutput("U2: READ MACRAW[%d]: +%d -> %d bytes\n", i, len, socket.sn_rx_rsr);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// ??? we just skip it
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_TRAFFIC
|
2021-04-30 20:10:30 +01:00
|
|
|
LogFileOutput("U2: SKIP MACRAW[%d]: %d bytes\n", i, len);
|
2021-04-25 18:29:48 +01:00
|
|
|
#endif
|
2021-04-30 20:10:30 +01:00
|
|
|
}
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
}
|
2021-04-30 20:10:30 +01:00
|
|
|
#endif
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void receiveOnePacket(const size_t i)
|
|
|
|
{
|
|
|
|
const Socket & socket = sockets[i];
|
2021-05-01 19:31:23 +01:00
|
|
|
const uint8_t sr = memory[socket.registers + SN_SR];
|
2021-04-23 11:49:19 +01:00
|
|
|
switch (sr)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_SR_SOCK_MACRAW:
|
2021-04-23 11:49:19 +01:00
|
|
|
receiveOnePacketMacRaw(i);
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-04-24 08:06:00 +01:00
|
|
|
void sendDataMacRaw(const size_t i, const std::vector<uint8_t> & data)
|
|
|
|
{
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_TRAFFIC
|
|
|
|
LogFileOutput("U2: SEND MACRAW[%d]: %d bytes\n", i, data.size());
|
|
|
|
#endif
|
2021-04-30 20:10:30 +01:00
|
|
|
#ifdef U2_USE_SLIRP
|
|
|
|
slirp->sendFromGuest(data.data(), data.size());
|
|
|
|
#else
|
2021-04-24 08:06:00 +01:00
|
|
|
tfeTransmitOnePacket(data.data(), data.size());
|
2021-04-30 20:10:30 +01:00
|
|
|
#endif
|
2021-04-24 08:06:00 +01:00
|
|
|
}
|
|
|
|
|
2021-04-30 20:10:30 +01:00
|
|
|
void sendDataIPRaw(const size_t i, std::vector<uint8_t> & data)
|
2021-04-24 08:06:00 +01:00
|
|
|
{
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_TRAFFIC
|
2021-04-24 08:06:00 +01:00
|
|
|
const Socket & socket = sockets[i];
|
2021-05-01 19:31:23 +01:00
|
|
|
const uint16_t ip = socket.registers + SN_DIPR0;
|
2021-04-24 08:06:00 +01:00
|
|
|
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: SEND IPRAW[%d]: %d bytes", i, data.size());
|
2021-05-01 19:31:23 +01:00
|
|
|
const uint8_t * source = memory.data() + SIPR0;
|
2021-04-25 18:29:48 +01:00
|
|
|
const uint8_t * dest = memory.data() + ip;
|
2021-05-01 19:31:23 +01:00
|
|
|
const uint8_t * gway = memory.data() + GAR0;
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput(" from %d.%d.%d.%d", source[0], source[1], source[2], source[3]);
|
|
|
|
LogFileOutput(" to %d.%d.%d.%d", dest[0], dest[1], dest[2], dest[3]);
|
|
|
|
LogFileOutput(" via %d.%d.%d.%d\n", gway[0], gway[1], gway[2], gway[3]);
|
|
|
|
#endif
|
2021-04-30 20:10:30 +01:00
|
|
|
// dont know how to send IP raw.
|
2021-04-24 08:06:00 +01:00
|
|
|
}
|
|
|
|
|
2021-04-23 11:49:19 +01:00
|
|
|
void sendData(const size_t i)
|
|
|
|
{
|
|
|
|
const Socket & socket = sockets[i];
|
|
|
|
const uint16_t size = socket.transmitSize;
|
|
|
|
const uint16_t mask = size - 1;
|
|
|
|
|
2021-05-01 19:31:23 +01:00
|
|
|
const int sn_tx_rr = readNetworkWord(memory.data() + socket.registers + SN_TX_RD0) & mask;
|
|
|
|
const int sn_tx_wr = readNetworkWord(memory.data() + socket.registers + SN_TX_WR0) & mask;
|
2021-04-23 11:49:19 +01:00
|
|
|
|
|
|
|
const uint16_t base = socket.transmitBase;
|
2021-04-23 20:10:25 +01:00
|
|
|
const uint16_t rr_address = base + sn_tx_rr;
|
|
|
|
const uint16_t wr_address = base + sn_tx_wr;
|
2021-04-23 11:49:19 +01:00
|
|
|
|
|
|
|
std::vector<uint8_t> data;
|
|
|
|
if (rr_address < wr_address)
|
|
|
|
{
|
|
|
|
data.assign(memory.begin() + rr_address, memory.begin() + wr_address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const uint16_t end = base + size;
|
|
|
|
data.assign(memory.begin() + rr_address, memory.begin() + end);
|
|
|
|
data.insert(data.end(), memory.begin() + base, memory.begin() + wr_address);
|
|
|
|
}
|
|
|
|
|
2021-04-23 20:10:25 +01:00
|
|
|
// move read pointer to writer
|
2021-05-01 19:31:23 +01:00
|
|
|
memory[socket.registers + SN_TX_RD0] = getIByte(sn_tx_wr, 8);
|
|
|
|
memory[socket.registers + SN_TX_RD1] = getIByte(sn_tx_wr, 0);
|
2021-04-23 11:49:19 +01:00
|
|
|
|
2021-05-01 19:31:23 +01:00
|
|
|
const uint8_t sr = memory[socket.registers + SN_SR];
|
2021-04-24 08:06:00 +01:00
|
|
|
switch (sr)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_SR_SOCK_IPRAW:
|
2021-04-24 08:06:00 +01:00
|
|
|
sendDataIPRaw(i, data);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_SR_SOCK_MACRAW:
|
2021-04-24 08:06:00 +01:00
|
|
|
sendDataMacRaw(i, data);
|
|
|
|
break;
|
|
|
|
}
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void resetRXTXBuffers(const size_t i)
|
|
|
|
{
|
|
|
|
Socket & socket = sockets[i];
|
2021-04-23 20:10:25 +01:00
|
|
|
socket.sn_rx_wr = 0x00;
|
|
|
|
socket.sn_rx_rsr = 0x00;
|
2021-05-01 19:31:23 +01:00
|
|
|
memory[socket.registers + SN_TX_RD0] = 0x00;
|
|
|
|
memory[socket.registers + SN_TX_RD1] = 0x00;
|
|
|
|
memory[socket.registers + SN_TX_WR0] = 0x00;
|
|
|
|
memory[socket.registers + SN_TX_WR1] = 0x00;
|
|
|
|
memory[socket.registers + SN_RX_RD0] = 0x00;
|
|
|
|
memory[socket.registers + SN_RX_RD1] = 0x00;
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void openSocket(const size_t i)
|
|
|
|
{
|
|
|
|
const Socket & socket = sockets[i];
|
2021-05-01 19:31:23 +01:00
|
|
|
const uint8_t mr = memory[socket.registers + SN_MR];
|
|
|
|
const uint8_t protocol = mr & SN_MR_PROTO_MASK;
|
|
|
|
uint8_t & sr = memory[socket.registers + SN_SR];
|
2021-04-23 11:49:19 +01:00
|
|
|
switch (protocol)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_MR_IPRAW:
|
|
|
|
sr = SN_SR_SOCK_IPRAW;
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_MR_MACRAW:
|
|
|
|
sr = SN_SR_SOCK_MACRAW;
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 20:39:09 +01:00
|
|
|
case SN_MR_TCP:
|
|
|
|
sr = SN_SR_SOCK_INIT;
|
|
|
|
break;
|
|
|
|
case SN_MR_UDP:
|
|
|
|
sr = SN_SR_SOCK_UDP;
|
|
|
|
break;
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_UNKNOWN
|
2021-04-23 11:49:19 +01:00
|
|
|
default:
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: OPEN[%d]: unknown mode: %02x\n", i, mr);
|
2021-04-23 11:49:19 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
resetRXTXBuffers(i);
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: OPEN[%d]: %02x\n", i, sr);
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void closeSocket(const size_t i)
|
|
|
|
{
|
|
|
|
const Socket & socket = sockets[i];
|
2021-05-01 20:39:09 +01:00
|
|
|
memory[socket.registers + SN_SR] = SN_SR_CLOSED;
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: CLOSE[%d]\n", i);
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
2021-05-01 20:39:09 +01:00
|
|
|
void connectSocket(const size_t i)
|
|
|
|
{
|
|
|
|
const Socket & socket = sockets[i];
|
|
|
|
memory[socket.registers + SN_SR] = SN_SR_ESTABLISHED;
|
|
|
|
const uint8_t * dest = memory.data() + socket.registers + SN_DIPR0;
|
|
|
|
const uint16_t port = readNetworkWord(memory.data() + socket.registers + SN_DPORT0);
|
|
|
|
LogFileOutput("U2: TCP[%d]: CONNECT to %d.%d.%d.%d:%d\n", i, dest[0], dest[1], dest[2], dest[3], port);
|
|
|
|
}
|
|
|
|
|
2021-04-23 11:49:19 +01:00
|
|
|
void setCommandRegister(const size_t i, const uint8_t value)
|
|
|
|
{
|
|
|
|
switch (value)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_CR_OPEN:
|
2021-04-23 11:49:19 +01:00
|
|
|
openSocket(i);
|
|
|
|
break;
|
2021-05-01 20:39:09 +01:00
|
|
|
case SN_CR_CONNECT:
|
|
|
|
connectSocket(i);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_CR_CLOSE:
|
2021-04-23 11:49:19 +01:00
|
|
|
closeSocket(i);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_CR_SEND:
|
2021-04-23 11:49:19 +01:00
|
|
|
sendData(i);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_CR_RECV:
|
2021-04-23 11:49:19 +01:00
|
|
|
updateRSR(i);
|
|
|
|
break;
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_UNKNOWN
|
2021-04-23 11:49:19 +01:00
|
|
|
default:
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: Unknown command[%d]: %02x\n", i, value);
|
2021-04-23 11:49:19 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t readSocketRegister(const uint16_t address)
|
|
|
|
{
|
|
|
|
const uint16_t i = (address >> (2 + 8 + 8));
|
|
|
|
const uint16_t loc = address & 0xFF;
|
|
|
|
uint8_t value;
|
|
|
|
switch (loc)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_MR:
|
|
|
|
case SN_CR:
|
2021-05-01 20:39:09 +01:00
|
|
|
case SN_SR:
|
2021-04-23 11:49:19 +01:00
|
|
|
value = memory[address];
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_TX_FSR0:
|
2021-04-23 11:49:19 +01:00
|
|
|
value = getTXFreeSizeRegister(i, 8);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_TX_FSR1:
|
2021-04-23 11:49:19 +01:00
|
|
|
value = getTXFreeSizeRegister(i, 0);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_TX_RD0:
|
|
|
|
case SN_TX_RD1:
|
2021-04-23 11:49:19 +01:00
|
|
|
value = memory[address];
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_TX_WR0:
|
|
|
|
case SN_TX_WR1:
|
2021-04-23 11:49:19 +01:00
|
|
|
value = memory[address];
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_RX_RSR0:
|
2021-04-23 20:10:25 +01:00
|
|
|
value = getRXDataSizeRegister(i, 8);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_RX_RSR1:
|
2021-04-23 20:10:25 +01:00
|
|
|
value = getRXDataSizeRegister(i, 0);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_RX_RD0:
|
|
|
|
case SN_RX_RD1:
|
2021-04-23 11:49:19 +01:00
|
|
|
value = memory[address];
|
|
|
|
break;
|
|
|
|
default:
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_UNKNOWN
|
|
|
|
LogFileOutput("U2: Get unknown socket register[%d]: %04x\n", i, address);
|
2021-04-23 11:49:19 +01:00
|
|
|
#endif
|
|
|
|
value = memory[address];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t readValueAt(const uint16_t address)
|
|
|
|
{
|
|
|
|
uint8_t value;
|
|
|
|
switch (address)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case MR ... UPORT1:
|
2021-04-23 11:49:19 +01:00
|
|
|
value = memory[address];
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case S0_BASE ... S3_MAX:
|
2021-04-23 11:49:19 +01:00
|
|
|
value = readSocketRegister(address);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case TX_BASE ... MEM_MAX:
|
2021-04-23 11:49:19 +01:00
|
|
|
value = memory[address];
|
|
|
|
break;
|
|
|
|
default:
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_UNKNOWN
|
|
|
|
LogFileOutput("U2: Read unknown location: %04x\n", address);
|
2021-04-23 11:49:19 +01:00
|
|
|
#endif
|
2021-05-01 19:31:23 +01:00
|
|
|
// this might not be 100% correct if address >= 0x8000
|
|
|
|
// see top of page 13 Uthernet II
|
|
|
|
value = memory[address & MEM_MAX];
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void autoIncrement()
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
if (modeRegister & MR_AI)
|
2021-04-23 11:49:19 +01:00
|
|
|
{
|
|
|
|
++dataAddress;
|
2021-05-01 19:31:23 +01:00
|
|
|
// Read bottom of Uthernet II page 12
|
|
|
|
// Setting the address to values >= 0x8000 is not really supported
|
2021-04-23 11:49:19 +01:00
|
|
|
switch (dataAddress)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case RX_BASE:
|
|
|
|
case MEM_SIZE:
|
2021-04-23 11:49:19 +01:00
|
|
|
dataAddress -= 0x2000;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t readValue()
|
|
|
|
{
|
|
|
|
const uint8_t value = readValueAt(dataAddress);
|
|
|
|
autoIncrement();
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setIPProtocol(const size_t i, const uint8_t value)
|
|
|
|
{
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: IP PROTO[%d] = %d\n", i, value);
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void setIPTypeOfService(const size_t i, const uint8_t value)
|
|
|
|
{
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: IP TOS[%d] = %d\n", i, value);
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void setIPTTL(const size_t i, const uint8_t value)
|
|
|
|
{
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: IP TTL[%d] = %d\n", i, value);
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void writeSocketRegister(const uint16_t address, const uint8_t value)
|
|
|
|
{
|
2021-04-24 08:06:00 +01:00
|
|
|
const uint16_t i = (address >> 8) - 0x04;
|
2021-04-23 11:49:19 +01:00
|
|
|
const uint16_t loc = address & 0xFF;
|
|
|
|
switch (loc)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_MR:
|
2021-04-23 11:49:19 +01:00
|
|
|
setSocketModeRegister(i, address, value);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_CR:
|
2021-04-23 11:49:19 +01:00
|
|
|
setCommandRegister(i, value);
|
|
|
|
break;
|
2021-05-01 20:39:09 +01:00
|
|
|
case SN_PORT0:
|
|
|
|
case SN_PORT1:
|
|
|
|
case SN_DPORT0:
|
|
|
|
case SN_DPORT1:
|
|
|
|
memory[address] = value;
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_DIPR0 ... SN_DIPR3:
|
2021-04-24 08:06:00 +01:00
|
|
|
memory[address] = value;
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_PROTO:
|
2021-04-23 11:49:19 +01:00
|
|
|
setIPProtocol(i, value);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_TOS:
|
2021-04-23 11:49:19 +01:00
|
|
|
setIPTypeOfService(i, value);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_TTL:
|
2021-04-23 11:49:19 +01:00
|
|
|
setIPTTL(i, value);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_TX_WR0:
|
2021-04-23 20:10:25 +01:00
|
|
|
memory[address] = value;
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_TX_WR1:
|
2021-04-23 11:49:19 +01:00
|
|
|
memory[address] = value;
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_RX_RD0:
|
2021-04-23 20:10:25 +01:00
|
|
|
memory[address] = value;
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case SN_RX_RD1:
|
2021-04-23 11:49:19 +01:00
|
|
|
memory[address] = value;
|
|
|
|
break;
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_UNKNOWN
|
2021-04-23 11:49:19 +01:00
|
|
|
default:
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: Set unknown socket register[%d]: %04x\n", i, address);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void setModeRegister(const uint16_t address, const uint8_t value)
|
|
|
|
{
|
|
|
|
modeRegister = value;
|
2021-05-01 19:31:23 +01:00
|
|
|
if (modeRegister & MR_RST)
|
2021-04-23 11:49:19 +01:00
|
|
|
{
|
|
|
|
initialise();
|
|
|
|
}
|
|
|
|
memory[address] = value; // redundant
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeCommonRegister(const uint16_t address, const uint8_t value)
|
|
|
|
{
|
|
|
|
switch (address)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case MR:
|
2021-04-23 11:49:19 +01:00
|
|
|
setModeRegister(address, value);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case GAR0 ... GAR3:
|
|
|
|
case SUBR0 ... SUBR3:
|
|
|
|
case SHAR0 ... SHAR5:
|
|
|
|
case SIPR0 ... SIPR3:
|
2021-04-23 11:49:19 +01:00
|
|
|
memory[address] = value;
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case RMSR:
|
2021-04-23 11:49:19 +01:00
|
|
|
setRXSizes(address, value);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case TMSR:
|
2021-04-23 11:49:19 +01:00
|
|
|
setTXSizes(address, value);
|
|
|
|
break;
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_UNKNOWN
|
2021-04-23 11:49:19 +01:00
|
|
|
default:
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: Set unknown common register: %04x\n", address);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeValueAt(const uint16_t address, const uint8_t value)
|
|
|
|
{
|
|
|
|
switch (address)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case MR ... UPORT1:
|
2021-04-23 11:49:19 +01:00
|
|
|
writeCommonRegister(address, value);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case S0_BASE ... S3_MAX:
|
2021-04-23 11:49:19 +01:00
|
|
|
writeSocketRegister(address, value);
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case TX_BASE ... MEM_MAX:
|
2021-04-23 11:49:19 +01:00
|
|
|
memory[address] = value;
|
|
|
|
break;
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_UNKNOWN
|
2021-04-23 11:49:19 +01:00
|
|
|
default:
|
2021-05-01 19:31:23 +01:00
|
|
|
LogFileOutput("U2: Write to unknown location: %02x to %04x\n", value, address);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeValue(const uint8_t value)
|
|
|
|
{
|
|
|
|
writeValueAt(dataAddress, value);
|
|
|
|
autoIncrement();
|
|
|
|
}
|
|
|
|
|
|
|
|
void initialise()
|
|
|
|
{
|
2021-04-25 18:29:48 +01:00
|
|
|
LogFileOutput("U2: Uthernet 2 initialisation\n");
|
2021-04-23 11:49:19 +01:00
|
|
|
modeRegister = 0;
|
2021-05-01 19:31:23 +01:00
|
|
|
// dataAddress is NOT reset, see page 10 of Uthernet II
|
2021-04-23 11:49:19 +01:00
|
|
|
sockets.resize(4);
|
|
|
|
memory.clear();
|
2021-05-01 19:31:23 +01:00
|
|
|
memory.resize(MEM_SIZE, 0);
|
2021-04-23 11:49:19 +01:00
|
|
|
|
2021-05-01 19:31:23 +01:00
|
|
|
for (size_t i = 0; i < sockets.size(); ++i)
|
2021-04-23 11:49:19 +01:00
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
sockets[i].registers = S0_BASE + (i << 8);
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
2021-05-01 19:31:23 +01:00
|
|
|
// initial values
|
|
|
|
memory[RTR0] = 0x07;
|
|
|
|
memory[RTR1] = 0xD0;
|
|
|
|
setRXSizes(RMSR, 0x55);
|
|
|
|
setTXSizes(TMSR, 0x55);
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
|
|
|
|
2021-04-30 20:10:30 +01:00
|
|
|
void receivePackets()
|
2021-04-23 11:49:19 +01:00
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
for (size_t i = 0; i < sockets.size(); ++i)
|
2021-04-23 11:49:19 +01:00
|
|
|
{
|
|
|
|
receiveOnePacket(i);
|
|
|
|
}
|
2021-04-30 20:10:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
BYTE u2_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
|
|
|
|
{
|
|
|
|
receivePackets();
|
2021-04-23 11:49:19 +01:00
|
|
|
|
2021-04-28 20:32:01 +01:00
|
|
|
BYTE res = write ? 0 : MemReadFloatingBus(nCycles);
|
2021-04-23 11:49:19 +01:00
|
|
|
|
|
|
|
const uint8_t loc = address & 0x0F;
|
|
|
|
|
|
|
|
if (write)
|
|
|
|
{
|
|
|
|
switch (loc)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case C0X_MODE_REGISTER:
|
|
|
|
setModeRegister(MR, value);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case C0X_ADDRESS_HIGH:
|
|
|
|
dataAddress = (value << 8) | (dataAddress & 0x00FF);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case C0X_ADDRESS_LOW:
|
|
|
|
dataAddress = (value << 0) | (dataAddress & 0xFF00);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case C0X_DATA_PORT:
|
2021-04-23 11:49:19 +01:00
|
|
|
writeValue(value);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (loc)
|
|
|
|
{
|
2021-05-01 19:31:23 +01:00
|
|
|
case C0X_MODE_REGISTER:
|
2021-04-23 11:49:19 +01:00
|
|
|
res = modeRegister;
|
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case C0X_ADDRESS_HIGH:
|
|
|
|
res = getIByte(dataAddress, 8);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case C0X_ADDRESS_LOW:
|
|
|
|
res = getIByte(dataAddress, 0);
|
2021-04-23 11:49:19 +01:00
|
|
|
break;
|
2021-05-01 19:31:23 +01:00
|
|
|
case C0X_DATA_PORT:
|
2021-04-23 11:49:19 +01:00
|
|
|
res = readValue();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-25 18:29:48 +01:00
|
|
|
#ifdef U2_LOG_VERBOSE
|
2021-04-23 11:49:19 +01:00
|
|
|
const char * mode = write ? "WRITE " : "READ ";
|
2021-04-28 20:36:03 +01:00
|
|
|
const char c = std::isprint(res) ? res : '.';
|
2021-05-01 20:39:09 +01:00
|
|
|
LogFileOutput("U2: %04x: %s %04x %02x = %02x, %c [%d = %d]\n", programcounter, mode, address, value, res, c, value, res);
|
2021-04-23 11:49:19 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void registerUthernet2()
|
|
|
|
{
|
|
|
|
initialise();
|
2021-04-30 20:10:30 +01:00
|
|
|
#ifdef U2_USE_SLIRP
|
|
|
|
slirp.reset();
|
|
|
|
slirp = std::make_shared<SlirpNet>();
|
|
|
|
#endif
|
2021-05-01 19:31:23 +01:00
|
|
|
RegisterIoHandler(SLOT3, u2_C0, u2_C0, nullptr, nullptr, nullptr, nullptr);
|
2021-04-23 11:49:19 +01:00
|
|
|
}
|
2021-04-30 20:10:30 +01:00
|
|
|
|
|
|
|
void processEventsUthernet2(uint32_t timeout)
|
|
|
|
{
|
|
|
|
#ifdef U2_USE_SLIRP
|
2021-05-01 20:39:09 +01:00
|
|
|
if (slirp)
|
2021-04-30 20:10:30 +01:00
|
|
|
{
|
|
|
|
slirp->process(timeout);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|