OpenCores
URL https://opencores.org/ocsvn/xge_mac/xge_mac/trunk

Subversion Repositories xge_mac

[/] [xge_mac/] [trunk/] [tbench/] [systemc/] [sc_xgmii_if.cpp] - Rev 12

Go to most recent revision | Compare with Previous | Blame | View Log

//////////////////////////////////////////////////////////////////////
////                                                              ////
////  File name "sc_xgmii_if.cpp"                                 ////
////                                                              ////
////  This file is part of the "10GE MAC" project                 ////
////  http://www.opencores.org/cores/xge_mac/                     ////
////                                                              ////
////  Author(s):                                                  ////
////      - A. Tanguay (antanguay@opencores.org)                  ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2008 AUTHORS. All rights reserved.             ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
 
#include <stdio.h>
#include <iostream>
#include <sys/times.h>
#include <sys/stat.h>
 
#include "systemc.h"
 
#include "sc_xgmii_if.h"
 
sc_fifo<packet_t*> * xgmii_if::get_tx_fifo_ptr() {
    return &tx_fifo;
}
 
sc_fifo<packet_t*> * xgmii_if::get_rx_fifo_ptr() {
    return &rx_fifo;
}
 
void xgmii_if::init(void) {
    allow_idle_errors = false;
    disable_padding = false;
}
 
void xgmii_if::connect_scoreboard(scoreboard *sbptr, scoreboard::sbSourceId sid) {
    sb = sbptr;
    sb_id = sid;
}
 
