1
0
Files
irix-657m-src/stand/arcs/IP32prom/simulate/SIM_mac110.c
2022-09-29 17:59:04 +03:00

392 lines
10 KiB
C

#include "SIM.h"
#include <mace.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
extern void bcopy(const void*, void*, int);
#define _FIFO x.hdr
/* Message format for communication with client/server */
typedef struct _t{
int code;
int len;
char buf[2048];
} Mac110Msg_t;
static pid_t child; /* Child process */
static int txPipe[2];
static int rxPipe[2];
static Mac110 mac110;
static long rxFifo[64];
enum{
macControl, /* 00 Control an config */
interruptStatus, /* 08 Interrupt status */
dmaCtrl, /* 10 Tx and rx DMA control */
rxIntrTimerCtrl, /* 18 Rx interrupt delay timer */
txIntrAlias, /* 20 Alias of tx interrupt bits */
rxIntrAlias, /* 28 Alias of rx interrupt bits */
txRingBufReadPtr, /* 30 Tx DMA ring buffer read ptr */
txRingBufWritePtr, /* 38 Tx DMA ring buffer write ptr*/
txRingBufProducerPtr, /* 40 diag */
txPingPongProducerPtr,/* 48 diag */
txPingPongConsumerPtr,/* 50 diag */
txPingPongMemWritePtr,/* 58 diag */
rxMclFIFOReadPtr, /* 60 Rx message cluster read ptr */
rxMclFIFOWritePtr, /* 68 Rx message cluster write ptr */
rxMclPingPongReadPtr, /* 70 diag */
rxMclPingPongWritePtr,/* 78 diag */
phyDataInOut, /* 80 */
phyAddress, /* 88 */
phyReadStart, /* 90 */
backoff, /* 98 Random number seed for backoff */
intReq_lastTxVec, /* a0 diag */
txRingBase, /* a8 Transmit ring base addr (phys) */
multicastFilter, /* b0 Multicast logical address mask */
physicalAddress, /* b8 Ethernet physical address */
txPkt1CmdHdr, /* c0 diag */
txPkt1CatBuf1, /* c8 diag */
txPkt1CatBuf2, /* d0 diag */
txPkt1CatBuf3, /* d8 diag */
txPkt2CmdHdr, /* e0 diag */
txPkt2CatBuf1, /* e8 diag */
txPkt2CatBuf2, /* f0 diag */
txPkt2CatBuf3, /* f8 diag */
mclRxFifo /*100 */
};
/***************
* initSimMac110
*/
void
initSimMac110(){
memset((void*)&mac110,0,sizeof mac110);
mac110.macControl |= MAC_RESET;
}
/************
* txFifoSize Returns number of entries in tx fifo
*/
int
txFifoSize(void){
int fs = mac110.dmaCtrl & DMA_TX_RINGMSK;
switch(fs){
case DMA_TX_16K : return 128;
case DMA_TX_32K : return 256;
case DMA_TX_64K : return 512;
default: sim_assert(IMPOSSIBLE);
}
}
/*************
* manageChild Manage ethernet simulation child helper
*------------
* Simulating ethernet transmit/receive is complicated enough to warrant
* using a child process. We fork a child process and exec SIM-MACE. We
* transmit/receive by writing and reading the pipes that connect us to the
* child process.
*/
static void
manageChild(long long control){
extern int wait(int*);
if (control & MAC_RESET){
if (child){
kill(child,1); /* Tell child to quit */
wait(0); /* Wait for it to exit */
close(txPipe[1]); /* Close pipes to/from TX/RX server */
close(rxPipe[0]);
}
/* Reset various registers */
mac110.txRingBufReadPtr = 0;
mac110.txRingBufWritePtr= 0;
mac110.rxMclFIFOReadPtr = 0;
mac110.rxMclFIFOWritePtr= 0;
}
else{
/* Create pipes */
int pipeOpen;
pipeOpen = pipe(txPipe);
sim_assert(pipeOpen>=0);
pipeOpen = pipe(rxPipe);
sim_assert(pipeOpen>=0);
/* Verify that I/O assigments are as we expect */
sim_assert(txPipe[0]==3);
sim_assert(txPipe[1]==4);
sim_assert(rxPipe[0]==5);
sim_assert(rxPipe[1]==6);
child = fork();
sim_assert(child!=-1);
if (child!=0){
close(txPipe[0]);
close(rxPipe[1]);
return;
}
close(0);
dup(txPipe[0]);
close(1);
dup(rxPipe[1]);
close(txPipe[0]);
close(txPipe[1]);
close(rxPipe[0]);
close(rxPipe[1]);
/*
* 0 => tx input pipe from client
* 1 => rx output pipe to client
* 2 => standard error output
*/
/*
* Exec the server process.
*/
execl("/tmp/SIM_MACE",0);
exit(1);
}
}
/***********
* txService Service "transmit"
*----------
*
* Check for transmitter service. Service occurs if:
*
* 1) MAC is not reset.
* 2) TX DMA is enabled
* 3) TX wptr!= TX rptr
* 4) txServiceCtr %3 == 0
*
* Service means copying the tx data to the txPipe
*/
static void
txService(void){
static txServiceCtr;
Mac110Msg_t t;
if ((mac110.macControl & MAC_RESET) == 0 &&
(mac110.dmaCtrl & DMA_TX_DMAENAB) &&
(mac110.txRingBufReadPtr != mac110.txRingBufWritePtr) &&
(txServiceCtr = (txServiceCtr+1)%3) == 0){
/*
* Data is distributed between the fifo entry and the concatenation
* buffer as shown below:
*
* +-----+ - <- fifo entry
* | hdr | |
* : |...............fifo.byteOffset
* | | |
* |=====| | <-+ <---+ <- dword aligned "start" of buffer
* | | | | |
* | | | | >.....skip
* | | | | |
* |-----| v | <---+ <- actual start of buffer
* | X | |
* X >...........fifo.requestLength
* | X | |
* +-----+ | <- end of fifo entry
* |
* +-----+ | <- start of concatenation buf
* | X | |
* | X | |
* X |
* | X | |
* /-----/ <--+
* | |
* :
* | |
* +-----+ <- end of concatenation buf
*
* Note: The data in the fifo entry must be shifted towards the end
* of the fifo entry.
* The requestLength in the fifo header includes the "skipped" bytes.
* The number of "skipped" bytes is the difference between the
* byte offset and the byte offset rounded back to the nearest
* dword aligned offset.
*
* We must figure out where the actual data is and copy it into the
* message we send to the server.
*/
TXfifo* txf = &((TXfifo*)mac110.txRingBase)[mac110.txRingBufReadPtr];
char* cp = t.buf;
int reqLen, flen, skip;
/* Compute # bytes in fifo entry itself */
flen = sizeof(txf->fifoBuf) - txf->_FIFO.cmd.byteOffset;
/*
* Compute the "skip" value so we can figure out the true request length
* from the fifo.requestLength field. (This should equal m->m_len from
* the originating mbuf).
*/
skip = txf->_FIFO.cmd.byteOffset % 8 ;
reqLen = txf->_FIFO.cmd.requestLength + 1 - skip;
t.code = 0;
t.len = reqLen;
/* Copy the data from the fifo entry to the buffer */
bcopy((void*)&txf->fifoBuf[txf->_FIFO.cmd.byteOffset],cp,flen);
cp += flen;
if (reqLen>flen){
sim_assert(txf->_FIFO.cmd.concatPtr0);
bcopy((void*)txf->x.ptr[0],cp,reqLen-flen);
}
write(txPipe[1],&t,t.len+2*sizeof(int));
/*
* Update the status to mark the buffer as sent, then
* Advance the read pointer for the buffer
*/
txf->_FIFO.ll = 0;
txf->_FIFO.sts.finished = 1;
txf->_FIFO.sts.transmitLength = t.len;
mac110.txRingBufReadPtr = (mac110.txRingBufReadPtr+1) % txFifoSize();
}
}
/***********
* rxService Service "receive"
*----------
*
* Check for receiver service. Service occurs if:
*
* 1) MAC is not reset
* 2) RX DMA is enabled
* 3) RX wptr != RX rptr
* 4) select( rxPipe) is true
*
* Service means copying data from rxPipe to rx buffer
*/
static void
rxService(void){
static struct timeval timeout = {0,0};
Mac110Msg_t t;
int tmp;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(rxPipe[0],&readfds);
while ((mac110.macControl & MAC_RESET) == 0 &&
(mac110.dmaCtrl & DMA_RX_DMAENAB) &&
(mac110.rxMclFIFOReadPtr != mac110.rxMclFIFOWritePtr) &&
(tmp = select(rxPipe[0]+1,&readfds,0,0,&timeout))){
tmp = read(rxPipe[0],&t.code,sizeof(t.code));
/* Note, an EOF from the pipe will trigger the following assertion */
sim_assert(tmp == sizeof(t.code));
sim_assert(t.code==0);
{
/*
* Get the "physical" address of the buffer.
* (NOTE: For this simulation, we needn't distinguish between physical
* and virtual as all addresses passed to us are umode.
*/
long long* rxb= (long long*)rxFifo[mac110.rxMclFIFOReadPtr];
/* Read and check the message length */
tmp = read(rxPipe[0],&t.len,sizeof(t.len));
sim_assert(tmp == sizeof(t.len));
/*
* Set the receive status.
* Copy the data to the receive buffer.
*/
*rxb = 0;
((RXbuf*)rxb)->receiveLength = t.len;
((RXbuf*)rxb)->finished = 1;
rxb += (mac110.dmaCtrl & DMA_RX_OFFSET)>>DMA_RX_OFFSET_SHF;
tmp = read(rxPipe[0],((char*)rxb)+2,t.len);
sim_assert(tmp == t.len);
}
/* Advance the read pointer */
mac110.rxMclFIFOReadPtr =
(mac110.rxMclFIFOReadPtr+1) % RXFIFOSIZE;
}
}
/************
* SIM_mac110
*/
void
SIM_mac110(Instr_t inst, Saddr_t eadr, Ctx_t* sc, int reg){
int regNum = (eadr & 0x1ff)/8;
char* regPtr = ((char*)(&mac110))+(regNum*8);
txService();
rxService();
/* Dispatch to appropriate register */
switch(regNum){
/*
* Note: for now the side effects of accessing these registers aren't
* being handled.
*/
case macControl:
loadstore(inst,sc,regPtr);
if (isStore(inst))
manageChild(mac110.macControl);
break;
case dmaCtrl:
case txRingBase: /* Pointer to TX fifo */
case multicastFilter:
case physicalAddress:
loadstore(inst,sc,regPtr);
break;
case txRingBufWritePtr: /* TX fifo wptr */
loadstore(inst,sc,regPtr);
break;
case rxMclFIFOWritePtr: /* Read rx wptr */
case rxMclFIFOReadPtr: /* Read rx rptr */
case txRingBufReadPtr: /* Read rx rptr */
if (!isStore(inst))
loadstore(inst,sc,regPtr);
else
advancePC(inst,sc); /* Ignore writes */
break;
case mclRxFifo:
/*
* Access the RX fifo window.
*/
if (!isStore(inst))
/* If read, load from rxFifo[rptr] */
mac110.mclRxFifo = rxFifo[mac110.rxMclFIFOReadPtr];
loadstore(inst,sc,regPtr);
if (isStore(inst)){
/* If write, store to rxFifo[wptr++] */
rxFifo[mac110.rxMclFIFOWritePtr] = mac110.mclRxFifo;
mac110.rxMclFIFOWritePtr = (mac110.rxMclFIFOWritePtr+1) % 64;
}
break;
default:
/* Report the offending register then quit */
{
extern void sprintf(const char*,...);
char buf[132];
sprintf(buf," sim_mac110: reg: %x[%x}\n", regNum, regNum*8);
SIM_message(buf);
}
sim_assert(UNIMPLEMENTED);
}
}