// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: etl.cpp
// Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
// 4150 Network Circle, Santa Clara, California 95054, U.S.A.
// * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 2 of the License.
// This program 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 General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// For the avoidance of doubt, and except that if any non-GPL license
// choice is available it will apply instead, Sun elects to use only
// the General Public License version 2 (GPLv2) at this time for any
// software where a choice of GPL license versions is made
// available with the language indicating that GPLv2 or any later version
// may be used, or where a choice of which version of the GPL is applied is
// otherwise unspecified.
// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
// CA 95054 USA or visit www.sun.com if you need additional information or
// ========== Copyright Header End ============================================
#include "pcie_common/logger.hpp"
* This method initializes module registers and flags.
* It also spawns threads that handle module operation.
execute_ph
= sc_spawn(sc_bind(&etl::execute
,this));
req_handler_ph
= sc_spawn(sc_bind(&etl::req_handler
,this));
cmpl_handler_ph
= sc_spawn(sc_bind(&etl::cmpl_handler
,this));
ecl_update_ph
= sc_spawn(sc_bind(&etl::ecl_update
,this));
LOG_INFO
<< "ETL: SW Reset : threads spawned";
* This thread forwards TLPs in the egress_q to DLL. Non-posted requests are also
void etl::execute(void) {
LOG_INFO
<<"ETL: execute begin...";
csr_port
.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR
, ecc
);
while (!egress_q
.empty()){
next_pkt
= egress_q
.front();
LOG_INFO
<< "ETL: Send Packet " << next_pkt
->getPacketId() << "\n";
//cout << sc_time_stamp() << "\t\t\t\t\t| ETL: Send Packet " << next_pkt->getPacketId() << " to DLL." << endl;
if((!next_pkt
->isPosted()) && (!next_pkt
->isCmpl()))
eg_etl_rsb_port
.send_packet(next_pkt
);
dout_port
.send_packet(next_pkt
);
LOG_WARNING
<< "ETL: Out of execute";
* This thread receives TLPs from the ILU interface and enqueues them into
* the egress_q, once credit is available.
void etl::req_handler() {
LOG_INFO
<<"ETL: req_handler begin...";
req_port
.get_packet(new_pkt
);
//cout<< sc_time_stamp() <<"\t\t\t\t\t| ETL: Recvd Req TLP " <<new_pkt->getPacketId() << " from ilu_intf" <<endl;
LOG_WARNING
<< "ETL: Out of req_handler";
* This thread receives CMPL TLPs from the ILU interface and enqueues them into
* the egress_q, once credit is available.
void etl::cmpl_handler() {
LOG_INFO
<<"ETL: cmpl_handler begins...";
cmpl_port
.get_packet(new_pkt
);
//cout<< sc_time_stamp() <<"\t\t\t\t\t| ETL: Recvd Cpl TLP " <<new_pkt->getPacketId() << " from ilu_intf" <<endl;
get_cmpl_credit(new_pkt
);
LOG_WARNING
<< "ETL: Out of cmpl_handler";
* This thread monitors the egress credit limit CSR register and provides updates
* to any waiting out-going TLPs.
LOG_INFO
<< "ETL: ecl_update begins...";
ecl
= csr_port
.read_csr(PEU_CSR_A_TLU_ECL_HW_ADDR
);
LOG_WARNING
<< "ETL: Out of ecl_update";
* This blocking thread waits for available posted credits for out-going TLPs.
void etl::get_p_credit(RefPciePacket
& p
) {
sc_uint
<12> cred
= (GET_TLP_LEN(p
))/4;
if((GET_TLP_LEN(p
))%4 != 0) cred
++;
ecc
= csr_port
.read_csr(PEU_CSR_A_TLU_ECC_HW_ADDR
);
else if(ecc(19,12)==ecl(19,12))
else if( (ecl(11,0)-((sc_uint
<12>)ecc(11,0)+cred
)) %4096 > 2048 )
ecc(19,12) = (sc_uint
<8>)ecc(19,12) + 1;
if(p
->hasData()) ecc(11,0) = (sc_uint
<12>)ecc(11,0) + cred
;
LOG_DEBUG
<< "ETL: PH consumed (+1) = " << ecc(19,12) << " PD consumed (+" << cred
<< ") = " << ecc(11,0) ;
LOG_DEBUG
<< "ETL: PH consumed (+1) = " << ecc(19,12) << " PD consumed (+0) = " << ecc(11,0) ;
csr_port
.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR
, ecc
);
* This blocking thread waits for available non-posted credits for out-going TLPs.
void etl::get_np_credit(RefPciePacket
& p
) {
sc_uint
<12> cred
= (GET_TLP_LEN(p
))/4;
if((GET_TLP_LEN(p
))%4 != 0) cred
++;
ecc
= csr_port
.read_csr(PEU_CSR_A_TLU_ECC_HW_ADDR
);
else if(ecc(39,32)==ecl(39,32))
else if( (ecl(31,20)-((sc_uint
<12>)ecc(31,20)+cred
)) %4096 > 2048 )
ecc(39,32) = (sc_uint
<8>)ecc(39,32) + 1;
if(p
->hasData()) ecc(31,20) = (sc_uint
<12>)ecc(31,20) + cred
;
LOG_DEBUG
<< "ETL: NPH consumed (+1) = " << ecc(39,32) << " NPD consumed (+" << cred
<< ") = " << ecc(31,20) ;
LOG_DEBUG
<< "ETL: NPH consumed (+1) = " << ecc(39,32) << " NPD consumed (+0) = " << ecc(31,20) ;
csr_port
.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR
, ecc
);
* This blocking thread waits for available cmpl credits for out-going TLPs.
void etl::get_cmpl_credit(RefPciePacket
& p
) {
sc_uint
<12> cred
= (GET_TLP_LEN(p
))/4;
if((GET_TLP_LEN(p
))%4 != 0) cred
++;
ecc
= csr_port
.read_csr(PEU_CSR_A_TLU_ECC_HW_ADDR
);
else if(ecc(59,52)==ecl(59,52))
else if( (ecl(51,40)-((sc_uint
<12>)ecc(51,40)+cred
)) %4096 > 2048 )
ecc(59,52) = (sc_uint
<8>)ecc(59,52) + 1;
if(p
->hasData()) ecc(51,40) = (sc_uint
<12>)ecc(51,40) + cred
;
LOG_DEBUG
<< "ETL: CH consumed (+1) = " << ecc(59,52) << " CD consumed (+" << cred
<< ") = " << ecc(51,40) ;
LOG_DEBUG
<< "ETL: CH consumed (+1) = " << ecc(59,52) << " CD consumed (+0) = " << ecc(51,40) ;
csr_port
.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR
, ecc
);
* This thread handles reset behavior of the module. On the arrival of a reset global event,
* it issue termination requests to threads in this module. Following the reset exit global event
* it invokes init() to re-spawn terminated threads.
void etl::reset_handler(){
csr_port
.set_notify_event(PEU_CSR_A_TLU_ECL_HW_ADDR
, &ecl_ev
);
switch(*global_event_type
){
LOG_WARNING
<< "\tETL: WMR/POR_RESET enter signal...";
if(execute_ph
.terminated() && req_handler_ph
.terminated() && cmpl_handler_ph
.terminated() && ecl_update_ph
.terminated()) break;
wait(execute_ph
.terminated_event()|req_handler_ph
.terminated_event()|cmpl_handler_ph
.terminated_event()|ecl_update_ph
.terminated_event());
LOG_WARNING
<< "ETL: WMR/POR Reset threads terminated";
while(!egress_q
.empty()) egress_q
.pop();
LOG_INFO
<< "ETL: WMR/POR Reset dbs cleared";
LOG_INFO
<< "\tETL: WMR/POR_RESET exit signal...";