
#define MACADDR 0x123456780001ULL
#define DEFAULTIP 0xC0A80080

inline WORD premrdat(WORD m){ return m >> 8 | m << 8;}

volatile DWORD txdesc[4] __attribute__ ((aligned (4)));
volatile WORD tx[768] __attribute__ ((aligned (4)));
volatile DWORD rxdesc[4][4] __attribute__ ((aligned (4)));
volatile WORD rx[4][768] __attribute__ ((aligned (4)));
volatile DWORD rxindex;

DWORD ip_r = 0x00000000;
DWORD macl_r = 0x00000000;
WORD mach_r = 0x0000;
DWORD clientip_r = 0x00000000;
DWORD clientmacl_r = 0x00000000;
WORD clientmach_r = 0x0000;

WORD PHYread(BYTE a, BYTE r)
{
  ETH->MACMIIAR = ETH_MACMIIAR_MB | 4 << dekkt(ETH_MACMIIAR_CR) | r << dekkt(ETH_MACMIIAR_MR) | a << dekkt(ETH_MACMIIAR_PA);
  while(ETH->MACMIIAR & ETH_MACMIIAR_MB);
  return ETH->MACMIIDR;
}
void PHYwrite (BYTE a, BYTE r, WORD d)
{
  ETH->MACMIIDR = d;
  ETH->MACMIIAR = ETH_MACMIIAR_MB | ETH_MACMIIAR_MW | 4 << dekkt(ETH_MACMIIAR_CR) | r << dekkt(ETH_MACMIIAR_MR) | a << dekkt(ETH_MACMIIAR_PA);
  while(ETH->MACMIIAR & ETH_MACMIIAR_MB);
}

BYTE ml_eth_init()
{
    ETH->DMABMR |= ETH_DMABMR_SR;   // MAC soft reset
    while(ETH->DMABMR & ETH_DMABMR_SR);
    ETH->DMAOMR = ETH_DMAOMR_FTF;   // flush tx FIFO
    while(ETH->DMAOMR & ETH_DMAOMR_FTF);

    volatile DWORD z;
    // PHY init
    BYTE phyaddr = 0;
    while(1)
    {
        z = 10000;
        while(z --);
        PHYwrite(phyaddr, 0, 1 << 15);
        z = 10000;
        while(z --);
        if((PHYread(phyaddr, 1) & 0xFF00) == 0x7800) break;
        z = 10000;
        while(z --);
        if((PHYread(phyaddr, 1) & 0xFF00) == 0x7800) break;
        if(++ phyaddr >= 32) return 0;
    }
    z = 10000;
    while(z --);
    PHYwrite(phyaddr, 0, 1 << 15);
    while(PHYread(phyaddr, 0) & 1 << 15);       // ujistit se ze se to opravdu reslo
    z = 10000;
    while(z --);
    PHYwrite(phyaddr, 0, 1 << 13 | 1 << 8);     // 100Mbit, full duplex
    z = 10000;
    while(z --);
    if((PHYread(phyaddr, 0) & 0xFF00) != (1 << 13 | 1 << 8)) return 0;
    while(!(PHYread(phyaddr, 1) & 1 << 2));
    z = 10000;
    while(z --);

    ip_r = premrdat(DEFAULTIP >> 16) << 16 | premrdat(DEFAULTIP);
    mach_r = premrdat(MACADDR >> 32);
    macl_r = premrdat(MACADDR >> 16) << 16 | premrdat(MACADDR);

   // ETH->MACFFR = ETH_MACFFR_PM;  // davat vsem
    ETH->MACFCR = ETH_MACFCR_ZQPD;
    ETH->MACA0HR = 0x80000000 | macl_r & 0xFFFF;
    ETH->MACA0LR = mach_r | macl_r & 0xFFFF0000;
    ETH->DMABMR = 32 << dekkt(ETH_DMABMR_PBL) | 32 << dekkt(ETH_DMABMR_RDP) | ETH_DMABMR_AAB | ETH_DMABMR_FB;

    txdesc[0] = DMA_TX_FS | DMA_TX_LS | 1 << dekkt(DMA_TX_CIC) | DMA_TX_TER;
    txdesc[1] = 0;
    txdesc[2] = &tx[0];
    txdesc[3] = 0;
    ETH->DMATDLAR = txdesc;
    rxdesc[0][0] = DMA_RX_OWN;
    rxdesc[0][1] = 1536 << dekkt(DMA_RX_RBS1);
    rxdesc[0][2] = &rx[0][0];
    rxdesc[0][3] = &rxdesc[1][0];
    rxdesc[1][0] = DMA_RX_OWN;
    rxdesc[1][1] = 1536 << dekkt(DMA_RX_RBS1);
    rxdesc[1][2] = &rx[1][0];
    rxdesc[1][3] = &rxdesc[2][0];
    rxdesc[2][0] = DMA_RX_OWN;
    rxdesc[2][1] = 1536 << dekkt(DMA_RX_RBS1);
    rxdesc[2][2] = &rx[2][0];
    rxdesc[2][3] = &rxdesc[3][0];
    rxdesc[3][0] = DMA_RX_OWN;
    rxdesc[3][1] = 1536 << dekkt(DMA_RX_RBS1);
    rxdesc[3][2] = &rx[3][0];
    rxdesc[3][3] = &rxdesc[0][0];
    ETH->DMARDLAR = rxdesc;
    rxindex = 0;
    ETH->DMASR = 0xFFFFFFFF;    // vyresetovat flagy
    ETH->DMAOMR = ETH_DMAOMR_RSF | ETH_DMAOMR_TSF | ETH_DMAOMR_DTCEFD | ETH_DMAOMR_ST | ETH_DMAOMR_SR;
    ETH->MACCR = 0x00008000 | ETH_MACCR_DM | ETH_MACCR_FES | ETH_MACCR_DC | ETH_MACCR_TE | ETH_MACCR_RE;
    return 1;
}