mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 21:57:57 +03:00
463 lines
11 KiB
C++
463 lines
11 KiB
C++
#include "Iop_Speed.h"
|
|
#include "Iop_Intc.h"
|
|
#include "Iop_DmacChannel.h"
|
|
#include "Log.h"
|
|
#include <cassert>
|
|
#include <cstring>
|
|
|
|
#define LOG_NAME ("iop_speed")
|
|
|
|
using namespace Iop;
|
|
|
|
// clang-format off
|
|
const uint16 CSpeed::m_eepromData[] =
|
|
{
|
|
//MAC address
|
|
0x1122, 0x1122, 0x4466,
|
|
//Checksum (just the sum of words above)
|
|
0x66AA
|
|
};
|
|
// clang-format on
|
|
|
|
CSpeed::CSpeed(CIntc& intc)
|
|
: m_intc(intc)
|
|
{
|
|
}
|
|
|
|
void CSpeed::Reset()
|
|
{
|
|
m_pendingRx = false;
|
|
m_rxDelay = 0;
|
|
m_rxIndex = 0;
|
|
m_intrStat = 0;
|
|
m_intrMask = 0;
|
|
m_eepRomReadIndex = 0;
|
|
m_txBuffer.clear();
|
|
m_rxBuffer.clear();
|
|
m_rxFifoPtr = 0;
|
|
m_rxFrameCount = 0;
|
|
m_smapEmac3AddressHi = 0;
|
|
m_smapEmac3AddressLo = 0;
|
|
m_smapEmac3StaCtrl.f = 0;
|
|
memset(m_smapBdTx, 0, sizeof(m_smapBdTx));
|
|
memset(m_smapBdRx, 0, sizeof(m_smapBdRx));
|
|
}
|
|
|
|
void CSpeed::SetEthernetFrameTxHandler(const EthernetFrameTxHandler& ethernetFrameTxHandler)
|
|
{
|
|
m_ethernetFrameTxHandler = ethernetFrameTxHandler;
|
|
}
|
|
|
|
void CSpeed::RxEthernetFrame(const uint8* frameData, uint32 frameSize)
|
|
{
|
|
assert(!m_pendingRx);
|
|
|
|
m_rxBuffer.resize(frameSize);
|
|
memcpy(m_rxBuffer.data(), frameData, frameSize);
|
|
|
|
auto& bdRx = reinterpret_cast<SMAP_BD*>(m_smapBdRx)[m_rxIndex];
|
|
assert((bdRx.ctrlStat & SMAP_BD_RX_EMPTY) != 0);
|
|
bdRx.ctrlStat &= ~SMAP_BD_RX_EMPTY;
|
|
bdRx.length = frameSize;
|
|
bdRx.pointer = 0;
|
|
|
|
m_rxIndex++;
|
|
m_rxIndex %= SMAP_BD_SIZE;
|
|
|
|
m_pendingRx = true;
|
|
m_rxDelay = 100000;
|
|
}
|
|
|
|
void CSpeed::CheckInterrupts()
|
|
{
|
|
if(m_intrStat & m_intrMask)
|
|
{
|
|
m_intc.AssertLine(CIntc::LINE_DEV9);
|
|
}
|
|
}
|
|
|
|
void CSpeed::ProcessEmac3StaCtrl()
|
|
{
|
|
auto staCtrl = make_convertible<SMAP_EMAC3_STA_CTRL>(m_smapEmac3StaCtrl.f);
|
|
//phyAddr:
|
|
//1: SMAP_DsPHYTER_ADDRESS
|
|
//phyRegAddr:
|
|
//0: SMAP_DsPHYTER_BMCR
|
|
//1: SMAP_DsPHYTER_BMSR
|
|
//4: SMAP_DsPHYTER_ANAR
|
|
//BMCR bits
|
|
//15: SMAP_PHY_BMCR_RST
|
|
//12: SMAP_PHY_BMCR_ANEN //Enable auto-nego
|
|
//9 : SMAP_PHY_BMCR_RSAN //Restart auto-nego
|
|
//BSMR bits
|
|
//2: SMAP_PHY_BMSR_LINK
|
|
//5: SMAP_PHY_BMSR_ANCP (Auto-Nego Complete)
|
|
switch(staCtrl.phyStaCmd)
|
|
{
|
|
case 0:
|
|
break;
|
|
case SMAP_EMAC3_STA_CMD_READ:
|
|
CLog::GetInstance().Print(LOG_NAME, "SMAP_PHY: Reading reg 0x%02X.\r\n", staCtrl.phyRegAddr);
|
|
assert(staCtrl.phyAddr == 1);
|
|
switch(staCtrl.phyRegAddr)
|
|
{
|
|
case 0:
|
|
staCtrl.phyData = 0;
|
|
break;
|
|
case 1:
|
|
staCtrl.phyData = (1 << 2) | (1 << 5);
|
|
break;
|
|
case 4:
|
|
staCtrl.phyData = 0;
|
|
break;
|
|
default:
|
|
//assert(false);
|
|
break;
|
|
}
|
|
staCtrl.phyOpComp = 1;
|
|
break;
|
|
case SMAP_EMAC3_STA_CMD_WRITE:
|
|
CLog::GetInstance().Print(LOG_NAME, "SMAP_PHY: Writing 0x%04X to reg 0x%02X.\r\n", staCtrl.phyData, staCtrl.phyRegAddr);
|
|
assert(staCtrl.phyAddr == 1);
|
|
//assert(staCtrl.phyRegAddr == 0);
|
|
staCtrl.phyOpComp = 1;
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
m_smapEmac3StaCtrl.f = staCtrl;
|
|
}
|
|
|
|
void CSpeed::HandleTx()
|
|
{
|
|
for(uint32 i = 0; i < SMAP_BD_COUNT; i++)
|
|
{
|
|
auto& bdTx = reinterpret_cast<SMAP_BD*>(m_smapBdTx)[i];
|
|
if(bdTx.ctrlStat & SMAP_BD_TX_READY)
|
|
{
|
|
//Is this always 0x1000?
|
|
static const uint32 bdTxBase = 0x1000;
|
|
assert(bdTx.pointer >= bdTxBase);
|
|
if(m_ethernetFrameTxHandler)
|
|
{
|
|
m_ethernetFrameTxHandler(m_txBuffer.data() + bdTx.pointer - bdTxBase, bdTx.length);
|
|
}
|
|
bdTx.ctrlStat &= ~SMAP_BD_TX_READY;
|
|
}
|
|
}
|
|
m_txBuffer.clear();
|
|
m_intrStat |= (1 << INTR_SMAP_TXDNV) | (1 << INTR_SMAP_TXEND) | (1 << INTR_SMAP_RXEND);
|
|
CheckInterrupts();
|
|
}
|
|
|
|
uint32 CSpeed::ReadRegister(uint32 address)
|
|
{
|
|
uint32 result = 0;
|
|
switch(address)
|
|
{
|
|
case REG_REV1:
|
|
//SMAP driver checks this
|
|
result = 17;
|
|
break;
|
|
case REG_REV3:
|
|
result = SPEED_CAPS_SMAP;
|
|
break;
|
|
case REG_INTR_STAT:
|
|
result = m_intrStat;
|
|
break;
|
|
case REG_INTR_MASK:
|
|
result = m_intrMask;
|
|
break;
|
|
case REG_PIO_DATA:
|
|
{
|
|
assert(m_eepRomReadIndex < ((m_eepRomDataSize * 16) + 1));
|
|
if(m_eepRomReadIndex == 0)
|
|
{
|
|
result = 0;
|
|
}
|
|
else
|
|
{
|
|
assert(m_eepRomReadIndex >= 1);
|
|
uint32 wordIndex = (m_eepRomReadIndex - 1) / 16;
|
|
uint32 wordBit = 15 - ((m_eepRomReadIndex - 1) % 16);
|
|
result = (m_eepromData[wordIndex] & (1 << wordBit)) ? 0x10 : 0;
|
|
}
|
|
m_eepRomReadIndex++;
|
|
}
|
|
break;
|
|
case REG_SMAP_RXFIFO_FRAME_CNT:
|
|
result = m_rxFrameCount;
|
|
break;
|
|
case REG_SMAP_RXFIFO_DATA:
|
|
{
|
|
result =
|
|
(m_rxBuffer[m_rxFifoPtr + 0] << 0) |
|
|
(m_rxBuffer[m_rxFifoPtr + 1] << 8) |
|
|
(m_rxBuffer[m_rxFifoPtr + 2] << 16) |
|
|
(m_rxBuffer[m_rxFifoPtr + 3] << 24);
|
|
m_rxFifoPtr += 4;
|
|
}
|
|
break;
|
|
case REG_SMAP_EMAC3_ADDR_HI:
|
|
result = m_smapEmac3AddressHi;
|
|
break;
|
|
case REG_SMAP_EMAC3_ADDR_LO:
|
|
result = m_smapEmac3AddressLo;
|
|
break;
|
|
case REG_SMAP_EMAC3_STA_CTRL_HI:
|
|
result = m_smapEmac3StaCtrl.h1 | (m_smapEmac3StaCtrl.h0 << 16);
|
|
break;
|
|
case REG_SMAP_EMAC3_STA_CTRL_LO:
|
|
result = m_smapEmac3StaCtrl.h0;
|
|
break;
|
|
}
|
|
|
|
if((address >= REG_SMAP_BD_TX_BASE) && (address < (REG_SMAP_BD_TX_BASE + SMAP_BD_SIZE)))
|
|
{
|
|
uint32 regOffset = address - REG_SMAP_BD_TX_BASE;
|
|
assert(regOffset < SMAP_BD_SIZE);
|
|
result = *reinterpret_cast<uint16*>(m_smapBdTx + regOffset);
|
|
}
|
|
else if((address >= REG_SMAP_BD_RX_BASE) && (address < (REG_SMAP_BD_RX_BASE + SMAP_BD_SIZE)))
|
|
{
|
|
uint32 regOffset = address - REG_SMAP_BD_RX_BASE;
|
|
assert(regOffset < SMAP_BD_SIZE);
|
|
result = *reinterpret_cast<uint16*>(m_smapBdRx + regOffset);
|
|
}
|
|
|
|
LogRead(address);
|
|
return result;
|
|
}
|
|
|
|
void CSpeed::WriteRegister(uint32 address, uint32 value)
|
|
{
|
|
switch(address)
|
|
{
|
|
case REG_INTR_MASK:
|
|
m_intrMask = value;
|
|
CheckInterrupts();
|
|
break;
|
|
case REG_PIO_DIR:
|
|
if(value == 0xE1)
|
|
{
|
|
//Reset reading process
|
|
m_eepRomReadIndex = 0;
|
|
}
|
|
break;
|
|
case REG_SMAP_INTR_CLR:
|
|
m_intrStat &= ~value;
|
|
break;
|
|
case REG_SMAP_RXFIFO_RD_PTR:
|
|
m_rxFifoPtr = value;
|
|
break;
|
|
case REG_SMAP_RXFIFO_FRAME_DEC:
|
|
assert(m_rxFrameCount != 0);
|
|
m_rxFrameCount--;
|
|
break;
|
|
case REG_SMAP_TXFIFO_DATA:
|
|
{
|
|
m_txBuffer.push_back(static_cast<uint8>(value >> 0));
|
|
m_txBuffer.push_back(static_cast<uint8>(value >> 8));
|
|
m_txBuffer.push_back(static_cast<uint8>(value >> 16));
|
|
m_txBuffer.push_back(static_cast<uint8>(value >> 24));
|
|
}
|
|
break;
|
|
case REG_SMAP_EMAC3_TXMODE0_HI:
|
|
if(value & 0x8000)
|
|
{
|
|
//Ready to send some stuff (wrote SMAP_E3_TX_GNP_0 bit)
|
|
HandleTx();
|
|
}
|
|
break;
|
|
case REG_SMAP_EMAC3_ADDR_HI:
|
|
m_smapEmac3AddressHi = value;
|
|
break;
|
|
case REG_SMAP_EMAC3_ADDR_LO:
|
|
m_smapEmac3AddressLo = value;
|
|
break;
|
|
case REG_SMAP_EMAC3_STA_CTRL_HI:
|
|
m_smapEmac3StaCtrl.h1 = static_cast<uint16>(value);
|
|
m_smapEmac3StaCtrl.h0 = static_cast<uint16>(value >> 16);
|
|
ProcessEmac3StaCtrl();
|
|
break;
|
|
case REG_SMAP_EMAC3_STA_CTRL_LO:
|
|
m_smapEmac3StaCtrl.h0 = static_cast<uint16>(value);
|
|
ProcessEmac3StaCtrl();
|
|
break;
|
|
}
|
|
|
|
if((address >= REG_SMAP_BD_TX_BASE) && (address < (REG_SMAP_BD_TX_BASE + SMAP_BD_SIZE)))
|
|
{
|
|
uint32 regOffset = address - REG_SMAP_BD_TX_BASE;
|
|
assert(regOffset < SMAP_BD_SIZE);
|
|
*reinterpret_cast<uint16*>(m_smapBdTx + regOffset) = static_cast<uint16>(value);
|
|
}
|
|
else if((address >= REG_SMAP_BD_RX_BASE) && (address < (REG_SMAP_BD_RX_BASE + SMAP_BD_SIZE)))
|
|
{
|
|
uint32 regOffset = address - REG_SMAP_BD_RX_BASE;
|
|
assert(regOffset < SMAP_BD_SIZE);
|
|
*reinterpret_cast<uint16*>(m_smapBdRx + regOffset) = static_cast<uint16>(value);
|
|
}
|
|
|
|
LogWrite(address, value);
|
|
}
|
|
|
|
uint32 CSpeed::ReceiveDma(uint8* buffer, uint32 blockSize, uint32 blockAmount, uint32 direction)
|
|
{
|
|
if(direction == Iop::Dmac::CChannel::CHCR_DR_TO)
|
|
{
|
|
uint32 size = blockSize * blockAmount;
|
|
memcpy(buffer, m_rxBuffer.data() + m_rxFifoPtr, size);
|
|
m_rxFifoPtr += size;
|
|
}
|
|
else
|
|
{
|
|
m_txBuffer.insert(std::end(m_txBuffer), buffer, buffer + blockSize * blockAmount);
|
|
}
|
|
return blockAmount;
|
|
}
|
|
|
|
void CSpeed::CountTicks(uint32 ticks)
|
|
{
|
|
if(m_pendingRx)
|
|
{
|
|
m_rxDelay -= ticks;
|
|
if(m_rxDelay <= 0)
|
|
{
|
|
m_intrStat |= (1 << INTR_SMAP_RXEND);
|
|
CheckInterrupts();
|
|
m_pendingRx = false;
|
|
m_rxFrameCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSpeed::LogRead(uint32 address)
|
|
{
|
|
#define LOG_GET(registerId) \
|
|
case registerId: \
|
|
CLog::GetInstance().Print(LOG_NAME, "= " #registerId "\r\n"); \
|
|
break;
|
|
|
|
if((address >= REG_SMAP_BD_TX_BASE) && (address < (REG_SMAP_BD_TX_BASE + SMAP_BD_SIZE)))
|
|
{
|
|
LogBdRead("REG_SMAP_BD_TX", REG_SMAP_BD_TX_BASE, address);
|
|
return;
|
|
}
|
|
|
|
if((address >= REG_SMAP_BD_RX_BASE) && (address < (REG_SMAP_BD_RX_BASE + SMAP_BD_SIZE)))
|
|
{
|
|
LogBdRead("REG_SMAP_BD_RX", REG_SMAP_BD_RX_BASE, address);
|
|
return;
|
|
}
|
|
|
|
switch(address)
|
|
{
|
|
LOG_GET(REG_REV1)
|
|
LOG_GET(REG_REV3)
|
|
LOG_GET(REG_INTR_STAT)
|
|
LOG_GET(REG_INTR_MASK)
|
|
LOG_GET(REG_PIO_DATA)
|
|
LOG_GET(REG_SMAP_RXFIFO_FRAME_CNT)
|
|
LOG_GET(REG_SMAP_RXFIFO_DATA)
|
|
LOG_GET(REG_SMAP_EMAC3_TXMODE0_HI)
|
|
LOG_GET(REG_SMAP_EMAC3_TXMODE0_LO)
|
|
LOG_GET(REG_SMAP_EMAC3_ADDR_HI)
|
|
LOG_GET(REG_SMAP_EMAC3_ADDR_LO)
|
|
LOG_GET(REG_SMAP_EMAC3_STA_CTRL_HI)
|
|
LOG_GET(REG_SMAP_EMAC3_STA_CTRL_LO)
|
|
|
|
default:
|
|
CLog::GetInstance().Warn(LOG_NAME, "Read an unknown register 0x%08X.\r\n", address);
|
|
break;
|
|
}
|
|
#undef LOG_GET
|
|
}
|
|
|
|
void CSpeed::LogWrite(uint32 address, uint32 value)
|
|
{
|
|
#define LOG_SET(registerId) \
|
|
case registerId: \
|
|
CLog::GetInstance().Print(LOG_NAME, #registerId " = 0x%08X\r\n", value); \
|
|
break;
|
|
|
|
if((address >= REG_SMAP_BD_TX_BASE) && (address < (REG_SMAP_BD_TX_BASE + SMAP_BD_SIZE)))
|
|
{
|
|
LogBdWrite("REG_SMAP_BD_TX", REG_SMAP_BD_TX_BASE, address, value);
|
|
return;
|
|
}
|
|
|
|
if((address >= REG_SMAP_BD_RX_BASE) && (address < (REG_SMAP_BD_RX_BASE + SMAP_BD_SIZE)))
|
|
{
|
|
LogBdWrite("REG_SMAP_BD_RX", REG_SMAP_BD_RX_BASE, address, value);
|
|
return;
|
|
}
|
|
|
|
switch(address)
|
|
{
|
|
LOG_SET(REG_DMA_CTRL)
|
|
LOG_SET(REG_INTR_STAT)
|
|
LOG_SET(REG_INTR_MASK)
|
|
LOG_SET(REG_PIO_DIR)
|
|
LOG_SET(REG_PIO_DATA)
|
|
LOG_SET(REG_SMAP_INTR_CLR)
|
|
LOG_SET(REG_SMAP_TXFIFO_FRAME_INC)
|
|
LOG_SET(REG_SMAP_RXFIFO_RD_PTR)
|
|
LOG_SET(REG_SMAP_RXFIFO_FRAME_DEC)
|
|
LOG_SET(REG_SMAP_TXFIFO_DATA)
|
|
LOG_SET(REG_SMAP_EMAC3_TXMODE0_HI)
|
|
LOG_SET(REG_SMAP_EMAC3_TXMODE0_LO)
|
|
LOG_SET(REG_SMAP_EMAC3_ADDR_HI)
|
|
LOG_SET(REG_SMAP_EMAC3_ADDR_LO)
|
|
LOG_SET(REG_SMAP_EMAC3_STA_CTRL_HI)
|
|
LOG_SET(REG_SMAP_EMAC3_STA_CTRL_LO)
|
|
|
|
default:
|
|
CLog::GetInstance().Warn(LOG_NAME, "Wrote 0x%08X to an unknown register 0x%08X.\r\n", value, address);
|
|
break;
|
|
}
|
|
#undef LOG_SET
|
|
}
|
|
|
|
void CSpeed::LogBdRead(const char* name, uint32 base, uint32 address)
|
|
{
|
|
uint32 regIndex = address & 0x7;
|
|
uint32 structIndex = (address - base) / 8;
|
|
switch(regIndex)
|
|
{
|
|
case 0:
|
|
CLog::GetInstance().Print(LOG_NAME, "= %s[%d].CTRLSTAT\r\n", name, structIndex);
|
|
break;
|
|
case 2:
|
|
CLog::GetInstance().Print(LOG_NAME, "= %s[%d].RESERVED\r\n", name, structIndex);
|
|
break;
|
|
case 4:
|
|
CLog::GetInstance().Print(LOG_NAME, "= %s[%d].LENGTH\r\n", name, structIndex);
|
|
break;
|
|
case 6:
|
|
CLog::GetInstance().Print(LOG_NAME, "= %s[%d].POINTER\r\n", name, structIndex);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CSpeed::LogBdWrite(const char* name, uint32 base, uint32 address, uint32 value)
|
|
{
|
|
uint32 regIndex = address & 0x7;
|
|
uint32 structIndex = (address - base) / 8;
|
|
switch(regIndex)
|
|
{
|
|
case 0:
|
|
CLog::GetInstance().Print(LOG_NAME, "%s[%d].CTRLSTAT = 0x%08X\r\n", name, structIndex, value);
|
|
break;
|
|
case 2:
|
|
CLog::GetInstance().Print(LOG_NAME, "%s[%d].RESERVED = 0x%08X\r\n", name, structIndex, value);
|
|
break;
|
|
case 4:
|
|
CLog::GetInstance().Print(LOG_NAME, "%s[%d].LENGTH = 0x%08X\r\n", name, structIndex, value);
|
|
break;
|
|
case 6:
|
|
CLog::GetInstance().Print(LOG_NAME, "%s[%d].POINTER = 0x%08X\r\n", name, structIndex, value);
|
|
break;
|
|
}
|
|
}
|