diff --git a/Source/Core/Core/Src/HW/EXI.cpp b/Source/Core/Core/Src/HW/EXI.cpp index b50e9f0a1c..e660e19491 100644 --- a/Source/Core/Core/Src/HW/EXI.cpp +++ b/Source/Core/Core/Src/HW/EXI.cpp @@ -44,9 +44,7 @@ void Init() g_Channels[0].AddDevice(EXIDEVICE_MEMORYCARD_A, 0); g_Channels[0].AddDevice(EXIDEVICE_IPL, 1); g_Channels[1].AddDevice(EXIDEVICE_MEMORYCARD_B, 0); - #if 0 g_Channels[0].AddDevice(EXIDEVICE_ETH, 2); - #endif //g_Channels[1].AddDevice(EXIDEVICE_MIC, 0); g_Channels[2].AddDevice(EXIDEVICE_AD16, 0); } diff --git a/Source/Core/Core/Src/HW/EXI_Device.cpp b/Source/Core/Core/Src/HW/EXI_Device.cpp index 968c1d5b4c..4fa4b5f1cc 100644 --- a/Source/Core/Core/Src/HW/EXI_Device.cpp +++ b/Source/Core/Core/Src/HW/EXI_Device.cpp @@ -22,9 +22,7 @@ #include "EXI_DeviceMemoryCard.h" #include "EXI_DeviceAD16.h" #include "EXI_DeviceMic.h" -#if 0 #include "EXI_DeviceEthernet.h" -#endif #include "../Core.h" @@ -153,9 +151,7 @@ IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice) break; case EXIDEVICE_ETH: - #if 0 return new CEXIETHERNET(); - #endif break; } diff --git a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp index 395091df95..2920b31c02 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp +++ b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.cpp @@ -28,10 +28,17 @@ enum { unsigned int Expecting; CEXIETHERNET::CEXIETHERNET() : m_uPosition(0), - m_uCommand(0) + m_uCommand(0), + mWriteBuffer(2000) { ID = 0x04020200; + mWriteP = INVALID_P; + mReadP = INVALID_P; + + mExpectSpecialImmRead = false; + Expecting = EXPECT_NONE; + mExpectVariableLengthImmWrite = false; } void CEXIETHERNET::SetCS(int cs) @@ -45,7 +52,7 @@ void CEXIETHERNET::SetCS(int cs) bool CEXIETHERNET::IsPresent() { - return true; + return false; } void CEXIETHERNET::Update() @@ -56,63 +63,225 @@ bool CEXIETHERNET::IsInterruptSet() { return false; } - -void CEXIETHERNET::Transfer(u8& _byte) -{ - //printf("%x %x POS: %d\n", _byte, m_uCommand, m_uPosition); - //printf("%x %x \n", _byte, m_uCommand); - if (m_uPosition == 0) - { - m_uCommand = _byte; - } - else - { - switch(m_uCommand) - { - case CMD_ID: // ID - if (m_uPosition != 1) - _byte = (u8)(ID >> (24-(((m_uPosition-2) & 3) * 8))); - break; - case CMD_READ_REG: // Read from Register - // Size is 2 - // Todo, Actually read it - break; - default: - printf("Unknown CMD 0x%x\n", m_uCommand); - exit(0); - break; - - } - } - m_uPosition++; -} bool isActivated() { // Todo: Return actual check return true; } +inline u8 makemaskb(int start, int end) { + return (u8)_rotl((2 << (end - start)) - 1, 7 - end); +} +inline u32 makemaskh(int start, int end) { + return (u32)_rotl((2 << (end - start)) - 1, 15 - end); +} +inline u32 makemaskw(int start, int end) { + return _rotl((2 << (end - start)) - 1, 31 - end); +} +inline u8 getbitsb(u8 byte, int start, int end) { + return (byte & makemaskb(start, end)) >> u8(7 - end); +} +inline u32 getbitsh(u32 hword, int start, int end) { + return (hword & makemaskh(start, end)) >> u32(15 - end); +} +inline u32 getbitsw(u32 dword, int start, int end) { + return (dword & makemaskw(start, end)) >> (31 - end); +} + void CEXIETHERNET::ImmWrite(u32 _uData, u32 _uSize) { printf("IMM Write, size 0x%x, data 0x%x\n", _uSize, _uData); - while (_uSize--) + if(mExpectVariableLengthImmWrite) { - u8 uByte = _uData >> 24; - this->Transfer(uByte); - _uData <<= 8; + printf("Not doing expecting variable length imm write!\n"); + exit(0); } + else if(mWriteP != INVALID_P) + { + if(mWriteP + _uSize > BBAMEM_SIZE) + { + printf("Write error: mWriteP + size = 0x%04X + %i\n", mWriteP, _uSize); + exit(0); + } + //BBADEGUB("Write to BBA address 0x%0*X, %i byte%s: 0x%0*X\n",mWriteP >= CB_OFFSET ? 4 : 2, mWriteP, size, (size==1?"":"s"), size*2, data); + + switch(mWriteP) + { + case 0x09: + printf("mWriteP is %x\n", mWriteP); + exit(0); + //BBADEGUB("BBA Interrupt reset 0x%02X & ~(0x%02X) => 0x%02X\n", mBbaMem[0x09], MAKE(BYTE, data), mBbaMem[0x09] & ~MAKE(BYTE, data)); + //MYASSERT(_uSize == 1); + //mBbaMem[0x09] &= ~MAKE(BYTE, data); + break; + case BBA_NCRA: + printf("mWriteP is %x\n", mWriteP); + exit(0); + /*#define RISE(flags) ((data & (flags)) && !(mBbaMem[0x00] & (flags))) + if(RISE(BBA_NCRA_RESET)) + { + printf("BBA Reset\n"); + } + if(RISE(BBA_NCRA_SR) && isActivated()) + { + BBADEGUB("BBA Start Recieve\n"); + HWGLE(startRecv()); + } + if(RISE(BBA_NCRA_ST1)) + { + BBADEGUB("BBA Start Transmit\n"); + if(!mReadyToSend) + throw hardware_fatal_exception("BBA Transmit without a packet!"); + HWGLE(sendPacket(mWriteBuffer.p(), mWriteBuffer.size())); + mReadyToSend = false; + } + mBbaMem[0x00] = MAKE(BYTE, data);*/ + break; + case BBA_NWAYC: + printf("mWriteP is %x\n", mWriteP); + exit(0); + /*if(data & (BBA_NWAYC_ANE | BBA_NWAYC_ANS_RA)) + { + HWGLE(activate()); + //say we've successfully negotiated for 10 Mbit full duplex + //should placate libogc + mBbaMem[BBA_NWAYS] = BBA_NWAYS_LS10 | BBA_NWAYS_LPNWAY | + BBA_NWAYS_ANCLPT | BBA_NWAYS_10TXF; + }*/ + break; + case 0x18: //RRP - Receive Buffer Read Page Pointer + printf("mWriteP is %x\n", mWriteP); + exit(0); + /*MYASSERT(size == 2 || size == 1); + mRBRPP = (BYTE)data << 8; //I hope this works with both write sizes. + mRBEmpty = mRBRPP == ((WORD)mCbw.p_write() + CB_OFFSET); + HWGLE(checkRecvBuffer());*/ + break; + case 0x16: //RWP + printf("mWriteP is %x\n", mWriteP); + exit(0); + /*MYASSERT(size == 2 || size == 1); + MYASSERT(data == DWORD((WORD)mCbw.p_write() + CB_OFFSET) >> 8);*/ + break; + default: + printf("Default one!\n"); + memcpy(mBbaMem + mWriteP, &_uData, _uSize); + mWriteP = mWriteP + _uSize; + } + return; + }else if(_uSize == 2 && _uData == 0) + { + // Device ID Request + mSpecialImmData = EXI_DEVTYPE_ETHER; + mExpectSpecialImmRead = true; + return; + } + else if((_uSize == 4 && (_uData & 0xC0000000) == 0xC0000000) || (_uSize == 2 && (_uData & 0x4000) == 0x4000)) + { // Write to BBA Register + printf("Write to BBA register!\n"); + if(_uSize == 4) + mWriteP = (u8)getbitsw(_uData, 16, 23); + else //size == 2 + mWriteP = (u8)getbitsw(_uData & ~0x4000, 16, 23); //Dunno about this... + if(mWriteP == 0x48) + { + mWriteBuffer.clear(); + mExpectVariableLengthImmWrite = true; + printf("Prepared for variable length write to address 0x48\n"); + } + else + { + //BBADEGUB("BBA Write pointer set to 0x%0*X\n", size, mWriteP); + } + return; + } + else if((_uSize == 4 && (_uData & 0xC0000000) == 0x80000000) || (_uSize == 2 && (_uData & 0x4000) == 0x0000)) + { + printf("Read from BBA register!\n"); + // Read from BBA Register! + if(_uSize == 4) + { + //Holy Fuck that's crazy + mReadP = (u32)getbitsw(_uData, 8, 23); + if(mReadP >= BBAMEM_SIZE) + { + printf("Illegal BBA address: 0x%04X\n", mReadP); + //if(g::bouehr) + exit(0); + //return EXI_UNHANDLED; + } + } + else + { //size == 2 + mReadP = (u8)getbitsw(_uData, 16, 23); + } + switch(mReadP) + { + case 0x20: //MAC address + printf("Mac Address!\n"); + exit(0); + //memcpy(mBbaMem + mReadP, g::mac_address, 6); + break; + case 0x01: //Revision ID + break; + case 0x16: //RWP - Receive Buffer Write Page Pointer + printf("RWP!\n"); + exit(0); + //MAKE(WORD, mBbaMem[mReadP]) = ((WORD)mCbw.p_write() + CB_OFFSET) >> 8; + break; + case 0x18: //RRP - Receive Buffer Read Page Pointer + printf("RRP!\n"); + exit(0); + //MAKE(WORD, mBbaMem[mReadP]) = (mRBRPP) >> 8; + break; + case 0x3A: //bit 1 set if no data available + printf("Bit 1 set!\n"); + exit(0); + //mBbaMem[mReadP] = !mRBEmpty; + break; + case 0x00: + //mBbaMem[mReadP] = 0x00; + //if(!sendInProgress()) + mBbaMem[mReadP] &= ~(0x06); + break; + case 0x03: + mBbaMem[mReadP] = 0x80; + break; + } + //BBADEGUB("BBA Read pointer set to 0x%0*X\n", size, mReadP); + return; + } + printf("Not expecting ImmWrite of size %d\n", _uSize); + exit(0); } u32 CEXIETHERNET::ImmRead(u32 _uSize) { - u32 uResult = 0; - u32 uPosition = 0; printf("IMM Read, size 0x%x\n", _uSize); - while (_uSize--) - { - u8 uByte = 0; - this->Transfer(uByte); - uResult |= uByte << (24-(uPosition++ * 8)); + if(mExpectSpecialImmRead) { + printf("special IMMRead\n"); + mExpectSpecialImmRead = false; + return mSpecialImmData; } - return uResult; + if(mReadP != INVALID_P) + { + if(mReadP + _uSize > BBAMEM_SIZE) + { + printf("Read error: mReadP + size = 0x%04X + %i\n", mReadP, _uSize); + exit(0); + } + u32 uResult = 0; + memcpy(&uResult, mBbaMem + mReadP, _uSize); + // We do as well? + //data = swapw(data); //we have a byteswap problem... + printf("Read from BBA address 0x%0*X, %i byte%s: 0x%0*X\n",mReadP >= CB_OFFSET ? 4 : 2, mReadP, _uSize, (_uSize==1?"":"s"),_uSize*2, getbitsw(uResult, 0, _uSize * 8 - 1)); + mReadP = mReadP + _uSize; + return uResult; + } + else + { + printf("Unhandled IMM read of %d bytes\n", _uSize); + } + printf("Not Expecting IMMRead of size %d!\n", _uSize); + exit(0); } void CEXIETHERNET::DMAWrite(u32 _uAddr, u32 _uSize) diff --git a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h index c92b6cc028..5c89d7d3cf 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h +++ b/Source/Core/Core/Src/HW/EXI_DeviceEthernet.h @@ -18,6 +18,32 @@ #ifndef _EXIDEVICE_ETHERNET_H #define _EXIDEVICE_ETHERNET_H +class WriteBuffer { +public: + WriteBuffer(u32 s) :_size(0) { _buffer = (u8*)malloc(s*sizeof(u8)); ucapacity = s;} + ~WriteBuffer() { free(_buffer);} + u32 size() const { return _size; } + u32 capacity() const { return ucapacity; } + void write(u32 s, const void *src) { + if(_size + s >= ucapacity) + { + printf("Write too large!"); + exit(0); + } + + memcpy(_buffer + _size, src, s); + _size = _size + s; + } + void clear() { + _size = 0; + } + u8* const p() { return _buffer; } +private: + u8* _buffer; + u32 ucapacity; + u32 _size; +}; + class CEXIETHERNET : public IEXIDevice { public: @@ -35,6 +61,19 @@ private: // STATE_TO_SAVE u32 m_uPosition; u32 m_uCommand; + + u32 mWriteP, mReadP; + #define INVALID_P 0xFFFF + + bool mExpectSpecialImmRead; //reset to false on deselect + u32 mSpecialImmData; + + #define BBAMEM_SIZE 0x1000 + u8 mBbaMem[BBAMEM_SIZE]; + + WriteBuffer mWriteBuffer; + + bool mExpectVariableLengthImmWrite; bool mReadyToSend; unsigned int ID; u8 RegisterBlock[0x1000]; @@ -43,6 +82,47 @@ private: CMD_READ_REG = 0x01, }; - void Transfer(u8& _uByte); }; +#define CB_OFFSET 0x100 +#define CB_SIZE (BBAMEM_SIZE - CB_OFFSET) +#define SIZEOF_RECV_DESCRIPTOR 4 + +#define EXI_DEVTYPE_ETHER 0x04020200 +#define BBA_NCRA 0x00 /* Network Control Register A, RW */ +#define BBA_NCRA_RESET (1<<0) /* RESET */ +#define BBA_NCRA_ST0 (1<<1) /* ST0, Start transmit command/status */ +#define BBA_NCRA_ST1 (1<<2) /* ST1, " */ +#define BBA_NCRA_SR (1<<3) /* SR, Start Receive */ + +#define BBA_NCRB 0x01 /* Network Control Register B, RW */ +#define BBA_NCRB_PR (1<<0) /* PR, Promiscuous Mode */ +#define BBA_NCRB_CA (1<<1) /* CA, Capture Effect Mode */ +#define BBA_NCRB_PM (1<<2) /* PM, Pass Multicast */ +#define BBA_NCRB_PB (1<<3) /* PB, Pass Bad Frame */ +#define BBA_NCRB_AB (1<<4) /* AB, Accept Broadcast */ +#define BBA_NCRB_HBD (1<<5) /* HBD, reserved */ +#define BBA_NCRB_RXINTC0 (1<<6) /* RXINTC, Receive Interrupt Counter */ +#define BBA_NCRB_RXINTC1 (1<<7) /* " */ +#define BBA_NCRB_1_PACKET_PER_INT (0<<6) /* 0 0 */ +#define BBA_NCRB_2_PACKETS_PER_INT (1<<6) /* 0 1 */ +#define BBA_NCRB_4_PACKETS_PER_INT (2<<6) /* 1 0 */ +#define BBA_NCRB_8_PACKETS_PER_INT (3<<6) /* 1 1 */ + +#define BBA_NWAYC 0x30 /* NWAY Configuration Register, RW, 84h */ +#define BBA_NWAYC_FD (1<<0) /* FD, Full Duplex Mode */ +#define BBA_NWAYC_PS100 (1<<1) /* PS100/10, Port Select 100/10 */ +#define BBA_NWAYC_ANE (1<<2) /* ANE, Autonegotiation Enable */ +#define BBA_NWAYC_ANS_RA (1<<3) /* ANS, Restart Autonegotiation */ +#define BBA_NWAYC_LTE (1<<7) /* LTE, Link Test Enable */ + +#define BBA_NWAYS 0x31 +#define BBA_NWAYS_LS10 (1<<0) +#define BBA_NWAYS_LS100 (1<<1) +#define BBA_NWAYS_LPNWAY (1<<2) +#define BBA_NWAYS_ANCLPT (1<<3) +#define BBA_NWAYS_100TXF (1<<4) +#define BBA_NWAYS_100TXH (1<<5) +#define BBA_NWAYS_10TXF (1<<6) +#define BBA_NWAYS_10TXH (1<<7) + #endif diff --git a/Source/Core/Core/Src/SConscript b/Source/Core/Core/Src/SConscript index a05efbfb9c..50efeea214 100644 --- a/Source/Core/Core/Src/SConscript +++ b/Source/Core/Core/Src/SConscript @@ -38,7 +38,7 @@ files = ["Console.cpp", "HW/EXI_DeviceAD16.cpp", "HW/EXI_DeviceMemoryCard.cpp", "HW/EXI_DeviceMic.cpp", -# "HW/EXI_DeviceEthernet.cpp", + "HW/EXI_DeviceEthernet.cpp", "HW/GPFifo.cpp", "HW/HW.cpp", "HW/Memmap.cpp",