void xgmii_if::transmit() {
 
    packet_t* pkt;
 
    sc_uint<64> txd = 0;
    sc_uint<8> txc = 0;
 
    int lane = 0;
    int bytecnt = 0;
    int length = 0;
    int preamblecnt = 0;
    int ifg = 0;
    int fragment_size = 8;
    int coding_offset = 0;
    int fault_cnt = 0;
    int fault_byte = 0;
    int fault_spacing;
    int fault_spacing_cnt = 0;
 
    while (true) {
 
        if (length == 0 && tx_fifo.nb_read(pkt)) {
 
            if (!disable_padding) {
                pad(pkt, 60);
            }
            pack(pkt);
 
            calc_crc(pkt);
 
            //---
            // Inject errors
 
            if (pkt->err_flags & PKT_FLAG_ERR_CRC) {
                pkt->crc++;
            }
 
            if (pkt->err_flags & PKT_FLAG_ERR_FRG) {
                pkt->length = fragment_size;
                fragment_size++;
                if (fragment_size > 64) {
                    fragment_size = 8;
                }
            }
 
            if (pkt->err_flags & PKT_FLAG_ERR_CODING) {
                if (coding_offset >= pkt->length) {
                    pkt->err_info = pkt->length-1;
                }
                else {
                    pkt->err_info = coding_offset;
                }
                coding_offset++;
                if (coding_offset >= 70) {
                    coding_offset = 0;
                }
            }
 
            //---
            // Inject local / remote faults
 
            if (pkt->err_flags & PKT_FLAG_LOCAL_FAULT ||
                pkt->err_flags & PKT_FLAG_REMOTE_FAULT) {
                fault_cnt = 4;
                fault_byte = 4;
                fault_spacing_cnt = 0;
 
                fault_spacing = pkt->err_info;
                cout << "INFO: Fault insert, spacing: " << fault_spacing << endl;
            }
 
            //---
            // Pass packet to scoreboard
 
            sb->notify_packet_tx(sb_id, pkt);
 
            add_crc(pkt);
            strip_crc(pkt);
            length = pkt->length + 4;
 
            //cout << "Transmit XGMII packet:\n" << * pkt << endl;
 
        }
 
 
        if (ifg != 0) {
            txd |= ((sc_uint<64>)0x07) << (8 * lane);
            txc |= 0x01 << lane;
            ifg--;
 
        }
        else if (fault_spacing_cnt != 0) {
 
            txd |= ((sc_uint<64>)0x07) << (8 * lane);
            txc |= 0x01 << lane;
 
            fault_spacing_cnt--;
 
        }
        else if ((lane == 0 || lane == 4) && fault_byte == 4) {
 
            txd |= ((sc_uint<64>)0x9c) << (8 * lane);
            txc |= 0x01 << lane;
 
            fault_byte--;
 
        }
        else if (fault_byte == 3 || fault_byte == 2) {
 
            fault_byte--;
 
        }
        else if (fault_byte == 1) {
 
            if (pkt->err_flags & PKT_FLAG_LOCAL_FAULT) {
                txd |= ((sc_uint<64>)0x01) << (8 * lane);
            }
            else {
                txd |= ((sc_uint<64>)0x02) << (8 * lane);
            }
            fault_byte--;
 
            fault_cnt--;
            if (fault_cnt > 0) {
                fault_byte = 4;
            }
 
            if (fault_cnt == 1) {
                fault_spacing_cnt = 4 * fault_spacing;
            }
        }
        else if ((lane == 0 || lane == 4) && bytecnt != length && preamblecnt == 0) {
 
            txd |= ((sc_uint<64>)0xfb) << (8 * lane);
            txc |= 0x01 << lane;
 
            preamblecnt++;
 
        }
        else if (preamblecnt > 0 && preamblecnt < 7) {
 
            txd |= ((sc_uint<64>)0x55) << (8 * lane);
 
            preamblecnt++;
 
        }
        else if (preamblecnt == 7) {
 
            txd |= ((sc_uint<64>)0xd5) << (8 * lane);
 
            preamblecnt++;
 
        }
        else if (preamblecnt > 7 && (bytecnt == (length-4)) &&
                 (pkt->err_flags & PKT_FLAG_ERR_FRG)) {
 
            //---
            // Fragment insertion
 
            bytecnt = 0;
            length = 0;
            preamblecnt = 0;
            ifg = 0;
 
        }
        else if (preamblecnt >7 && bytecnt == pkt->err_info && 
                 (pkt->err_flags & PKT_FLAG_ERR_CODING)) {
 
            //---
            // Coding error insertion
 
            txc |= 0x01 << lane;
            txd |= ((sc_uint<64>)pkt->data[bytecnt]) << (8 * lane);
            bytecnt++;
 
        }
        else if (preamblecnt > 7 && bytecnt < length) {
 
            txd |= ((sc_uint<64>)pkt->data[bytecnt]) << (8 * lane);
            bytecnt++;
 
        }
        else if (preamblecnt > 7 && bytecnt == length) {
 
            //---
            // End of frame TERMINATE
 
            txd |= ((sc_uint<64>)0xfd) << (8 * lane);
            txc |= 0x01 << lane;
 
            bytecnt = 0;
            length = 0;
            preamblecnt = 0;
 
            // Minimum IFG is 5 including TERMINATE
            ifg = 4;
 
        }
        else {
            txd |= ((sc_uint<64>)0x07) << (8 * lane);
            txc |= 0x01 << lane;
        }
        if (lane == 7) {
            xgmii_rxd = txd;
            xgmii_rxc = txc;
            txd = 0;
            txc = 0;
            wait();
        }
        lane = (lane + 1) % 8;
 
    }
};
 
 
void xgmii_if::receive() {
 
    packet_t* pkt;
 
    sc_uint<64> rxd;
    sc_uint<8> rxc;
 
    int lane, bytecnt, ifgcnt;
 
    lane = 0;
 
    wait();
 
    while (true) {
 
        ifgcnt = 1;
 
        rxd = xgmii_txd;
        rxc = xgmii_txc;
 
 
        //---
        // Wait for START code in lane0 or lane4
 
        while (true) {
 
            // Check for START character
            if (((rxd >> (8*lane)) & 0xff) == 0xfb && ((rxc >> lane) & 0x1) == 1) {
                if (disable_receive) {
                    cout << "INFO: XGMII Receive Disabled" << endl;
                }
                else {
                    break;
                }
            };
 
            // Check IDLE character and control lines
            if (((rxd >> (8*lane)) & 0xff) != 0x07 || ((rxc >> lane) & 0x1) != 1) {
                if (allow_idle_errors) {
                    cout << "INFO: IDLE check disabled" << endl;
                }
                else {
                    cout << "ERROR: IDLE character " << hex << rxd << " " << rxc << dec << lane << endl;
                    sc_stop();
                }
            };
 
            ifgcnt++;
 
            lane = (lane + 1) % 8;
            if (lane == 0) {
                wait();
                rxd = xgmii_txd;
                rxc = xgmii_txc;
            }
        }
 
        //cout << "START in lane " << lane << " IFG " << ifgcnt << endl;
 
        // Check starting lane
        if (lane != 0 && lane != 4) {
            cout << "ERROR: Lane aligment" << endl;
            sc_stop();
        }
 
        // Check for minimum inter frame gap
        if (ifgcnt < 9) {
            cout << "ERROR: MINIMUM IFG " << ifgcnt << endl;
            sc_stop();
        }
 
        //---
        // Capture data until end of frame is detected (TERMINATE)
 
        pkt = new(packet_t);
        pkt->ifg = ifgcnt;
        pkt->start_lane = lane;
        pkt->length = 0;
 
        bytecnt = 0;
        while (true) {
 
            // Look for end of frame delimiter in any lane
            if (((rxd >> (8*lane)) & 0xff) == 0xfd && ((rxc >> lane) & 0x1) == 1) {
                break;
            };
 
            // Stop if packet is too long
            if (bytecnt >=  10000) {
                break;
            }
 
            // Validate preamble bytes
            if (bytecnt > 0 && bytecnt <= 6 && ((rxd >> (8*lane)) & 0xff) != 0x55) {
                cout << "ERROR: Invalid preamble byte: " << bytecnt << endl;
                sc_stop();
            }
 
            // Validate SFD code in preamble
            if (bytecnt == 7 && ((rxd >> (8*lane)) & 0xff) != 0xd5) {
                cout << "ERROR: Invalid preamble byte: " << bytecnt << endl;
                sc_stop();
            }
 
            // Store all bytes after preamble
            if (bytecnt >  7) {
                if (((rxc >> lane) & 0x1) == 0) {
                    pkt->data[pkt->length] = ((rxd >> (8*lane)) & 0xff);
                    pkt->length++;
                }
                else {
                    cout << "ERROR: RXC high during data cycle" << endl;
                    sc_stop();
                }
            }
            else if (bytecnt > 0) {
                if (((rxc >> lane) & 0x1) == 1) {
                    cout << "ERROR: RXC high during preamble" << endl;
                    sc_stop();
                }
            }
 
            bytecnt++;
            lane = (lane + 1) % 8;
            if (lane == 0) {
                wait();
                rxd = xgmii_txd;
                rxc = xgmii_txc;
            }
        }
 
 
        lane = (lane + 1) % 8;
        if (lane == 0) {
            wait();
            rxd = xgmii_txd;
            rxc = xgmii_txc;
        }
 
        //---
        // Store packet
 
        strip_crc(pkt);
 
        unpack(pkt);
        //rx_fifo.write(pkt);
        //cout << "Received XGMII packet:" << * pkt << endl;
 
        //---
        // Pass packet to scoreboard
 
        sb->notify_packet_rx(sb_id, pkt);
 
    }
};
 
 
void xgmii_if::monitor() {
 
    sc_uint<64> rxd;
    sc_uint<8> rxc;
 
    wait();
 
    while (true) {
 
        rxd = xgmii_txd;
        rxc = xgmii_txc;
 
        //---
        // Check for local/remote fault
 
        if (((rxd & 0xffffffff) == 0x0100009c && (rxc & 0xf) == 0x1) &&
            (((rxd >> 32) & 0xffffffff) == 0x0100009c && ((rxc > 4) & 0xf) == 0x1)) {
 
            //--
            // Local fault detection
 
            if (!rx_local_fault) {
                cout << "XGMII Local Fault Asserted" << endl;
 
                // Notify Scoreboard
                sb->notify_status(sb_id, scoreboard::LOCAL_FAULT);
            }
            rx_local_fault = true;
 
        }
        else {
 
            if (rx_local_fault) {
                cout << "XGMII Local Fault De-Asserted" << endl;
            }
            rx_local_fault = false;
 
        }
 
        if (((rxd & 0xffffffff) == 0x0200009c && (rxc & 0xf) == 0x1) &&
            (((rxd >> 32) & 0xffffffff) == 0x0200009c && ((rxc > 4) & 0xf) == 0x1)) {
 
            //--
            // Remote fault detection
 
            if (!rx_remote_fault) {
                cout << "XGMII Remote Fault Asserted" << endl;
 
                // Notify Scoreboard
                sb->notify_status(sb_id, scoreboard::REMOTE_FAULT);
            }
            rx_remote_fault = true;
 
        }
        else {
 
            if (rx_remote_fault) {
                cout << "XGMII Remote Fault De-Asserted" << endl;
            }
            rx_remote_fault = false;
 
        }
 
        wait();
    }
};
 
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.