Add support for the Uthernet 2 card.
Just enough to run contiki and A2osX. Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
This commit is contained in:
parent
982ba0922d
commit
5dd8e39787
8 changed files with 806 additions and 2 deletions
|
@ -73,6 +73,8 @@ set(SOURCE_FILES
|
|||
linux/keyboard.cpp
|
||||
linux/linuxframe.cpp
|
||||
linux/context.cpp
|
||||
linux/uthernet2.cpp
|
||||
linux/tfe2.cpp
|
||||
|
||||
linux/duplicates/Debug.cpp
|
||||
linux/duplicates/Debug_Display.cpp
|
||||
|
@ -159,6 +161,8 @@ set(HEADER_FILES
|
|||
linux/registry.h
|
||||
linux/keyboard.h
|
||||
linux/linuxframe.h
|
||||
linux/uthernet2.h
|
||||
linux/tfe2.h
|
||||
linux/win.h
|
||||
|
||||
Z80VICE/z80.h
|
||||
|
|
|
@ -501,7 +501,7 @@ void tfe_arch_transmit(int force, /* FORCE: Delete waiting frames in trans
|
|||
int inhibit_crc, /* INHIBITCRC: Do not append CRC to the transmission */
|
||||
int tx_pad_dis, /* TXPADDIS: Disable padding to 60 Bytes */
|
||||
int txlength, /* Frame length */
|
||||
BYTE *txframe /* Pointer to the frame to be transmitted */
|
||||
const BYTE *txframe /* Pointer to the frame to be transmitted */
|
||||
)
|
||||
{
|
||||
#ifdef TFE_DEBUG_ARCH
|
||||
|
|
|
@ -56,7 +56,7 @@ void tfe_arch_transmit(int force, /* FORCE: Delete waiting frames in trans
|
|||
int inhibit_crc, /* INHIBITCRC: Do not append CRC to the transmission */
|
||||
int tx_pad_dis, /* TXPADDIS: Disable padding to 60 Bytes */
|
||||
int txlength, /* Frame length */
|
||||
BYTE *txframe /* Pointer to the frame to be transmitted */
|
||||
const BYTE *txframe /* Pointer to the frame to be transmitted */
|
||||
);
|
||||
|
||||
extern
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include "Tfe/tfe.h"
|
||||
#include "Tfe/tfesupp.h"
|
||||
#include "linux/uthernet2.h"
|
||||
|
||||
#include "imgui_internal.h"
|
||||
|
||||
|
@ -583,6 +584,10 @@ namespace sa2
|
|||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if (ImGui::Button("Enable Uthernet 2"))
|
||||
{
|
||||
registerUthernet2();
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
|
|
122
source/linux/tfe2.cpp
Normal file
122
source/linux/tfe2.cpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
#include "StdAfx.h"
|
||||
#include "tfe2.h"
|
||||
|
||||
#include "Tfe/tfearch.h"
|
||||
#include "Tfe/tfe.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool shouldAccept(const uint8_t * mac, const BYTE *buffer, const int len)
|
||||
{
|
||||
if (len < 6)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer[0] == mac[0] &&
|
||||
buffer[1] == mac[1] &&
|
||||
buffer[2] == mac[2] &&
|
||||
buffer[3] == mac[3] &&
|
||||
buffer[4] == mac[4] &&
|
||||
buffer[5] == mac[5])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (buffer[0] == 0xFF &&
|
||||
buffer[1] == 0xFF &&
|
||||
buffer[2] == 0xFF &&
|
||||
buffer[3] == 0xFF &&
|
||||
buffer[4] == 0xFF &&
|
||||
buffer[5] == 0xFF)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::ostream & stream_mac(std::ostream & s, const uint8_t * mac)
|
||||
{
|
||||
for (size_t i = 0; i < 6; ++i)
|
||||
{
|
||||
as_hex(s, mac[i], 2);
|
||||
if (i != 6 - 1)
|
||||
{
|
||||
s << ":";
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void tfeTransmitOnePacket(const BYTE * buffer, const int len)
|
||||
{
|
||||
if (tfe_enabled)
|
||||
{
|
||||
tfe_arch_transmit(0, 0, 0, 0, len, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool tfeReceiveOnePacket(const uint8_t * mac, BYTE * buffer, int & len)
|
||||
{
|
||||
if (!tfe_enabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool done;
|
||||
|
||||
do
|
||||
{
|
||||
done = true;
|
||||
int hashed;
|
||||
int hash_index;
|
||||
int rx_ok;
|
||||
int correct_mac;
|
||||
int broadcast;
|
||||
int multicast = 0;
|
||||
int crc_error;
|
||||
|
||||
const int newframe = tfe_arch_receive(
|
||||
buffer, /* where to store a frame */
|
||||
&len, /* length of received frame */
|
||||
&hashed, /* set if the dest. address is accepted by the hash filter */
|
||||
&hash_index, /* hash table index if hashed == TRUE */
|
||||
&rx_ok, /* set if good CRC and valid length */
|
||||
&correct_mac, /* set if dest. address is exactly our IA */
|
||||
&broadcast, /* set if dest. address is a broadcast address */
|
||||
&crc_error /* set if received frame had a CRC error */
|
||||
);
|
||||
|
||||
if (newframe)
|
||||
{
|
||||
/* determine ourself the type of frame */
|
||||
if (shouldAccept(mac, buffer, len))
|
||||
{
|
||||
// std::cerr << "DEST ";
|
||||
// stream_mac(std::cerr, buffer) << " ? ";
|
||||
// stream_mac(std::cerr, mac) << " ";
|
||||
// as_hex(std::cerr, len, 4) << " bytes" << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
done = false; /* try another frame */
|
||||
}
|
||||
}
|
||||
} while (!done);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ostream & as_hex(std::ostream & s, const size_t value, const size_t width)
|
||||
{
|
||||
s << std::setfill('0') << std::setw(width) << std::hex << value << std::dec;
|
||||
return s;
|
||||
}
|
9
source/linux/tfe2.h
Normal file
9
source/linux/tfe2.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
bool tfeReceiveOnePacket(const uint8_t * mac, BYTE * buffer, int & len);
|
||||
void tfeTransmitOnePacket(const BYTE * buffer, const int len);
|
||||
|
||||
std::ostream & as_hex(std::ostream & s, const size_t value, const size_t width);
|
||||
std::ostream & stream_mac(std::ostream & s, const uint8_t * mac);
|
661
source/linux/uthernet2.cpp
Normal file
661
source/linux/uthernet2.cpp
Normal file
|
@ -0,0 +1,661 @@
|
|||
#include <StdAfx.h>
|
||||
#include "linux/uthernet2.h"
|
||||
#include "linux/tfe2.h"
|
||||
|
||||
#include "Memory.h"
|
||||
|
||||
#define MAX_RXLENGTH 1518
|
||||
//#define U2_VERBOSE
|
||||
#define U2_UNKNOWN
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace
|
||||
{
|
||||
#define MR_INDIRECT 0x01 // 0
|
||||
#define MR_AUTO_INC 0x02 // 1
|
||||
#define MR_PPOE_MOD 0x08 // 3
|
||||
#define MR_PING_BLK 0x10 // 4
|
||||
#define MR_SW_RESET 0x80 // 7
|
||||
|
||||
struct Socket
|
||||
{
|
||||
uint16_t transmitBase;
|
||||
uint16_t transmitSize;
|
||||
uint16_t receiveBase;
|
||||
uint16_t receiveSize;
|
||||
uint16_t registers;
|
||||
|
||||
uint16_t rx_wr;
|
||||
};
|
||||
|
||||
std::vector<uint8_t> memory;
|
||||
std::vector<Socket> sockets;
|
||||
uint8_t modeRegister = 0;
|
||||
uint16_t dataAddress = 0;
|
||||
|
||||
void initialise();
|
||||
|
||||
void write8(const size_t i, const uint8_t value)
|
||||
{
|
||||
Socket & socket = sockets[i];
|
||||
const uint16_t base = socket.receiveBase;
|
||||
const uint16_t address = base + socket.rx_wr;
|
||||
memory[address] = value;
|
||||
socket.rx_wr = (socket.rx_wr + 1) % socket.receiveSize;
|
||||
}
|
||||
|
||||
void write16(const size_t i, const uint16_t value)
|
||||
{
|
||||
write8(i, (value & 0xFF00) >> 8); // high
|
||||
write8(i, (value & 0x00FF) >> 0); // low
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t readNetworkWord(const uint16_t address)
|
||||
{
|
||||
const uint8_t high = memory[address];
|
||||
const uint8_t low = memory[address + 1];
|
||||
const uint16_t value = low + (high << 8);
|
||||
return value;
|
||||
}
|
||||
|
||||
void setSocketModeRegister(const size_t i, const uint16_t address, const uint8_t value)
|
||||
{
|
||||
memory[address] = value;
|
||||
const uint8_t protocol = value & 0x0F;
|
||||
switch (protocol)
|
||||
{
|
||||
case 0x00:
|
||||
std::cerr << "Mode[" << i << "]: Closed" << std::endl;
|
||||
break;
|
||||
case 0x03:
|
||||
std::cerr << "Mode[" << i << "]: IPRAW" << std::endl;
|
||||
break;
|
||||
case 0x04:
|
||||
std::cerr << "Mode[" << i << "]: MACRAW" << std::endl;
|
||||
break;
|
||||
#ifdef U2_UNKNOWN
|
||||
default:
|
||||
std::cerr << "Unknown protocol: ";
|
||||
as_hex(std::cerr, value, 2) << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void setTXSizes(const uint16_t address, uint8_t value)
|
||||
{
|
||||
memory[address] = value;
|
||||
uint16_t base = 0x4000;
|
||||
const uint16_t ceiling = base + 0x2000;
|
||||
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;
|
||||
|
||||
if (base > ceiling)
|
||||
{
|
||||
base = ceiling;
|
||||
}
|
||||
sockets[i].transmitSize = base - sockets[i].transmitBase;
|
||||
// std::cerr << "TX[" << i << "] = ";
|
||||
// as_hex(std::cerr, sockets[i].transmitSize, 4) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void setRXSizes(const uint16_t address, uint8_t value)
|
||||
{
|
||||
memory[address] = value;
|
||||
uint16_t base = 0x6000;
|
||||
const uint16_t ceiling = base + 0x2000;
|
||||
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;
|
||||
|
||||
if (base > ceiling)
|
||||
{
|
||||
base = ceiling;
|
||||
}
|
||||
sockets[i].receiveSize = base - sockets[i].receiveBase;
|
||||
// std::cerr << "RX[" << i << "] = ";
|
||||
// as_hex(std::cerr, sockets[i].receiveSize, 4) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t getTXDataSize(const size_t i)
|
||||
{
|
||||
const uint16_t size = sockets[i].transmitSize;
|
||||
const uint16_t mask = size - 1;
|
||||
|
||||
const int TX_RR = readNetworkWord(sockets[i].registers + 0x22) & mask;
|
||||
const int TX_WR = readNetworkWord(sockets[i].registers + 0x24) & mask;
|
||||
|
||||
int dataPresent = TX_WR - TX_RR;
|
||||
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;
|
||||
const uint8_t reg = (free >> shift) & 0xFF;
|
||||
return reg;
|
||||
}
|
||||
|
||||
uint16_t getRXDataSize(const size_t i)
|
||||
{
|
||||
const int size = sockets[i].receiveSize;
|
||||
const uint16_t mask = size - 1;
|
||||
|
||||
const int RX_RD = readNetworkWord(sockets[i].registers + 0x28) & mask;
|
||||
const int RX_WR = sockets[i].rx_wr & mask;
|
||||
int dataPresent = RX_WR - RX_RD;
|
||||
if (dataPresent < 0)
|
||||
{
|
||||
dataPresent += size;
|
||||
}
|
||||
return dataPresent;
|
||||
}
|
||||
|
||||
void updateRSR(const size_t i)
|
||||
{
|
||||
const Socket & socket = sockets[i];
|
||||
const uint16_t data = getRXDataSize(i);
|
||||
memory[socket.registers + 0x26] = (data >> 8) & 0xFF;
|
||||
memory[socket.registers + 0x27] = (data >> 0) & 0xFF;
|
||||
}
|
||||
|
||||
void receiveOnePacketMacRaw(const size_t i)
|
||||
{
|
||||
const uint16_t rxData = getRXDataSize(i);
|
||||
|
||||
BYTE buffer[MAX_RXLENGTH];
|
||||
int len = sizeof(buffer);
|
||||
if (tfeReceiveOnePacket(memory.data() + 0x0009, buffer, len))
|
||||
{
|
||||
const int size = sockets[i].receiveSize;
|
||||
if (rxData + len < size) // we do not want to fill the buffer.
|
||||
{
|
||||
writeData(i, buffer, len);
|
||||
updateRSR(i);
|
||||
std::cerr << "READ[" << i << "]: ";
|
||||
as_hex(std::cerr, len, 4) << " bytes" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ??? we just skip it
|
||||
std::cerr << "SKIP[" << i << "]: ";
|
||||
as_hex(std::cerr, len, 4) << " bytes" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void receiveOnePacket(const size_t i)
|
||||
{
|
||||
const Socket & socket = sockets[i];
|
||||
const uint8_t sr = memory[socket.registers + 0x03];
|
||||
switch (sr)
|
||||
{
|
||||
case 0x42:
|
||||
receiveOnePacketMacRaw(i);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void sendData(const size_t i)
|
||||
{
|
||||
const Socket & socket = sockets[i];
|
||||
const uint16_t size = socket.transmitSize;
|
||||
const uint16_t mask = size - 1;
|
||||
|
||||
const int TX_RR = readNetworkWord(socket.registers + 0x22);
|
||||
const int TX_WR = readNetworkWord(socket.registers + 0x24);
|
||||
|
||||
const uint16_t base = socket.transmitBase;
|
||||
const uint16_t rr_address = base + (TX_RR & mask);
|
||||
const uint16_t wr_address = base + (TX_WR & mask);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
memory[socket.registers + 0x22] = memory[socket.registers + 0x24];
|
||||
memory[socket.registers + 0x23] = memory[socket.registers + 0x25];
|
||||
|
||||
std::cerr << "SEND[" << i << "]: ";
|
||||
as_hex(std::cerr, data.size(), 4) << " bytes " << std::endl;
|
||||
tfeTransmitOnePacket(data.data(), data.size());
|
||||
}
|
||||
|
||||
void resetRXTXBuffers(const size_t i)
|
||||
{
|
||||
Socket & socket = sockets[i];
|
||||
socket.rx_wr = 0x00;
|
||||
memory[socket.registers + 0x22] = 0x00;
|
||||
memory[socket.registers + 0x23] = 0x00;
|
||||
memory[socket.registers + 0x24] = 0x00;
|
||||
memory[socket.registers + 0x25] = 0x00;
|
||||
memory[socket.registers + 0x28] = 0x00;
|
||||
memory[socket.registers + 0x29] = 0x00;
|
||||
updateRSR(i);
|
||||
}
|
||||
|
||||
void openSocket(const size_t i)
|
||||
{
|
||||
const Socket & socket = sockets[i];
|
||||
const uint8_t mr = memory[socket.registers + 0x00];
|
||||
const uint8_t protocol = mr & 0x0F;
|
||||
uint8_t & sr = memory[socket.registers + 0x03];
|
||||
switch (protocol)
|
||||
{
|
||||
case 0x03: // IPRAW
|
||||
sr = 0x32; // SOCK_IPRAW
|
||||
break;
|
||||
case 0x04: // MACRAW
|
||||
sr = 0x42; // SOCK_MACRAW
|
||||
break;
|
||||
#ifdef U2_UNKNOWN
|
||||
default:
|
||||
std::cerr << "OPEN: unknown mode: ";
|
||||
as_hex(std::cerr, mr, 2) << std::endl;
|
||||
#endif
|
||||
}
|
||||
resetRXTXBuffers(i);
|
||||
std::cerr << "OPEN[" << i << "] = ";
|
||||
as_hex(std::cerr, sr, 2) << std::endl;
|
||||
}
|
||||
|
||||
void closeSocket(const size_t i)
|
||||
{
|
||||
const Socket & socket = sockets[i];
|
||||
memory[socket.registers + 0x03] = 0x00; // SOCK_CLOSED
|
||||
std::cerr << "CLOSE[" << i << "]" << std::endl;
|
||||
}
|
||||
|
||||
void setCommandRegister(const size_t i, const uint8_t value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case 0x01: // OPEN
|
||||
openSocket(i);
|
||||
break;
|
||||
case 0x10: // CLOSE
|
||||
closeSocket(i);
|
||||
break;
|
||||
case 0x20: // SEND
|
||||
sendData(i);
|
||||
break;
|
||||
case 0x40: // RECV
|
||||
updateRSR(i);
|
||||
break;
|
||||
#ifdef U2_UNKNOWN
|
||||
default:
|
||||
std::cerr << "Unknown command: ";
|
||||
as_hex(std::cerr, value, 2) << std::endl;
|
||||
#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)
|
||||
{
|
||||
case 0x00: // Sn_MR
|
||||
case 0x01: // Sn_CR
|
||||
value = memory[address];
|
||||
break;
|
||||
case 0x20: // Sn_TX_FSR high
|
||||
value = getTXFreeSizeRegister(i, 8);
|
||||
break;
|
||||
case 0x21: // Sn_TX_FSR low
|
||||
value = getTXFreeSizeRegister(i, 0);
|
||||
break;
|
||||
case 0x22: // Sn_TX_RR
|
||||
case 0x23: // Sn_TX_RR
|
||||
value = memory[address];
|
||||
break;
|
||||
case 0x24: // Sn_TX_WR
|
||||
case 0x25: // Sn_TX_WR
|
||||
value = memory[address];
|
||||
break;
|
||||
case 0x26: // Sn_RX_RSR
|
||||
case 0x27: // Sn_RX_RSR
|
||||
updateRSR(i);
|
||||
value = memory[address];
|
||||
break;
|
||||
case 0x28: // Sn_RX_RD
|
||||
case 0x29: // Sn_RX_RD
|
||||
value = memory[address];
|
||||
break;
|
||||
default:
|
||||
#ifdef U2_UNKNOWN
|
||||
std::cerr << "Get unknown socket register: ";
|
||||
as_hex(std::cerr, address, 4) << std::endl;
|
||||
#endif
|
||||
value = memory[address];
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
uint8_t readValueAt(const uint16_t address)
|
||||
{
|
||||
uint8_t value;
|
||||
switch (address)
|
||||
{
|
||||
case 0x0000 ... 0x002F:
|
||||
value = memory[address];
|
||||
break;
|
||||
case 0x0400 ... 0x07FF:
|
||||
value = readSocketRegister(address);
|
||||
break;
|
||||
case 0x4000 ... 0x7FFF:
|
||||
value = memory[address];
|
||||
break;
|
||||
default:
|
||||
#ifdef U2_UNKNOWN
|
||||
std::cerr << "Read unknown location: ";
|
||||
as_hex(std::cerr, address, 4) << std::endl;
|
||||
#endif
|
||||
value = memory[address];
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void autoIncrement()
|
||||
{
|
||||
if (modeRegister & MR_AUTO_INC)
|
||||
{
|
||||
++dataAddress;
|
||||
switch (dataAddress)
|
||||
{
|
||||
case 0x8000:
|
||||
case 0x6000:
|
||||
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)
|
||||
{
|
||||
std::cerr << "IP PROTO[" << i << "] = ";
|
||||
as_hex(std::cerr, value, 2) << std::endl;
|
||||
}
|
||||
|
||||
void setIPTypeOfService(const size_t i, const uint8_t value)
|
||||
{
|
||||
std::cerr << "IP TOS[" << i << "] = ";
|
||||
as_hex(std::cerr, value, 2) << std::endl;
|
||||
}
|
||||
|
||||
void setIPTTL(const size_t i, const uint8_t value)
|
||||
{
|
||||
std::cerr << "IP TTL[" << i << "] = ";
|
||||
as_hex(std::cerr, value, 2) << std::endl;
|
||||
}
|
||||
|
||||
void writeSocketRegister(const uint16_t address, const uint8_t value)
|
||||
{
|
||||
const uint16_t i = (address >> (2 + 8 + 8));
|
||||
const uint16_t loc = address & 0xFF;
|
||||
switch (loc)
|
||||
{
|
||||
case 0x00:
|
||||
setSocketModeRegister(i, address, value);
|
||||
break;
|
||||
case 0x01:
|
||||
setCommandRegister(i, value);
|
||||
break;
|
||||
case 0x14:
|
||||
setIPProtocol(i, value);
|
||||
break;
|
||||
case 0x15:
|
||||
setIPTypeOfService(i, value);
|
||||
break;
|
||||
case 0x16:
|
||||
setIPTTL(i, value);
|
||||
break;
|
||||
case 0x24: // Sn_TX_WR
|
||||
// some code sets the absolute value of the address rather than the offset
|
||||
// is this correct?
|
||||
memory[address] = value % 0x40;
|
||||
break;
|
||||
case 0x25: // Sn_TX_WR
|
||||
memory[address] = value;
|
||||
break;
|
||||
case 0x28: // Sn_RX_RD
|
||||
// some code sets the absolute value of the address rather than the offset
|
||||
// is this correct?
|
||||
memory[address] = value % 0x60;
|
||||
break;
|
||||
case 0x29: // Sn_RX_RD
|
||||
memory[address] = value;
|
||||
break;
|
||||
#ifdef U2_UNKNOWN
|
||||
default:
|
||||
std::cerr << "Set unknown socket register: ";
|
||||
as_hex(std::cerr, address, 4) << std::endl;
|
||||
break;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
void setModeRegister(const uint16_t address, const uint8_t value)
|
||||
{
|
||||
modeRegister = value;
|
||||
if (modeRegister & MR_SW_RESET)
|
||||
{
|
||||
initialise();
|
||||
}
|
||||
memory[address] = value; // redundant
|
||||
}
|
||||
|
||||
void writeCommonRegister(const uint16_t address, const uint8_t value)
|
||||
{
|
||||
switch (address)
|
||||
{
|
||||
case 0x0000:
|
||||
setModeRegister(address, value);
|
||||
break;
|
||||
case 0x0009 ... 0x000e: // mac address
|
||||
memory[address] = value;
|
||||
break;
|
||||
case 0x001A:
|
||||
setRXSizes(address, value);
|
||||
break;
|
||||
case 0x001B:
|
||||
setTXSizes(address, value);
|
||||
break;
|
||||
#ifdef U2_UNKNOWN
|
||||
default:
|
||||
std::cerr << "Set unknown common register: ";
|
||||
as_hex(std::cerr, address, 4) << std::endl;
|
||||
break;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
void writeValueAt(const uint16_t address, const uint8_t value)
|
||||
{
|
||||
switch (address)
|
||||
{
|
||||
case 0x0000 ... 0x002F:
|
||||
writeCommonRegister(address, value);
|
||||
break;
|
||||
case 0x0400 ... 0x07FF:
|
||||
writeSocketRegister(address, value);
|
||||
break;
|
||||
case 0x4000 ... 0x7FFF:
|
||||
memory[address] = value;
|
||||
break;
|
||||
#ifdef U2_UNKNOWN
|
||||
default:
|
||||
std::cerr << "Write to an unknown location: ";
|
||||
as_hex(std::cerr, address, 4) << std::endl;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void writeValue(const uint8_t value)
|
||||
{
|
||||
writeValueAt(dataAddress, value);
|
||||
autoIncrement();
|
||||
}
|
||||
|
||||
void initialise()
|
||||
{
|
||||
std::cerr << "Init" << std::endl;
|
||||
modeRegister = 0;
|
||||
dataAddress = 0;
|
||||
sockets.resize(4);
|
||||
memory.clear();
|
||||
memory.resize(0x8000);
|
||||
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
sockets[i].registers = 0x0400 + (i << 8);
|
||||
}
|
||||
|
||||
memory[0x0017] = 0x07; // RTR
|
||||
memory[0x0018] = 0xD0; // RTR
|
||||
setRXSizes(0x001A, 0x55); // RMSR
|
||||
setTXSizes(0x001B, 0x55); // TMSR
|
||||
}
|
||||
|
||||
BYTE u2_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
|
||||
{
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
receiveOnePacket(i);
|
||||
}
|
||||
|
||||
BYTE res = write ? 0 : MemReadFloatingBus(nCycles);
|
||||
|
||||
const uint8_t loc = address & 0x0F;
|
||||
|
||||
if (write)
|
||||
{
|
||||
switch (loc)
|
||||
{
|
||||
case 4:
|
||||
setModeRegister(0x0000, value);
|
||||
break;
|
||||
case 5: // set high. do not accept >= 0x8000
|
||||
dataAddress = ((value & 0x7F) << 8) | (dataAddress & 0x00FF);
|
||||
break;
|
||||
case 6: // set low
|
||||
dataAddress = ((value & 0XFF) << 0) | (dataAddress & 0xFF00);
|
||||
break;
|
||||
case 7:
|
||||
writeValue(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (loc)
|
||||
{
|
||||
case 4:
|
||||
res = modeRegister;
|
||||
break;
|
||||
case 5:
|
||||
res = (dataAddress & 0xFF00) >> 8;
|
||||
break;
|
||||
case 6:
|
||||
res = (dataAddress & 0x00FF) >> 0;
|
||||
break;
|
||||
case 7:
|
||||
res = readValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char * mode = write ? "WRITE " : "READ ";
|
||||
|
||||
char c;
|
||||
switch (res)
|
||||
{
|
||||
case 'A'...'Z':
|
||||
case 'a'...'z':
|
||||
case '0'...'9':
|
||||
c = res;
|
||||
break;
|
||||
default:
|
||||
c = '.';
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef U2_VERBOSE
|
||||
std::cerr << std::hex << programcounter << ": ";
|
||||
std::cerr << mode << std::hex << address << " ";
|
||||
std::cerr << std::setfill('0') << std::setw(2) << std::hex << size_t(value) << " = ";
|
||||
std::cerr << std::setfill('0') << std::setw(2) << std::hex << size_t(res) << " " << c << std::endl;
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void registerUthernet2()
|
||||
{
|
||||
initialise();
|
||||
RegisterIoHandler(3, u2_C0, u2_C0, nullptr, nullptr, nullptr, nullptr);
|
||||
}
|
3
source/linux/uthernet2.h
Normal file
3
source/linux/uthernet2.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
// this register the IOCalls for Uthernet 2 on slot 3
|
||||
// if TFE is not enabled (or available) all operations will timeout
|
||||
void registerUthernet2();
|
Loading…
Add table
Reference in a new issue