// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: ilu_intf.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"
* Binary to gray code helper function
sc_uint
<32> bin2gc (sc_uint
<32> binval
) {
gcval
= binval
^ (bit_zero
, binval(32-1, 1));
* Gray code to binary helper function
sc_uint
<32> gc2bin (sc_uint
<32> gcval
) {
binval
[32-1] = gcval
[32-1];
for (i
= (32 - 2); i
>= 0; --i
)
binval
[i
] = binval
[i
+1] ^ gcval
[i
];
int parity (sc_uint
<32> data
) {
for (int i
= 0; i
< 32; i
++) {
* This thread collects outgoing Hdr from the ILU and loads it into the EHB.
void ilu_intf::ehb_write(void) {
sc_uint
<D2P_EHB_ADDR_WDTH
> ehb_addr
;
wait(clk
.negedge_event());
ehb_we
= d2p_ehb_we
.read();
ehb_addr
= d2p_ehb_addr
.read().to_uint();
ehb_buffer
[ehb_addr
](127,0) = d2p_ehb_data
.read();
ehb_buffer
[ehb_addr
](131,128) = d2p_ehb_dpar
.read();
LOG_DEBUG
<< "EHB Write @ " << ehb_addr
<< " DATA: " << (string
) d2p_ehb_data
.read().to_string();
* This thread collects outgoing data from the ILU and loads it into the EDB.
void ilu_intf::edb_write(void) {
sc_uint
<D2P_EDB_ADDR_WDTH
> edb_addr
;
wait(clk
.negedge_event());
edb_we
= d2p_edb_we
.read();
edb_addr
= d2p_edb_addr
.read().to_uint();
edb_buffer
[edb_addr
](127,0) = d2p_edb_data
.read();
edb_buffer
[edb_addr
](131,128) = d2p_edb_dpar
.read();
LOG_DEBUG
<< "EDB Write @ " << edb_addr
;
* This thread provides IHB content to the ILU.
void ilu_intf::ihb_read(void) {
sc_uint
<D2P_IHB_ADDR_WDTH
> ihb_addr
;
wait (clk
.negedge_event());
ihb_addr
= d2p_ihb_addr
.read().to_uint();
ihb_rd
= d2p_ihb_rd
.read();
wait (clk
.posedge_event());
if ( (bin2gc(ihb_addr
) != ihb_wptr
) && (!ihb_empty
) ) {
p2d_ihb_dpar
.write ( ihb_buffer
[ihb_addr
]
(P2D_IHB_DATA_WDTH
+P2D_IHB_DPAR_WDTH
-1,
p2d_ihb_data
.write(ihb_buffer
[ihb_addr
](P2D_IHB_DATA_WDTH
-1, 0));
LOG_DEBUG
<< "IHB Read @ " << ihb_addr
;
LOG_DEBUG
<< "Reading empty IHB @ " << ihb_addr
;
* This thread provides IDB content to the ILU.
void ilu_intf::idb_read(void) {
sc_uint
<D2P_IDB_ADDR_WDTH
> idb_addr
;
wait (clk
.negedge_event());
idb_addr
= d2p_idb_addr
.read().to_uint();
idb_rd
= d2p_idb_rd
.read();
wait (clk
.posedge_event());
p2d_idb_dpar
.write ( idb_buffer
[idb_addr
]
(P2D_IDB_DATA_WDTH
+P2D_IDB_DPAR_WDTH
-1,
p2d_idb_data
.write(idb_buffer
[idb_addr
](P2D_IDB_DATA_WDTH
-1, 0));
//LOG_DEBUG << "IDB Read @ " << idb_addr;
* This thread receives ingress TLPs from the lower layers (i.e. ITL), and loads
* it into the IHB and IDB.
void ilu_intf::ingress_packet_handler() {
LOG_INFO
<<"ILU_INTF: ingress_packet_handler begins...";
//sc_uint<D2P_IHB_ADDR_WDTH> ihb_wr_addr;
//sc_uint<D2P_IHB_ADDR_WDTH+1> nxt_ihb_wr_addr;
//sc_uint<D2P_IDB_ADDR_WDTH> idb_wr_addr;
//sc_uint<D2P_IDB_ADDR_WDTH> nxt_idb_wr_addr;
in_pkt_port
.get_packet(next_pkt
);
LOG_DEBUG
<< "Received Ingress Packet " << next_pkt
->to_string();
//cout<< sc_time_stamp() << " ILU_INTF: Received TLP " << next_pkt->getPacketId() << " from itl." << endl;
if(next_pkt
->get_control() == DROP_TLP_ILUINTF_RECOVER_CREDITS
){//indicates that the packet is to be dropped in here and credits are to be recovered
LOG_DEBUG
<<"Recvd pkt to be dropped";
LOG_DEBUG
<<"Recovering CHC/CDC...";
recovered_credits
.range(CHC
) = recovered_credits
.range(CHC
) + 1;
sc_uint
<12> cred
= (GET_TLP_LEN(next_pkt
))/4;
if((GET_TLP_LEN(next_pkt
))%4 != 0) cred
++;
recovered_credits
.range(CDC
) = recovered_credits
.range(CDC
) + cred
;
else if(next_pkt
->isPosted()){
LOG_DEBUG
<<"Recovering PHC/PDC...";
recovered_credits
.range(PHC
) = recovered_credits
.range(PHC
) + 1;
sc_uint
<12> cred
= (GET_TLP_LEN(next_pkt
))/4;
if((GET_TLP_LEN(next_pkt
))%4 != 0) cred
++;
recovered_credits
.range(PDC
) = recovered_credits
.range(PDC
) + cred
;
LOG_DEBUG
<<"Recovering NHC/NDC...";
recovered_credits
.range(NHC
) = recovered_credits
.range(NHC
) + 1;
sc_uint
<12> cred
= (GET_TLP_LEN(next_pkt
))/4;
if((GET_TLP_LEN(next_pkt
))%4 != 0) cred
++;
recovered_credits
.range(NDC
) = recovered_credits
.range(NDC
) + cred
;
ihb_wr_addr
= nxt_ihb_wr_addr
;
if(!drain_state
&& !POR_RESET
){
if (GET_TLP_FMT(next_pkt
) & 0x01) {
/// Load the Header into Header buffer
for (int byte
= 15, pkt_byte
=0; pkt_byte
< hdr_size
; byte
--, pkt_byte
++) {
ihb_buffer
[ihb_wr_addr
](byte
*8+7, byte
*8) =
next_pkt
->get_byte(TLP_HDR_START
+ pkt_byte
);
/// Calculate Header Parity
ihb_buffer
[ihb_wr_addr
][128] = parity(ihb_buffer
[ihb_wr_addr
](31,0).to_uint());
ihb_buffer
[ihb_wr_addr
][129] = parity(ihb_buffer
[ihb_wr_addr
](63,32).to_uint());
ihb_buffer
[ihb_wr_addr
][130] = parity(ihb_buffer
[ihb_wr_addr
](95,64).to_uint());
ihb_buffer
[ihb_wr_addr
][131] = parity(ihb_buffer
[ihb_wr_addr
](127,96).to_uint());
/// Polulate Data buffers, if data associated with the packet
if ((GET_TLP_FMT(next_pkt
) >> 1) &&
((next_pkt
->get_byte(TLP_HDR_START
) != tlp_IORd
) &&
(next_pkt
->get_byte(TLP_HDR_START
) != tlp_IOWr
) &&
(next_pkt
->get_byte(TLP_HDR_START
) != tlp_MRdLk_32
) &&
(next_pkt
->get_byte(TLP_HDR_START
) != tlp_MRdLk_64
) &&
(next_pkt
->get_byte(TLP_HDR_START
) != tlp_CfgRd0
) &&
(next_pkt
->get_byte(TLP_HDR_START
) != tlp_CfgRd1
) &&
(next_pkt
->get_byte(TLP_HDR_START
) != tlp_CfgWr0
) &&
(next_pkt
->get_byte(TLP_HDR_START
) != tlp_CfgWr1
) )
pld_len
= GET_TLP_LEN(next_pkt
);
idb_wr_len
= pld_len(9,2);
LOG_DEBUG
<< "Payload Length: " << pld_len
<< " IDB Write Len: " << idb_wr_len
;
int pkt_byte_ctr
= TLP_HDR_START
+hdr_size
;
for (int idb_ctr
= 0; idb_ctr
< idb_wr_len
; idb_ctr
++) {
idb_wr_addr
= nxt_idb_wr_addr
;
for (int byte
= 15; byte
>= 0; byte
--) {
idb_buffer
[idb_wr_addr
](byte
*8+7, byte
*8) =
next_pkt
->get_byte(pkt_byte_ctr
++);
idb_buffer
[idb_wr_addr
][128] =
parity(idb_buffer
[idb_wr_addr
](31,0).to_uint());
idb_buffer
[idb_wr_addr
][129] =
parity(idb_buffer
[idb_wr_addr
](63,32).to_uint());
idb_buffer
[idb_wr_addr
][130] =
parity(idb_buffer
[idb_wr_addr
](95,64).to_uint());
idb_buffer
[idb_wr_addr
][131] =
parity(idb_buffer
[idb_wr_addr
](127,96).to_uint());
if (pld_len(1,0).or_reduce()) {
idb_wr_addr
= nxt_idb_wr_addr
;
sc_uint
<32> idb_byte_cnt
= pld_len(1,0) * 4;
for (int byte
= 15; byte
> 15-(pld_len(1,0)*4); byte
--) {
idb_buffer
[idb_wr_addr
](byte
*8+7, byte
*8) =
next_pkt
->get_byte(pkt_byte_ctr
++);
idb_buffer
[idb_wr_addr
][128] =
parity(idb_buffer
[idb_wr_addr
](31,0).to_uint());
idb_buffer
[idb_wr_addr
][129] =
parity(idb_buffer
[idb_wr_addr
](63,32).to_uint());
idb_buffer
[idb_wr_addr
][130] =
parity(idb_buffer
[idb_wr_addr
](95,64).to_uint());
idb_buffer
[idb_wr_addr
][131] =
parity(idb_buffer
[idb_wr_addr
](127,96).to_uint());
WAIT(clk
.posedge_event());
p2d_ihb_wptr
.write(bin2gc(nxt_ihb_wr_addr
));
ihb_wptr
= bin2gc(nxt_ihb_wr_addr
);
else WAIT(clk
.posedge_event());
LOG_WARNING
<<"ILU_INTF: Out of ingress_packet_handler";
} // ingress_packet_handler()
* This thread build TLPs out of requests in the EHB and fwds them to the DLL.
* Parity errors are also checked for. If detected, Drain State is entered.
void ilu_intf::egress_packet_handler() {
/** EHB Interface Signals
LOG_INFO
<<"ILU_INTF: egress_packet_handler begins...";
sc_uint
<P2D_EHB_ADDR_WDTH
> erh_addr
;
sc_uint
<P2D_ERH_RPTR_WDTH
> erh_rptr
;
sc_uint
<P2D_ERH_RPTR_WDTH
> nxt_erh_rptr
;
sc_uint
<P2D_EHB_ADDR_WDTH
> ech_addr
;
sc_uint
<P2D_ECH_RPTR_WDTH
> ech_rptr
;
sc_uint
<P2D_ERH_RPTR_WDTH
> nxt_ech_rptr
;
sc_uint
<P2D_EHB_ADDR_WDTH
> ehb_addr
;
sc_uint
<D2P_EDB_ADDR_WDTH
-1> erd_rd_addr
;
sc_uint
<D2P_EDB_ADDR_WDTH
-1> ecd_rd_addr
;
sc_uint
<D2P_EDB_ADDR_WDTH
> edb_rd_addr
;
sc_biguint
<D2P_EHB_DATA_WDTH
> ehb_data
;
sc_uint
<D2P_EHB_DPAR_WDTH
> ehb_dpar
;
sc_biguint
<D2P_EDB_DATA_WDTH
> edb_data
;
sc_uint
<D2P_EDB_DPAR_WDTH
> edb_dpar
;
sc_uint
<PCIE_PLD_LEN_WDTH
> pld_len
;
sc_uint
<PCIE_PLD_LEN_WDTH
-1> edb_rd_len
;
erh_rptr
= bin2gc(erh_addr
);
nxt_erh_rptr
= bin2gc(erh_addr
);
ech_rptr
= bin2gc(ech_addr
);
WAIT(clk
.negedge_event());
if(!drain_state
&& !POR_RESET
){
nxt_erh_rptr
= d2p_erh_wptr
.read();
/// Check if the req empty
if (erh_rptr
!= nxt_erh_rptr
) {
ehb_addr
= erh_addr
| 0x20;
p2d_erh_rptr
.write(erh_rptr
);
LOG_DEBUG
<< " Processing Egress Request Header \n"
<< " ERH_ADDR : " << erh_addr
<< " ERH_RPTR : " << erh_rptr
<< " EHB_ADDR : " << ehb_addr
<< "\n"
<< "Next: ERH Addr: " << erh_addr
+1
<< " ERH Rptr: " << bin2gc(erh_addr
+1);
(ehb_dpar
, ehb_data
) = ehb_buffer
[ehb_addr
];
for (int dword
= 0; dword
< 4; dword
++) {
sc_uint
<32> dw_data
= (sc_uint
<32>) ehb_data(31+(dword
* 32), dword
* 32);
LOG_DEBUG
<< "dw_data: " << dw_data
<< " datapar: " << ehb_dpar
[dword
] << " calcpar: " <<parity(dw_data
);
if (ehb_dpar
[dword
] != parity(dw_data
)) {
LOG_ERROR
<< "Parity Error detected on DMU Request Header\n"
<< "Data: " << (string
) dw_data
.to_string()
<< " Parity: " << (int) parity(dw_data
);
write_error_csr(OE
,12,44,"ehp");
int hdr_size
= (ehb_data
[125] & 0x1) ? 16 : 12;
nxt_pkt
= NEW_TLP(hdr_size
);
nxt_pkt
->modify_byte(0, STP
);
LOG_DEBUG
<< " TLP Hdr Size " << hdr_size
;
for (int byte
= 15, pkt_byte
= 0;
data_byte
= ehb_data((byte
*8)+7, (byte
*8));
nxt_pkt
->modify_byte( TLP_HDR_START
+pkt_byte
,
if ((GET_TLP_FMT(nxt_pkt
) >> 1)) {
pld_len
= GET_TLP_LEN(nxt_pkt
);
edb_rd_len
= pld_len(9,2);
int pkt_byte_ctr
= TLP_HDR_START
+hdr_size
;
LOG_DEBUG
<< "Egress Request : Payload Length: " << pld_len
<< " EDB Read Len: " << edb_rd_len
;
nxt_pkt
->alloc_bytes(edb_rd_len
* 16 + (pld_len(1,0)*4));
for (int edb_ctr
= 0; edb_ctr
< edb_rd_len
; edb_ctr
++) {
while (erd_rd_addr
== erd_waddr
) {
WAIT(clk
.negedge_event());
edb_rd_addr
= (1,erd_rd_addr
);
p2d_erd_rptr
.write(bin2gc(edb_rd_addr
));
LOG_DEBUG
<< "TL: EDB Read Addr: " << edb_rd_addr
<< " ERD Rd Ptr: " << bin2gc(edb_rd_addr
);
(edb_dpar
, edb_data
) = edb_buffer
[edb_rd_addr
];
for (int dword
= 0; dword
< 4; dword
++) {
sc_uint
<32> dw_data
= (sc_uint
<32>) edb_data(31+(dword
* 32), dword
* 32);
LOG_DEBUG
<< "EBD: dw_data: " << dw_data
<< " datapar: " << edb_dpar
[dword
] << " calcpar: " <<parity(dw_data
);
if (edb_dpar
[dword
] != parity(dw_data
) && GET_TLP_EP(nxt_pkt
)!=1) {
LOG_ERROR
<< "Parity Error detected on DMU Request Data\n";
write_error_csr(OE
,13,45,"edp");
/// Load ERD Data to Packet
for (int byte
= 15; byte
>= 0; byte
--) {
data_byte
= (sc_uint
<8>) edb_data((byte
*8)+7, (byte
*8));
nxt_pkt
->modify_byte( pkt_byte_ctr
++, data_byte
);
if (pld_len(1,0).or_reduce()) {
while (erd_rd_addr
== erd_waddr
) {
WAIT(clk
.negedge_event());
edb_rd_addr
= (1,erd_rd_addr
);
p2d_erd_rptr
.write(bin2gc(edb_rd_addr
));
LOG_DEBUG
<< "TL: EDB Read Addr: " << edb_rd_addr
<< " ERD Rd Ptr: " << bin2gc(edb_rd_addr
);
(edb_dpar
, edb_data
) = edb_buffer
[edb_rd_addr
];
for (int dword
= 0; dword
< 4; dword
++) {
sc_uint
<32> dw_data
= (sc_uint
<32>) edb_data(31+(dword
* 32), dword
* 32);
LOG_DEBUG
<< "EBD: dw_data: " << dw_data
<< " datapar: " << edb_dpar
[dword
] << " calcpar: " <<parity(dw_data
);
if (edb_dpar
[dword
] != parity(dw_data
) && GET_TLP_EP(nxt_pkt
)!=1) {
LOG_ERROR
<< "Parity Error detected on DMU Request Data\n";
write_error_csr(OE
,13,45,"edp");
for (int byte
= 15; byte
>= 15-(pld_len(1,0)*4); byte
--) {
data_byte
= (sc_uint
<8>) edb_data((byte
*8)+7, (byte
*8));
nxt_pkt
->modify_byte( pkt_byte_ctr
++, data_byte
);
} // If Packet contains Data
nxt_pkt
->set_control(0x2);
LOG_DEBUG
<< "Sending Request Packet to DLL" << nxt_pkt
->to_string();
//cout << sc_time_stamp() << "\t\t\t\t\t| ILU_INTF: Sending Req TLP " << nxt_pkt->getPacketId() << " to ETL." << endl;
req_pkt_port
.send_packet(nxt_pkt
);
nxt_pkt
->set_control(0x12);
LOG_DEBUG
<< "Sending Request Packet to DLL" << nxt_pkt
->to_string();
//cout << sc_time_stamp() << "\t\t\t\t\t| ILU_INTF: Sending Req TLP " << nxt_pkt->getPacketId() << " to ETL." << endl;
req_pkt_port
.send_packet(nxt_pkt
);
erh_rptr
= bin2gc(erh_addr
);
} // If Req Hdr not empty
} else { // Completion arb
nxt_ech_rptr
= d2p_ech_wptr
.read();
/// Check if the req empty
if (ech_rptr
!= nxt_ech_rptr
) {
ehb_addr
= ech_addr
& 0x1F;
p2d_ech_rptr
.write(ech_rptr
);
LOG_DEBUG
<< " Processing Completion Header "
<< " ECH_ADDR : " << ech_addr
<< " ECH_RPTR : " << ech_rptr
<< " EHB_ADDR : " << ehb_addr
<< "\n"
<< "Next: ERH Addr: " << ech_addr
+1
<< " ERH Rptr: " << bin2gc(ech_addr
+1);
(ehb_dpar
, ehb_data
) = ehb_buffer
[ehb_addr
];
for (int dword
= 0; dword
< 4; dword
++) {
sc_uint
<32> dw_data
= (sc_uint
<32>) ehb_data(31+(dword
* 32), dword
* 32);
if (ehb_dpar
[dword
] != parity(dw_data
)) {
LOG_ERROR
<< "Parity Error detected on DMU Completion Header\n"
<< "Data: " << (string
) dw_data
.to_string()
<< " Parity: " << (int) parity(dw_data
);
write_error_csr(OE
,12,44,"ehp");
int hdr_size
= (ehb_data
[125] & 0x1) ? 16 : 12;
nxt_pkt
= NEW_TLP(hdr_size
);
nxt_pkt
->modify_byte(0, STP
);
LOG_DEBUG
<< " TLP Hdr Size " << hdr_size
;
for (int byte
= 15, pkt_byte
= 0;
data_byte
= ehb_data((byte
*8)+7, (byte
*8));
nxt_pkt
->modify_byte( TLP_HDR_START
+pkt_byte
, data_byte
);
if ((GET_TLP_FMT(nxt_pkt
) >> 1)) {
pld_len
= GET_TLP_LEN(nxt_pkt
);
edb_rd_len
= pld_len(9,2);
int pkt_byte_ctr
= TLP_HDR_START
+hdr_size
;
LOG_DEBUG
<< "Egress Completion Packet : Payload Length: " << pld_len
<< "EDB Read Len: " << edb_rd_len
;
nxt_pkt
->alloc_bytes(edb_rd_len
* 16 + (pld_len(1,0)*4));
for (int edb_ctr
= 0; edb_ctr
< edb_rd_len
; edb_ctr
++) {
while (ecd_rd_addr
== ecd_waddr
) {
WAIT(clk
.negedge_event());
edb_rd_addr
= (0,ecd_rd_addr
);
p2d_ecd_rptr
.write(bin2gc(edb_rd_addr
));
LOG_DEBUG
<< "TL: EDB Read Addr: " << edb_rd_addr
<< " ECD Rd Ptr: " << bin2gc(edb_rd_addr
);
(edb_dpar
, edb_data
) = edb_buffer
[edb_rd_addr
];
for (int dword
= 0; dword
< 4; dword
++) {
sc_uint
<32> dw_data
= (sc_uint
<32>) edb_data(31+(dword
* 32), dword
* 32);
if (edb_dpar
[dword
] != parity(dw_data
) && GET_TLP_EP(nxt_pkt
)!=1) {
LOG_ERROR
<< "Parity Error detected on DMU Request Data\n";
write_error_csr(OE
,13,45,"edp");
/// Load ECD Data to Packet
for (int byte
= 15; byte
>= 0; byte
--) {
data_byte
= (sc_uint
<8>) edb_data((byte
*8)+7, (byte
*8));
nxt_pkt
->modify_byte( pkt_byte_ctr
++, data_byte
);
if (pld_len(1,0).or_reduce()) {
while (ecd_rd_addr
== ecd_waddr
) {
WAIT(clk
.negedge_event());
edb_rd_addr
= (0,ecd_rd_addr
);
p2d_ecd_rptr
.write(bin2gc(edb_rd_addr
));
LOG_DEBUG
<< "TL: EDB Read Addr: " << edb_rd_addr
<< " ECD Rd Ptr: " << bin2gc(edb_rd_addr
);
(edb_dpar
, edb_data
) = edb_buffer
[edb_rd_addr
];
for (int dword
= 0; dword
< 4; dword
++) {
sc_uint
<32> dw_data
= (sc_uint
<32>) edb_data(31+(dword
* 32), dword
* 32);
if (edb_dpar
[dword
] != parity(dw_data
) && GET_TLP_EP(nxt_pkt
)!=1) {
LOG_ERROR
<< "Parity Error detected on DMU Request Data\n";
write_error_csr(OE
,13,45,"edp");
for (int byte
= 15; byte
>= 15-(pld_len(1,0)*4); byte
--) {
data_byte
= (sc_uint
<8>) edb_data((byte
*8)+7, (byte
*8));
nxt_pkt
->modify_byte( pkt_byte_ctr
++, data_byte
);
} // If Packet contains Data
nxt_pkt
->set_control(0x2);
LOG_DEBUG
<< "Sending Completion Packet to DLL" << nxt_pkt
->to_string();
//cout<< sc_time_stamp() << "\t\t\t\t\t| ILU_INTF: Sending Cpl TLP " << nxt_pkt->getPacketId() << " to ETL." << endl;
cmpl_pkt_port
.send_packet(nxt_pkt
);
nxt_pkt
->set_control(0x12);
LOG_DEBUG
<< "Sending Completion Packet to DLL" << nxt_pkt
->to_string();
//cout<< sc_time_stamp() << "\t\t\t\t\t| ILU_INTF: Sending Cpl TLP " << nxt_pkt->getPacketId() << " to ETL." << endl;
cmpl_pkt_port
.send_packet(nxt_pkt
);
ech_rptr
= bin2gc(ech_addr
);
} // If Req Hdr not empty
LOG_WARNING
<<"ILU_INTF: Out of egress_packet_handler";
* When interrupt enabled error bits are set in the OE, CE or UE CSRs, a corresponding interrupt
void ilu_intf::proc_ce_int() {
csr_port
.set_notify_event(PEU_CSR_A_CE_ERR_RW1C_ALIAS_HW_ADDR
, &ce_ev
);
ce_err
= csr_port
.read_csr(PEU_CSR_A_CE_ERR_RW1C_ALIAS_HW_ADDR
);
if ( (ce_err
& ce_int_en
) != 0) {
wait (clk
.posedge_event());
wait (clk
.posedge_event());
void ilu_intf::proc_ce_int_en() {
csr_port
.set_notify_event(PEU_CSR_A_CE_INT_EN_HW_ADDR
, &ce_en_ev
);
ce_int_en
= csr_port
.read_csr(PEU_CSR_A_CE_INT_EN_HW_ADDR
);
void ilu_intf::proc_ue_int() {
csr_port
.set_notify_event(PEU_CSR_A_UE_ERR_RW1C_ALIAS_HW_ADDR
, &ue_ev
);
ue_err
= csr_port
.read_csr(PEU_CSR_A_UE_ERR_RW1C_ALIAS_HW_ADDR
);
if ( (ue_err
& ue_int_en
) != 0) {
wait (clk
.posedge_event());
wait (clk
.posedge_event());
void ilu_intf::proc_ue_int_en() {
csr_port
.set_notify_event(PEU_CSR_A_UE_INT_EN_HW_ADDR
, &ue_en_ev
);
ue_int_en
= csr_port
.read_csr(PEU_CSR_A_UE_INT_EN_HW_ADDR
);
void ilu_intf::proc_oe_int() {
csr_port
.set_notify_event(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR
, &oe_ev
);
oe_err
= csr_port
.read_csr(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR
);
if ( (oe_err
& oe_int_en
) != 0) {
wait (clk
.posedge_event());
wait (clk
.posedge_event());
void ilu_intf::proc_oe_int_en() {
csr_port
.set_notify_event(PEU_CSR_A_OE_INT_EN_HW_ADDR
, &oe_en_ev
);
oe_int_en
= csr_port
.read_csr(PEU_CSR_A_OE_INT_EN_HW_ADDR
);
* This thread collects credits from the ILU and updates the Ingress Credits Allocated CSR.
void ilu_intf::ilu_credit_update_handler(){
sc_uint
<D2P_IBC_NHC_WDTH
> prev_nhc_cred
=0;
sc_uint
<D2P_IBC_PHC_WDTH
> prev_phc_cred
=0;
sc_uint
<D2P_IBC_PDC_WDTH
> prev_pdc_cred
=0;
wait(d2p_ibc_req
.posedge_event()|p2d_drain
.negedge_event());
sc_uint
<D2P_IBC_NHC_WDTH
> nhc_cred
= d2p_ibc_nhc
.read();
sc_uint
<D2P_IBC_PHC_WDTH
> phc_cred
= d2p_ibc_phc
.read();
sc_uint
<D2P_IBC_PDC_WDTH
> pdc_cred
= d2p_ibc_pdc
.read();
//LOG_DEBUG << "ILU_INTF: ilu_credit_update_handler: drain_state: " << drain_state << " nhc:" << nhc_cred << " phc:" << phc_cred << " pdc:" << pdc_cred;
//LOG_DEBUG << "ILU_INTF: p_nhc:" << prev_nhc_cred << " p_phc:" << prev_phc_cred << " p_pdc:" << prev_pdc_cred;
if(!drain_state
&& (nhc_cred
!=prev_nhc_cred
|| phc_cred
!=prev_phc_cred
|| pdc_cred
!=prev_pdc_cred
))
LOG_DEBUG
<< "ILU_INTF : IIL has sent IBC credit updates. ";
LOG_DEBUG
<< "NHC: " << nhc_cred
<< " PHC: " << phc_cred
<< " PDC: " << pdc_cred
;
sc_uint
<64> ica_reg
= csr_port
.read_csr(PEU_CSR_A_TLU_ICA_HW_ADDR
);
sc_uint
<64> ici_reg
= csr_port
.read_csr(PEU_CSR_A_TLU_ICI_HW_ADDR
);
ica_reg
.range(NHC
) = (sc_uint
<8>)(ici_reg(NHC
) + nhc_cred
+ recovered_credits(NHC
));
ica_reg
.range(PHC
) = (sc_uint
<8>)(ici_reg(PHC
) + phc_cred
+ recovered_credits(PHC
));
ica_reg
.range(PDC
) = (sc_uint
<12>)(ici_reg(PDC
) + pdc_cred
+ recovered_credits(PDC
));
csr_port
.write_csr(PEU_CSR_A_TLU_ICA_HW_ADDR
,ica_reg
);
prev_nhc_cred
= nhc_cred
;
prev_phc_cred
= phc_cred
;
prev_pdc_cred
= pdc_cred
;
WAIT(clk
.posedge_event());
WAIT(clk
.posedge_event());
WAIT(clk
.posedge_event());
WAIT(clk
.posedge_event());
WAIT(clk
.posedge_event());
WAIT(clk
.posedge_event());
LOG_WARNING
<<"ILU_INTF: ilu_credit_update_handler...ending clock wait";
if(RETRAIN_NO_RESET
) wait(clk
.posedge_event());
p2d_ibc_ack
.write(false);
* This thread forwards CMPL Timeout requests from the RSB to the ILU.
void ilu_intf::cto_req_handler(){
cto_req_port
->get(cto_req_tag
);
LOG_WARNING
<< "ILU_INTF: cto_req_handler recvd: " << cto_req_tag
;
p2d_cto_tag
.write(cto_req_tag
);
WAIT(d2p_cto_ack
.posedge_event());
WAIT(d2p_cto_ack
.negedge_event());
LOG_INFO
<< "ILU_INTF: CTO Req handling complete" ;
LOG_WARNING
<<"ILUT_INTF: cto req handler resetting...";
* This function updates the requested UE, CE and OE error bits.
void ilu_intf::write_error_csr(uint8 err_type
, uint8 primary
, uint8 secondary
, char field_name
[3]){
sc_uint
<64> orig_csr_val
;
sc_uint
<64> new_csr_val
=0;
LOG_DEBUG
<< "Setting err bit: " << field_name
;
case OE
: orig_csr_val
= csr_port
.read_csr(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR
);
LOG_DEBUG
<< "Updating OE CSR (orig val: " << orig_csr_val
<< ")";
case UE
: orig_csr_val
= csr_port
.read_csr(PEU_CSR_A_UE_ERR_RW1C_ALIAS_HW_ADDR
);
LOG_DEBUG
<< "Updating UE CSR (orig val: " << orig_csr_val
<< ")";
case CE
: orig_csr_val
= csr_port
.read_csr(PEU_CSR_A_CE_ERR_RW1C_ALIAS_HW_ADDR
);
LOG_DEBUG
<< "Updating CE CSR (orig val: " << orig_csr_val
<< ")";
default: LOG_ERROR
<< "Warning: undefined error type!";
case OE
: log_enable
= csr_port
.read_csr(PEU_CSR_A_OE_LOG_HW_ADDR
);
LOG_DEBUG
<< "OE Log enable : " << log_enable
<< ")";
case UE
: log_enable
= csr_port
.read_csr(PEU_CSR_A_UE_LOG_HW_ADDR
);
LOG_DEBUG
<< "UE Log Enable : " << log_enable
<< ")";
case CE
: log_enable
= csr_port
.read_csr(PEU_CSR_A_CE_LOG_HW_ADDR
);
LOG_DEBUG
<< "CE Log Enable : " << log_enable
<< ")";
if(log_enable
.range(primary
,primary
)==1)
if(orig_csr_val
.range(primary
,primary
)!=1)
new_csr_val
.range(primary
,primary
)=1;
else if(orig_csr_val
.range(secondary
,secondary
)!=1)
new_csr_val
.range(secondary
,secondary
)=1;
LOG_DEBUG
<< "Warning: Both PRIMARY and SECONDARY of " << field_name
<< "are set.";
case OE
: csr_port
.write_csr(PEU_CSR_A_OE_ERR_RW1S_ALIAS_HW_ADDR
,new_csr_val
);
LOG_DEBUG
<< "Updating OE CSR (new val : " << new_csr_val
<< ")";
case UE
: csr_port
.write_csr(PEU_CSR_A_UE_ERR_RW1S_ALIAS_HW_ADDR
,new_csr_val
);
LOG_DEBUG
<< "Updating UE CSR (new val : " << new_csr_val
<< ")";
case CE
: csr_port
.write_csr(PEU_CSR_A_CE_ERR_RW1S_ALIAS_HW_ADDR
,new_csr_val
);
LOG_DEBUG
<< "Updating CE CSR (new val : " << new_csr_val
<< ")";
* Updates to the Max Payload Size ILU port are reflected into the corresponding CSR.
void ilu_intf::mps_handler() {
csr_port
.set_notify_event(PEU_CSR_A_DEV_CTL_HW_ADDR
, &dev_ctl_ev
);
dev_ctl
= csr_port
.read_csr(PEU_CSR_A_DEV_CTL_HW_ADDR
);
LOG_DEBUG
<< "P2D MPS: " << dev_mps
<< " Device Ctrl Reg: " << dev_ctl
;
LOG_DEBUG
<< "P2D MPS: " << dev_mps
<< " Device Ctrl Reg: " << dev_ctl
<< " written";
* This thread handles entry and exit of the model from 'drain state'.
void ilu_intf::drain_handler(){
sc_event csr_core_status_ev
,csr_tlu_status_ev
,csr_lnk_ctl_ev
;
csr_port
.set_notify_event(PEU_CSR_A_CORE_STATUS_HW_ADDR
,&csr_core_status_ev
);
csr_port
.set_notify_event(PEU_CSR_A_TLU_STS_HW_ADDR
,&csr_tlu_status_ev
);
csr_port
.set_notify_event(PEU_CSR_A_LINK_CTL_HW_ADDR
,&csr_lnk_ctl_ev
);
LOG_DEBUG
<<"++++++++++ ILU_INTF: Signaling DRAIN STATE to ILU ++++++++++";
if(csr_port
.read_csr(ILU_CSR_A_ILU_LOG_ERR_RW1S_ALIAS_HW_ADDR
).range(4,4)!=1){
//Setting drain bit in PEU Status CSR
csr_port
.write_csr_mask(PEU_CSR_A_TLU_STS_HW_ADDR
,(0x1 << 8),PEU_CSR_TLU_STS_SET_MASK
);
*parent_global_event_type
= SW_RESET_ENTER
; //This state is needed to ensure timers are stopped and to keep updatefcs sent...
notify(*parent_global_event
);
if(csr_port
.read_csr(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR
).range(9,9)!=1){
while((csr_port
.read_csr(PEU_CSR_A_LINK_CTL_HW_ADDR
)).range(0,0)!=0x1) wait(csr_lnk_ctl_ev
);
LOG_INFO
<<"ILU_INTF: Reset-assert bit is set...";
//Setting retrain bit in Link Ctrl CSR
sc_uint
<64> lnk_ctrl_reg
= csr_port
.read_csr(PEU_CSR_A_LNK_CTL_HW_ADDR
);
csr_port
.write_csr(PEU_CSR_A_LNK_CTL_HW_ADDR
,lnk_ctrl_reg
);
while((csr_port
.read_csr(PEU_CSR_A_CORE_STATUS_HW_ADDR
)).range(48,44)!=0x0D) wait(csr_core_status_ev
);
LOG_WARNING
<<"ILU_INTF: PEU now in Recovery...";
wait(rst_l
.negedge_event()|csr_tlu_status_ev
);
LOG_WARNING
<<"ILU_INTF: PEU now receives RESET_L...";
if(csr_port
.read_csr(PEU_CSR_A_TLU_STS_HW_ADDR
).range(8,8)==0){
//cout << "=== ILU_INTF: SW has cleared drain-state bit ===" << endl;
sc_uint
<D2P_IHB_ADDR_WDTH
> prev_ihb_wr_addr
= ihb_wr_addr
;
sc_uint
<D2P_IHB_ADDR_WDTH
+1> prev_nxt_ihb_wr_addr
= nxt_ihb_wr_addr
;
sc_uint
<D2P_IDB_ADDR_WDTH
> prev_idb_wr_addr
= idb_wr_addr
;
sc_uint
<D2P_IDB_ADDR_WDTH
+1> prev_nxt_idb_wr_addr
= nxt_idb_wr_addr
;
*parent_global_event_type
= SW_RESET_EXIT
;
notify(*parent_global_event
);
*parent_global_event_type
= WMR_RESET_ENTER
;
notify(*parent_global_event
);
*parent_global_event_type
= SW_RESET_CHNL_EXIT
;
notify(*parent_global_event
);
*parent_global_event_type
= WMR_RESET_EXIT
;
notify(*parent_global_event
);
ihb_wr_addr
= prev_ihb_wr_addr
;
nxt_ihb_wr_addr
= prev_nxt_ihb_wr_addr
;
p2d_ihb_wptr
.write(bin2gc(nxt_ihb_wr_addr
));
idb_wr_addr
= prev_idb_wr_addr
;
nxt_idb_wr_addr
= prev_nxt_idb_wr_addr
;
*parent_global_event_type
= SW_RESET_EXIT
;
notify(*parent_global_event
);
*parent_global_event_type
= WMR_RESET_ENTER
;
notify(*parent_global_event
);
sc_uint
<D2P_IHB_ADDR_WDTH
> ihb_wr_addr
=0;
p2d_ihb_wptr
.write(bin2gc(ihb_wr_addr
));
*parent_global_event_type
= SW_RESET_CHNL_EXIT
;
notify(*parent_global_event
);
wait(rst_l
.posedge_event());
*parent_global_event_type
= WMR_RESET_EXIT
;
notify(*parent_global_event
);
* This thread monitors the 'link down' event. This event puts the model into 'drain state'
void ilu_intf::pl_drain_catcher(){
csr_port
.set_notify_event(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR
,&csr_status_ev
);
if(!drain_state
&& csr_port
.read_csr(PEU_CSR_A_OE_ERR_RW1C_ALIAS_HW_ADDR
).range(9,9)==1) {
LOG_WARNING
<<"ILU_INTF: LINK DOWN...Entering DRAIN state";
* This method initializes module registers and flags.
* It also spawns threads that handle module operation.
sc_uint
<P2D_EHB_ADDR_WDTH
> erh_addr
;
p2d_erh_rptr
.write(bin2gc(erh_addr
));
sc_uint
<P2D_EHB_ADDR_WDTH
> ech_addr
;
p2d_ech_rptr
.write(bin2gc(ech_addr
));
p2d_ihb_wptr
.write(bin2gc(ihb_wr_addr
));
ihb_wptr
= bin2gc(ihb_wr_addr
);
ingress_packet_handler_ph
= sc_spawn(sc_bind(&ilu_intf::ingress_packet_handler
,this));
egress_packet_handler_ph
= sc_spawn(sc_bind(&ilu_intf::egress_packet_handler
,this));
LOG_INFO
<<"ILU_INTF: threads spawned...";
* This thread handles reset behavior of the module. On the arrival of a reset global event,
* it issues termination requests to threads in this module. Following the reset exit global event
* it invokes init() to re-spawn terminated threads.
void ilu_intf::reset_handler(){
wait(*parent_global_event
);
switch(*parent_global_event_type
){
//Wait for all thread to terminate
if(ingress_packet_handler_ph
.terminated() && egress_packet_handler_ph
.terminated()) break;
wait(ingress_packet_handler_ph
.terminated_event()|egress_packet_handler_ph
.terminated_event());
LOG_WARNING
<< "ILU_INTF: WMR/POR Reset threads terminated" ;
LOG_WARNING
<< "ILU_INTF: WMR/POR Reset dbs cleared" ;
LOG_INFO
<<"ILU_INTF: WMR/POR Reset exit";
* This thread monitors the 'ihb parity error' event. This event puts the model into 'drain state'
void ilu_intf::ilu_drain_catcher(){
sc_event ilu_err_rw1s_ev
;
csr_port
.set_notify_event(ILU_CSR_A_ILU_LOG_ERR_RW1S_ALIAS_HW_ADDR
,&ilu_err_rw1s_ev
);
if(!drain_state
&& csr_port
.read_csr(ILU_CSR_A_ILU_LOG_ERR_RW1S_ALIAS_HW_ADDR
).range(4,4)==1) {
LOG_WARNING
<<"ILU_INTF: ILU has detected a parity error...Entering DRAIN state";