More work on BBA. Socket Test gets stuck in a loop, but now it's also receiving packets in that loop, Linux only. The device to set up in Linux is a bit of a pain as well. Breaks Windows compiling, but I will commit another with Windows fix in a moment

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3284 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Sonicadvance1 2009-05-25 13:07:42 +00:00
parent e72b77931c
commit cd03e98d3c
3 changed files with 260 additions and 22 deletions

View File

@ -27,6 +27,7 @@
#if !defined(__APPLE__) #if !defined(__APPLE__)
#include <stropts.h> #include <stropts.h>
#include <linux/if_tun.h> #include <linux/if_tun.h>
#include <assert.h>
#endif #endif
int fd = -1; int fd = -1;
bool CEXIETHERNET::deactivate() bool CEXIETHERNET::deactivate()
@ -63,6 +64,7 @@ bool CEXIETHERNET::activate() {
DEBUGPRINT(" Error with IOCTL: 0x%X\n", err); DEBUGPRINT(" Error with IOCTL: 0x%X\n", err);
return false; return false;
} }
ioctl( fd, TUNSETNOCSUM, 1 );
#endif #endif
DEBUGPRINT("Returned Socket name is: %s\n", ifr.ifr_name); DEBUGPRINT("Returned Socket name is: %s\n", ifr.ifr_name);
resume(); resume();
@ -123,23 +125,22 @@ bool CEXIETHERNET::startRecv() {
//exit(0); //exit(0);
if(!isActivated()) if(!isActivated())
return false;// Should actually be an assert return false;// Should actually be an assert
if(!CheckRecieved()) // Check if we have data if(!CheckRecieved())
return false; // Nope return false;
DEBUGPRINT("startRecv... "); DEBUGPRINT("startRecv... ");
if(mWaiting) { if(mWaiting) {
DEBUGPRINT("already waiting\n"); DEBUGPRINT("already waiting\n");
return true; return true;
} }
u32 BytesRead = 0; u32 BytesRead = 0;
u8 B[2]; u8 B[1514];
int Num = 0; if((BytesRead = read(fd, B, 1500)) > 0)
while(read(fd, B, 1))
{ {
DEBUGPRINT("Read 1 Byte!\n"); strncpy((char*)mRecvBuffer.p(), (const char*)B, BytesRead);
mRecvBuffer.write(1, B);
Num++;
} }
DEBUGPRINT("Read %d bytes\n", Num); DEBUGPRINT("Read %d bytes\n", BytesRead);
mRecvBufferLength = BytesRead;
handleRecvdPacket();
return true; return true;
} }
bool CEXIETHERNET::sendPacket(u8 *etherpckt, int size) bool CEXIETHERNET::sendPacket(u8 *etherpckt, int size)
@ -166,6 +167,101 @@ bool CEXIETHERNET::sendPacket(u8 *etherpckt, int size)
} }
bool CEXIETHERNET::handleRecvdPacket() bool CEXIETHERNET::handleRecvdPacket()
{ {
DEBUGPRINT(" Handle received Packet!\n");
exit(0); int rbwpp = mCbw.p_write() + CB_OFFSET; //read buffer write page pointer
u32 available_bytes_in_cb;
if(rbwpp < mRBRPP)
available_bytes_in_cb = mRBRPP - rbwpp;
else if(rbwpp == mRBRPP)
available_bytes_in_cb = mRBEmpty ? CB_SIZE : 0;
else //rbwpp > mRBRPP
available_bytes_in_cb = CB_SIZE - rbwpp + (mRBRPP - CB_OFFSET);
//DUMPWORD(rbwpp);
//DUMPWORD(mRBRPP);
//DUMPWORD(available_bytes_in_cb);
assert(available_bytes_in_cb <= CB_SIZE);
if(available_bytes_in_cb != CB_SIZE)//< mRecvBufferLength + SIZEOF_RECV_DESCRIPTOR)
if(available_bytes_in_cb != CB_SIZE)//< mRecvBufferLength + SIZEOF_RECV_DESCRIPTOR)
return true;
cbwriteDescriptor(mRecvBufferLength);
mCbw.write(mRecvBuffer.p(), mRecvBufferLength);
mCbw.align();
rbwpp = mCbw.p_write() + CB_OFFSET;
//DUMPWORD(rbwpp);
//mPacketsRcvd++;
mRecvBufferLength = 0;
if(mBbaMem[0x08] & BBA_INTERRUPT_RECV)
{
if(!(mBbaMem[0x09] & BBA_INTERRUPT_RECV))
{
mBbaMem[0x09] |= BBA_INTERRUPT_RECV;
DEBUGPRINT("BBA Recv interrupt raised\n");
m_bInterruptSet = true;
}
}
if(mBbaMem[BBA_NCRA] & BBA_NCRA_SR)
{
startRecv();
}
return true;
}
union bba_descr {
struct { u32 next_packet_ptr:12, packet_len:12, status:8; };
u32 word;
};
bool CEXIETHERNET::cbwriteDescriptor(u32 size) {
//if(size < 0x3C) {//60
#define ETHERNET_HEADER_SIZE 0xE
if(size < ETHERNET_HEADER_SIZE)
{
DEBUGPRINT("Packet too small: %i bytes\n", size);
return false;
}
size += SIZEOF_RECV_DESCRIPTOR; //The descriptor supposed to include the size of itself
//We should probably not implement wraparound here,
//since neither tmbinc, riptool.dol, or libogc does...
if(mCbw.p_write() + SIZEOF_RECV_DESCRIPTOR >= CB_SIZE)
{
DEBUGPRINT("The descriptor won't fit\n");
return false;
}
if(size >= CB_SIZE)
{
DEBUGPRINT("Packet too big: %i bytes\n", size);
return false;
}
bba_descr descr;
descr.word = 0;
descr.packet_len = size;
descr.status = 0;
u32 npp;
if(mCbw.p_write() + size < CB_SIZE)
{
npp = mCbw.p_write() + size + CB_OFFSET;
}
else
{
npp = mCbw.p_write() + size + CB_OFFSET - CB_SIZE;
}
npp = (npp + 0xff) & ~0xff;
if(npp >= CB_SIZE + CB_OFFSET)
npp -= CB_SIZE;
descr.next_packet_ptr = npp >> 8;
//DWORD swapped = swapw(descr.word);
//next_packet_ptr:12, packet_len:12, status:8;
DEBUGPRINT("Writing descriptor 0x%08X @ 0x%04X: next 0x%03X len 0x%03X status 0x%02X\n",
descr.word, mCbw.p_write() + CB_OFFSET, descr.next_packet_ptr,
descr.packet_len, descr.status);
mCbw.write(&descr.word, SIZEOF_RECV_DESCRIPTOR);
return true;
} }

