Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / model / pcie / tl / etl.cpp
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: etl.cpp
4// Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
5// 4150 Network Circle, Santa Clara, California 95054, U.S.A.
6//
7// * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8//
9// This program is free software; you can redistribute it and/or modify
10// it under the terms of the GNU General Public License as published by
11// the Free Software Foundation; version 2 of the License.
12//
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21//
22// For the avoidance of doubt, and except that if any non-GPL license
23// choice is available it will apply instead, Sun elects to use only
24// the General Public License version 2 (GPLv2) at this time for any
25// software where a choice of GPL license versions is made
26// available with the language indicating that GPLv2 or any later version
27// may be used, or where a choice of which version of the GPL is applied is
28// otherwise unspecified.
29//
30// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
31// CA 95054 USA or visit www.sun.com if you need additional information or
32// have any questions.
33//
34// ========== Copyright Header End ============================================
35#include "etl.hpp"
36#include "pcie_common/logger.hpp"
37
38namespace pcie {
39
40 /**
41 * This method initializes module registers and flags.
42 * It also spawns threads that handle module operation.
43 */
44 void etl::init(){
45 POR_RESET = false;
46 execute_ph = sc_spawn(sc_bind(&etl::execute,this));
47 req_handler_ph = sc_spawn(sc_bind(&etl::req_handler,this));
48 cmpl_handler_ph = sc_spawn(sc_bind(&etl::cmpl_handler,this));
49 ecl_update_ph = sc_spawn(sc_bind(&etl::ecl_update,this));
50 LOG_INFO << "ETL: SW Reset : threads spawned";
51 }
52
53 /**
54 * This thread forwards TLPs in the egress_q to DLL. Non-posted requests are also
55 * forwarded to the RSB.
56 */
57 void etl::execute(void) {
58 LOG_INFO<<"ETL: execute begin...";
59 ecc=0;
60 csr_port.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR, ecc);
61 RefPciePacket next_pkt;
62 try{
63 while(1){
64 while (!egress_q.empty()){
65 next_pkt = egress_q.front();
66 egress_q.pop();
67
68 LOG_INFO << "ETL: Send Packet " << next_pkt->getPacketId() << "\n";
69 //cout << sc_time_stamp() << "\t\t\t\t\t| ETL: Send Packet " << next_pkt->getPacketId() << " to DLL." << endl;
70 if((!next_pkt->isPosted()) && (!next_pkt->isCmpl()))
71 eg_etl_rsb_port.send_packet(next_pkt);
72 dout_port.send_packet(next_pkt);
73 }
74 WAIT(epktRdy_ev);
75 } //end while(1)
76 }//end try
77 catch(sc_exception &e){
78 LOG_WARNING << "ETL: Out of execute";
79 }
80 }//end execute()
81
82 /**
83 * This thread receives TLPs from the ILU interface and enqueues them into
84 * the egress_q, once credit is available.
85 */
86 void etl::req_handler() {
87 LOG_INFO<<"ETL: req_handler begin...";
88 RefPciePacket new_pkt;
89 try{
90 while (1) {
91 req_port.get_packet(new_pkt);
92 //cout<< sc_time_stamp() <<"\t\t\t\t\t| ETL: Recvd Req TLP " <<new_pkt->getPacketId() << " from ilu_intf" <<endl;
93 if (new_pkt->isPosted())
94 get_p_credit(new_pkt);
95 else
96 get_np_credit(new_pkt);
97 egress_q.push(new_pkt);
98 epktRdy_ev.notify();
99 }
100 }
101 catch(sc_exception &e){
102 LOG_WARNING << "ETL: Out of req_handler";
103 }
104 }
105
106 /**
107 * This thread receives CMPL TLPs from the ILU interface and enqueues them into
108 * the egress_q, once credit is available.
109 */
110 void etl::cmpl_handler() {
111 LOG_INFO<<"ETL: cmpl_handler begins...";
112 try{
113 RefPciePacket new_pkt;
114 while (1) {
115 cmpl_port.get_packet(new_pkt);
116 //cout<< sc_time_stamp() <<"\t\t\t\t\t| ETL: Recvd Cpl TLP " <<new_pkt->getPacketId() << " from ilu_intf" <<endl;
117 get_cmpl_credit(new_pkt);
118 egress_q.push(new_pkt);
119 epktRdy_ev.notify();
120 }
121 }
122 catch(sc_exception &e){
123 LOG_WARNING << "ETL: Out of cmpl_handler";
124 }
125 }
126
127 /**
128 * This thread monitors the egress credit limit CSR register and provides updates
129 * to any waiting out-going TLPs.
130 */
131 void etl::ecl_update() {
132 LOG_INFO << "ETL: ecl_update begins...";
133 try{
134 while (1) {
135 WAIT(ecl_ev);
136 ecl = csr_port.read_csr(PEU_CSR_A_TLU_ECL_HW_ADDR);
137 ecl_event.notify();
138 }
139 }
140 catch(sc_exception &e){
141 LOG_WARNING << "ETL: Out of ecl_update";
142 }
143 }
144
145 /**
146 * This blocking thread waits for available posted credits for out-going TLPs.
147 */
148 void etl::get_p_credit(RefPciePacket& p) {
149 bool hcAvail = false;
150 bool dcAvail = false;
151 sc_uint<12> cred = (GET_TLP_LEN(p))/4;
152 if((GET_TLP_LEN(p))%4 != 0) cred++;
153
154 while(1){
155 ecc = csr_port.read_csr(PEU_CSR_A_TLU_ECC_HW_ADDR);
156 if(ecc[60] == 0x1)
157 hcAvail = true;
158 else if(ecc(19,12)==ecl(19,12))
159 hcAvail = false;
160 else
161 hcAvail = true;
162
163 if(p->hasData()){
164 if(ecl[60] == 0x1)
165 dcAvail = true;
166 else if( (ecl(11,0)-((sc_uint<12>)ecc(11,0)+cred)) %4096 > 2048 )
167 dcAvail=false;
168 else
169 dcAvail = true;
170 }
171 else
172 dcAvail=true;
173
174 if(hcAvail && dcAvail){
175 ecc(19,12) = (sc_uint<8>)ecc(19,12) + 1;
176 if(p->hasData()) ecc(11,0) = (sc_uint<12>)ecc(11,0) + cred;
177 if(p->hasData())
178 LOG_DEBUG << "ETL: PH consumed (+1) = " << ecc(19,12) << " PD consumed (+" << cred << ") = " << ecc(11,0) ;
179 else
180 LOG_DEBUG << "ETL: PH consumed (+1) = " << ecc(19,12) << " PD consumed (+0) = " << ecc(11,0) ;
181 csr_port.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR, ecc);
182 break;
183 }
184 WAIT(ecl_event);
185 }
186 return;
187 }//end get_p_credit
188
189 /**
190 * This blocking thread waits for available non-posted credits for out-going TLPs.
191 */
192 void etl::get_np_credit(RefPciePacket& p) {
193 bool hcAvail = false;
194 bool dcAvail = false;
195 sc_uint<12> cred = (GET_TLP_LEN(p))/4;
196 if((GET_TLP_LEN(p))%4 != 0) cred++;
197
198 while(1){
199 ecc = csr_port.read_csr(PEU_CSR_A_TLU_ECC_HW_ADDR);
200 if(ecc[61] == 0x1)
201 hcAvail = true;
202 else if(ecc(39,32)==ecl(39,32))
203 hcAvail = false;
204 else
205 hcAvail = true;
206
207 if(p->hasData()){
208 if(ecl[61] == 0x1)
209 dcAvail = true;
210 else if( (ecl(31,20)-((sc_uint<12>)ecc(31,20)+cred)) %4096 > 2048 )
211 dcAvail=false;
212 else
213 dcAvail = true;
214 }
215 else
216 dcAvail=true;
217
218 if(hcAvail && dcAvail){
219 ecc(39,32) = (sc_uint<8>)ecc(39,32) + 1;
220 if(p->hasData()) ecc(31,20) = (sc_uint<12>)ecc(31,20) + cred;
221 if(p->hasData())
222 LOG_DEBUG << "ETL: NPH consumed (+1) = " << ecc(39,32) << " NPD consumed (+" << cred << ") = " << ecc(31,20) ;
223 else
224 LOG_DEBUG << "ETL: NPH consumed (+1) = " << ecc(39,32) << " NPD consumed (+0) = " << ecc(31,20) ;
225 csr_port.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR, ecc);
226 break;
227 }
228 WAIT(ecl_event);
229 }
230 return;
231 }//end get_np_credit
232
233 /**
234 * This blocking thread waits for available cmpl credits for out-going TLPs.
235 */
236 void etl::get_cmpl_credit(RefPciePacket& p) {
237 bool hcAvail = false;
238 bool dcAvail = false;
239 sc_uint<12> cred = (GET_TLP_LEN(p))/4;
240 if((GET_TLP_LEN(p))%4 != 0) cred++;
241
242 while(1){
243 ecc = csr_port.read_csr(PEU_CSR_A_TLU_ECC_HW_ADDR);
244 if(ecc[62] == 0x1)
245 hcAvail = true;
246 else if(ecc(59,52)==ecl(59,52))
247 hcAvail = false;
248 else
249 hcAvail = true;
250
251 if(p->hasData()){
252 if(ecl[62] == 0x1)
253 dcAvail = true;
254 else if( (ecl(51,40)-((sc_uint<12>)ecc(51,40)+cred)) %4096 > 2048 )
255 dcAvail=false;
256 else
257 dcAvail = true;
258 }
259 else
260 dcAvail=true;
261
262 if(hcAvail && dcAvail){
263 ecc(59,52) = (sc_uint<8>)ecc(59,52) + 1;
264 if(p->hasData()) ecc(51,40) = (sc_uint<12>)ecc(51,40) + cred;
265 if(p->hasData())
266 LOG_DEBUG << "ETL: CH consumed (+1) = " << ecc(59,52) << " CD consumed (+" << cred << ") = " << ecc(51,40) ;
267 else
268 LOG_DEBUG << "ETL: CH consumed (+1) = " << ecc(59,52) << " CD consumed (+0) = " << ecc(51,40) ;
269 csr_port.write_csr(PEU_CSR_A_TLU_ECC_HW_ADDR, ecc);
270 break;
271 }
272 WAIT(ecl_event);
273 }
274 return;
275 }//end get_cmpl_credit
276
277 /**
278 * This thread handles reset behavior of the module. On the arrival of a reset global event,
279 * it issue termination requests to threads in this module. Following the reset exit global event
280 * it invokes init() to re-spawn terminated threads.
281 */
282 void etl::reset_handler(){
283 csr_port.set_notify_event(PEU_CSR_A_TLU_ECL_HW_ADDR, &ecl_ev);
284 while(1){
285 wait(*parent_global_ev);
286 switch(*global_event_type){
287 case POR_RESET_ENTER:
288 case WMR_RESET_ENTER:
289 LOG_WARNING << "\tETL: WMR/POR_RESET enter signal...";
290 POR_RESET=true;
291 reset_ev.notify();
292 while(1){
293 if(execute_ph.terminated() && req_handler_ph.terminated() && cmpl_handler_ph.terminated() && ecl_update_ph.terminated()) break;
294 wait(execute_ph.terminated_event()|req_handler_ph.terminated_event()|cmpl_handler_ph.terminated_event()|ecl_update_ph.terminated_event());
295 }
296 LOG_WARNING << "ETL: WMR/POR Reset threads terminated";
297 while(!egress_q.empty()) egress_q.pop();
298 LOG_INFO << "ETL: WMR/POR Reset dbs cleared";
299 break;
300
301 case POR_RESET_EXIT:
302 case WMR_RESET_EXIT:
303 POR_RESET=false;
304 LOG_INFO << "\tETL: WMR/POR_RESET exit signal...";
305 init();
306 break;
307 }
308 } //end while(1)
309 }//end reset_handler()
310}