View File

@ -76,7 +76,29 @@ CEXIETHERNET::CEXIETHERNET() :
Expecting = EXPECT_NONE; Expecting = EXPECT_NONE;
mExpectVariableLengthImmWrite = false; mExpectVariableLengthImmWrite = false;
} }
void CyclicBufferWriter::write(void *src, size_t size)
{
assert(size < _cap);
u8* bsrc = (u8*) src;
if(_write + size >= _cap)
{ //wraparound
memcpy(_buffer + _write, src, _cap - _write);
memcpy(_buffer, bsrc + (_cap - _write), size - (_cap - _write));
_write = size - (_cap - _write);
}
else
{
memcpy(_buffer + _write, src, size);
_write += size;
}
//DEGUB("CBWrote %i bytes\n", size);
}
void CyclicBufferWriter::align()
{
_write = (_write + 0xff) & ~0xff;
if(_write >= _cap)
_write -= _cap;
}
void CEXIETHERNET::SetCS(int cs) void CEXIETHERNET::SetCS(int cs)
{ {
DEBUGPRINT("Set CS: %s Expect Variable write?: %s\n", cs ? "true" : "false", mExpectVariableLengthImmWrite ? "true" : "false"); DEBUGPRINT("Set CS: %s Expect Variable write?: %s\n", cs ? "true" : "false", mExpectVariableLengthImmWrite ? "true" : "false");
@ -215,8 +237,6 @@ void CEXIETHERNET::ImmWrite(u32 _uData, u32 _uSize)
DEBUGPRINT( "\t\t[INFO]BBA_NWAYC\n"); DEBUGPRINT( "\t\t[INFO]BBA_NWAYC\n");
if(Common::swap32(_uData) & (BBA_NWAYC_ANE | BBA_NWAYC_ANS_RA)) if(Common::swap32(_uData) & (BBA_NWAYC_ANE | BBA_NWAYC_ANS_RA))
{ {
DEBUGPRINT("\t\t\tACTIVATING!\n");
activate();
//say we've successfully negotiated for 10 Mbit full duplex //say we've successfully negotiated for 10 Mbit full duplex
//should placate libogc //should placate libogc
mBbaMem[BBA_NWAYS] = (BBA_NWAYS_LS10 | BBA_NWAYS_LPNWAY | BBA_NWAYS_ANCLPT | BBA_NWAYS_10TXF); mBbaMem[BBA_NWAYS] = (BBA_NWAYS_LS10 | BBA_NWAYS_LPNWAY | BBA_NWAYS_ANCLPT | BBA_NWAYS_10TXF);
@ -335,18 +355,25 @@ void CEXIETHERNET::ImmWrite(u32 _uData, u32 _uSize)
case 0x20: //MAC address case 0x20: //MAC address
DEBUGPRINT( "\t\t[INFO]Mac Address!\n"); DEBUGPRINT( "\t\t[INFO]Mac Address!\n");
memcpy(mBbaMem + mReadP, mac_address, 6); memcpy(mBbaMem + mReadP, mac_address, 6);
DEBUGPRINT("\t\t\tACTIVATING!\n");
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; break;
case 0x01: //Revision ID case 0x01: //Revision ID
break; break;
case 0x16: //RWP - Receive Buffer Write Page Pointer case 0x16: //RWP - Receive Buffer Write Page Pointer
DEBUGPRINT( "\t\t[INFO]RWP!\n"); DEBUGPRINT( "\t\t[INFO]RWP!\n");
exit(0); //exit(0);
//MAKE(WORD, mBbaMem[mReadP]) = ((WORD)mCbw.p_write() + CB_OFFSET) >> 8; // TODO: Dunno if correct
MAKE(u16, mBbaMem[mReadP]) = ((u16)mCbw.p_write() + CB_OFFSET) >> 8;
break; break;
case 0x18: //RRP - Receive Buffer Read Page Pointer case 0x18: //RRP - Receive Buffer Read Page Pointer
DEBUGPRINT( "\t\t[INFO]RRP!\n"); DEBUGPRINT( "\t\t[INFO]RRP!\n");
exit(0); //exit(0);
//MAKE(WORD, mBbaMem[mReadP]) = (mRBRPP) >> 8; // TODO: Dunno if correct
MAKE(u16, mBbaMem[mReadP]) = (mRBRPP) >> 8;
break; break;
case 0x3A: //bit 1 set if no data available case 0x3A: //bit 1 set if no data available
DEBUGPRINT( "\t\t[INFO]Bit 1 set!\n"); DEBUGPRINT( "\t\t[INFO]Bit 1 set!\n");
@ -399,7 +426,8 @@ u32 CEXIETHERNET::ImmRead(u32 _uSize)
//DEBUGPRINT("Mem spot is 0x%02x uResult is 0x%x\n", mBbaMem[mReadP], uResult); //DEBUGPRINT("Mem spot is 0x%02x uResult is 0x%x\n", mBbaMem[mReadP], uResult);
#ifndef _WIN32 #ifndef _WIN32
CheckRecieved(); if(CheckRecieved())
startRecv();
#endif #endif
DEBUGPRINT( "\t[INFO]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)); DEBUGPRINT( "\t[INFO]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; mReadP = mReadP + _uSize;
@ -433,6 +461,26 @@ void CEXIETHERNET::DMAWrite(u32 _uAddr, u32 _uSize)
void CEXIETHERNET::DMARead(u32 _uAddr, u32 _uSize) void CEXIETHERNET::DMARead(u32 _uAddr, u32 _uSize)
{ {
DEBUGPRINT( "DMAR\n"); if(mReadP != INVALID_P)
exit(0); {
if(mReadP + _uSize > BBAMEM_SIZE)
{
DEBUGPRINT("Read error: mReadP + size = 0x%04X + %i\n", mReadP, _uSize);
return;
}
//mem.write_physical(address, size, mBbaMem + mReadP);
memcpy(Memory::GetPointer(_uAddr), mBbaMem + mReadP, _uSize);
DEBUGPRINT("DMA Read from BBA address 0x%0*X, %i bytes\n",
mReadP >= CB_OFFSET ? 4 : 2, mReadP, _uSize);
mReadP = mReadP + (u16)_uSize;
return;
}
else
{
DEBUGPRINT("Unhandled BBA DMA read: %i, 0x%08X\n", _uSize, _uAddr);
//if(g::bouehr)
exit(0);
//throw bouehr_exception("Unhandled BBA DMA read");
//return EXI_UNHANDLED;
}
}; };

View File

@ -37,6 +37,99 @@ inline u32 getbitsw(u32 dword, int start, int end) {
return (dword & makemaskw(start, end)) >> (31 - end); return (dword & makemaskw(start, end)) >> (31 - end);
} }
// Container Class Stolen from Whinecube
template<class T> class SubContainer;
template<class T> class Container {
public:
Container(size_t _size) {
b = 0;
allocate(_size);
}
Container(size_t _size, const T *data) {
b = 0;
allocate(size);
memcpy(a, data, _size);
}
~Container() {
if(a) /*if(_msize(a))*/ free(a);
}
void resize(size_t _size) {
if(b == _size)
return;
free(a);
allocate(_size);
}
/*void insert(int before, void *src, size_t size) {
char *temp = a;
a = new char[b + size];
if(a == NULL)
BFE("Memory insert failed in container");
memcpy(a, temp, before);
memcpy(a+before, src, size);
memcpy(a+before+size, temp+before, b-before);
b += size;
delete temp;
}*/
class SubContainer : public Container {
private:
SubContainer(void* ptr, size_t size) : Container(ptr, size) {}
friend class Container;
public:
~SubContainer() {
a = NULL;
b = 0;
}
};
SubContainer getSub(size_t pos) {
return SubContainer(((char*)a) + pos, b - pos);
}
operator T*() { return (T *)a; }
operator const T*() const { return (T *)a; }
T* p() { return (T *)a; }
const T* p() const { return (T *)a; }
T *operator->() { return (T *)a; }
size_t size() const { return b; }
void steal(Container<T> &src) {
resize(0); a = src.a; b = src.b;
src.a = NULL; src.b = 0;
}
void swap(Container<T> &other) {
T *ta = a; size_t tb = b;
a = other.a; b = other.b;
other.a = ta; other.b = tb;
}
protected:
void *a;
size_t b;
private:
Container(const Container&);
Container &operator=(const Container&);
Container(void* ptr, size_t _size) : a(ptr), b(_size) {}
friend class SubContainer;
void allocate(size_t _size) {
if(_size > (100*1024*1024)) // 100 MB cap
exit(0);
//DEGUB("Resize: %i -> %i = %i\n", b, size, g_con_total);
//if(size > 1000*K) {
//DEGUB("Megabyte Container resize!\n");
//}
b = _size;
if(_size == 0)
a = NULL;
else {
a = malloc(_size);
//if(!_CrtIsValidHeapPointer(a))
//throw generic_fatal_exception("malloc failed in Container");
}
}
};
void DEBUGPRINT (const char * format, ...); void DEBUGPRINT (const char * format, ...);
class WriteBuffer { class WriteBuffer {
@ -141,9 +234,10 @@ private:
bool isActivated(); bool isActivated();
bool resume(); bool resume();
bool startRecv(); bool startRecv();
bool cbwriteDescriptor(u32 size);
volatile bool mWaiting; volatile bool mWaiting;
WriteBuffer mRecvBuffer; Container<u8> mRecvBuffer;
#ifdef _WIN32 #ifdef _WIN32
HANDLE mHAdapter, mHRecvEvent, mHReadWait; HANDLE mHAdapter, mHRecvEvent, mHReadWait;
DWORD mMtu; DWORD mMtu;