Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: ccxDevSpcBFM.vr | |
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 <vera_defines.vrh> | |
36 | ||
37 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
38 | // To use this class, you must have in your bench a files called globals.vri | |
39 | // that has all global extern declerations in it. | |
40 | #include <globals.vri> | |
41 | ||
42 | #include <ccxDevicesDefines.vri> | |
43 | #include <std_display_defines.vri> | |
44 | ||
45 | #include <std_display_class.vrh> | |
46 | #include <basePktClass.vrh> | |
47 | #include <cpxPktClass.vrh> | |
48 | #include <pcxPktClass.vrh> | |
49 | #include <baseParamsClass.vrh> | |
50 | #include <sparcParams.vrh> | |
51 | #include <ccxDevBaseBFM.vrh> | |
52 | ||
53 | ||
54 | #define CLASSNAME CcxDevSpcBFM | |
55 | #define CLASSNAMEQ "CcxDevSpcBFM" | |
56 | ||
57 | class CLASSNAME extends CcxDevBaseBFM { | |
58 | ||
59 | // methods | |
60 | task new(integer instatnce, reg passiveIn=0, reg flagUnexpected=0, reg ccxOnly=0); | |
61 | // virtual in base | |
62 | task recv(BasePkt pktHndl); | |
63 | task cancelRecv(BasePkt pktHndl); | |
64 | task sendIntr(reg [5:0] tid, | |
65 | reg [1:0] type, | |
66 | reg [5:0] vect); | |
67 | local task slave(); | |
68 | } | |
69 | ||
70 | ||
71 | task CLASSNAME::new (integer instatnce, reg passiveIn=0, | |
72 | reg flagUnexpected=0, reg ccxOnly=0) { | |
73 | ||
74 | super.new(instatnce,passiveIn,CLASSNAMEQ); | |
75 | super.flagUnexpected = flagUnexpected; | |
76 | ccxOnly = ccxOnly; // only testing ccx | |
77 | srandom(gSeed,this); | |
78 | ||
79 | if (!passiveIn) { | |
80 | // Initialize Outputs | |
81 | gPcxPort[myPort].$req = 0; | |
82 | gPcxPort[myPort].$atmo = 0; | |
83 | gPcxPort[myPort].$datao = 0; | |
84 | } | |
85 | ||
86 | ||
87 | // fork { | |
88 | // monitor(); | |
89 | // } join none | |
90 | ||
91 | ||
92 | fork { | |
93 | @(posedge gPcxPort[myPort].$clk); | |
94 | gPcxPort[myPort].$gnt == 0; | |
95 | gCpxPort[myPort].$datai == 0; | |
96 | } join none | |
97 | ||
98 | ||
99 | // as a slave, we listen to one of two crossbars | |
100 | fork slave(); | |
101 | join none | |
102 | ||
103 | // service mailboxes, send packets | |
104 | fork super.serviceSends2(PP_PCX); | |
105 | join none | |
106 | ||
107 | } | |
108 | ||
109 | ||
110 | ||
111 | // use to receive an expected packet. | |
112 | // mainly for CCX testing. | |
113 | // | |
114 | // user passes in a packet who's fields are set to match the | |
115 | // packet that should show up at this port. When it does, the | |
116 | // caller is notified (toggle a var in the passed in packet) and | |
117 | // the passed in packet will be populated with what showed up at the | |
118 | // destinatin port. Unexpected (not registered via a call to this task) | |
119 | // packets will cause failure (if enabled). | |
120 | task CLASSNAME::recv(BasePkt pktHndl) { | |
121 | ||
122 | //CpxPkt cpxPkt; | |
123 | ||
124 | // assign/cast pktHndl to be of PcxPkt type rather than base | |
125 | //cast_assign(cpxPkt,pktHndl); | |
126 | ||
127 | // load signature hash. key is "signature" and data is handle. | |
128 | expectedSig[pktHndl.signature] = pktHndl; | |
129 | ||
130 | } | |
131 | ||
132 | // Mainly for CCX testing. Call when a pkt should no longer arrive. | |
133 | // For CCX, a pkt should never intentionally get dropped so this may not get used. | |
134 | task CLASSNAME::cancelRecv(BasePkt pktHndl) { | |
135 | ||
136 | //CpxPkt cpxPkt; | |
137 | ||
138 | // assign/cast pktHndl to be of PcxPkt type rather than base | |
139 | //cast_assign(cpxPkt,pktHndl); | |
140 | ||
141 | // clear signature hash. | |
142 | //void = assoc_index(DELETE,expectedSig,pcxPkt.getVector()); | |
143 | void = assoc_index(DELETE,expectedSig,pktHndl.signature); | |
144 | ||
145 | } | |
146 | ||
147 | ||
148 | ||
149 | // Wait for data from CPX, we are a SPC | |
150 | task CLASSNAME::slave() { | |
151 | ||
152 | CpxPkt pktHndl; | |
153 | ccxPort portVar = gCpxPort[myPort]; | |
154 | integer second = 0; | |
155 | reg [145:0] tmpVec; | |
156 | ||
157 | // if (!passive) { | |
158 | ||
159 | while (1) { | |
160 | if (portVar.$datai[145] == 0) @(posedge portVar.$datai[145]); | |
161 | pktHndl = new(); | |
162 | pktHndl.loadPkt(portVar.$datai, myPort); | |
163 | pktHndl.ccxSourced = 1; | |
164 | ||
165 | // anyone waiting for this packet? | |
166 | // was it expected? | |
167 | tmpVec = pktHndl.makeSignature(); | |
168 | if (assoc_index(CHECK, expectedSig, tmpVec)) { | |
169 | expectedSig[tmpVec].loadPkt(pktHndl.getVector(), myPort); | |
170 | expectedSig[tmpVec].arrivalTime = get_cycle(); | |
171 | expectedSig[tmpVec].pktArrived = ~expectedSig[tmpVec].pktArrived; | |
172 | } else if (flagUnexpected) { | |
173 | pktHndl.print(myPort); | |
174 | PR_ERROR(CLASSNAMEQ, MON_ERROR, | |
175 | psprintf ("Unexpected packet on port %0d, vector=%h",myPort,pktHndl.getVector())); | |
176 | } | |
177 | ||
178 | // do something | |
179 | @(negedge portVar.$clk); | |
180 | } | |
181 | ||
182 | // while (1) { | |
183 | // @(negedge portVar.$clk); | |
184 | // if (portVar.$datai[145] == 1) { | |
185 | // pktHndl = new(); | |
186 | // pktHndl.loadPkt(portVar.$datai, myPort); | |
187 | // pktHndl.ccxSourced = 1; | |
188 | // //if (gParam.ccxPktPrint[PP_CPX] || gParam.ccxPktPrint[PP_SPC]) pktHndl.print(myPort); | |
189 | // } | |
190 | // } | |
191 | ||
192 | ||
193 | ||
194 | // while (1) { | |
195 | // @(posedge portVar.$datai[145]); | |
196 | // pktHndl = new(); | |
197 | // pktHndl.loadPkt(portVar.$datai, myPort); | |
198 | // if (gParam.ccxPktPrint[PP_CPX] || gParam.ccxPktPrint[PP_SPC]) pktHndl[second].print(myPort); | |
199 | // | |
200 | // // deal with 2 ifill return pkts | |
201 | // if (pktHndl[second].rtntyp == CPX_IFILL && | |
202 | // pktHndl[second].wayf4b == 0) { | |
203 | // second++; | |
204 | // @(negedge portVar.$clk); | |
205 | // pktHndl[second] = new(); | |
206 | // pktHndl[second].loadPkt(portVar.$datai, myPort); | |
207 | // if (gParam.ccxPktPrint[PP_CPX] || gParam.ccxPktPrint[PP_SPC]) pktHndl[second].print(myPort); | |
208 | // } | |
209 | // | |
210 | // @(negedge portVar.$datai[145]); | |
211 | // second = 0; | |
212 | // | |
213 | // // print? | |
214 | // //printf("\n%0d CcxDevSpcBFM::slavePcx got packet!\n", get_cycle()); | |
215 | // | |
216 | // //pktHndl.printPkt(); | |
217 | // | |
218 | // // anyone waiting for this packet? | |
219 | // // was it expected? review | |
220 | // | |
221 | // } // while | |
222 | ||
223 | // } | |
224 | } | |
225 | ||
226 | ||
227 | ||
228 | ||
229 | // // monitor real devices initiations when we are passive on the bus. | |
230 | // task CLASSNAME::monitor() { | |
231 | // | |
232 | // ccxPort portVar = gPcxPort[myPort]; | |
233 | // ccxPort portVarC = gCpxPort[myPort]; | |
234 | // CpxPkt pktHndlC; | |
235 | // reg [9:0] atm,req; | |
236 | // integer i; | |
237 | // | |
238 | // if (gParam.ccxPktPrint[PP_PCX] || | |
239 | // gParam.ccxPktPrint[PP_SPC] || | |
240 | // gParam.ccxPktPrint[PP_TRG] || | |
241 | // gParam.ccxPktPrintMask[myPort]) { | |
242 | // | |
243 | // while (get_cycle() < 3) @(posedge CLOCK); | |
244 | // | |
245 | // pktHndlC = new(); | |
246 | // | |
247 | // // monitor SPC out going requests. | |
248 | // if (gParam.ccxPktPrint[PP_PCX] || | |
249 | // gParam.ccxPktPrint[PP_SPC] || | |
250 | // gParam.ccxPktPrintMask[myPort]) { | |
251 | // fork | |
252 | // { | |
253 | // // monitor SPC out going requests. | |
254 | // // need to detect req changing back to zero here. | |
255 | // while (1) { | |
256 | // | |
257 | // if (!portVar.$req) { | |
258 | // @(portVar.$req); | |
259 | // req = portVar.$req; | |
260 | // if (portVar.$atmo) { | |
261 | // i = 2; | |
262 | // atm = portVar.$atmo; | |
263 | // } else { | |
264 | // i = 1; | |
265 | // atm = 0; | |
266 | // } | |
267 | // } | |
268 | // | |
269 | // repeat (i) { | |
270 | // // need to fork off to handle streaming/ back to back packets | |
271 | // { | |
272 | // PcxPkt pktHndl = new(); // keep in block | |
273 | // fork { | |
274 | // pktHndl.atm_wire = atm; | |
275 | // pktHndl.req_wire = req; | |
276 | // @(negedge portVar.$clk); | |
277 | // pktHndl.loadPkt(portVar.$datao, myPort); | |
278 | // // if (gParam.ccxPktPrint[PP_PCX] || | |
279 | // // gParam.ccxPktPrint[PP_SPC] || | |
280 | // // gParam.ccxPktPrintMask[myPort]) | |
281 | // pktHndl.print(myPort); | |
282 | // } join none | |
283 | // } | |
284 | // @(negedge portVar.$clk); | |
285 | // }// rep | |
286 | // } // while | |
287 | // } join none | |
288 | // } | |
289 | // | |
290 | // fork | |
291 | // { | |
292 | // // monitor SPC incomming packets/responses | |
293 | // if (gParam.ccxPktPrint[PP_CPX] || | |
294 | // gParam.ccxPktPrint[PP_SPC] || | |
295 | // gParam.ccxPktPrint[PP_TRG] || | |
296 | // gParam.ccxPktPrintMask[myPort]) { | |
297 | // | |
298 | // while (1) { | |
299 | // if (portVarC.$datai[145] == 0) @(posedge portVarC.$datai[145]); | |
300 | // pktHndlC.loadPkt(portVarC.$datai, myPort); | |
301 | // // if (gParam.ccxPktPrint[PP_PCX] || | |
302 | // // gParam.ccxPktPrint[PP_SPC] || | |
303 | // // gParam.ccxPktPrint[PP_TRG] || | |
304 | // // gParam.ccxPktPrintMask[myPort]) | |
305 | // pktHndlC.print(myPort); | |
306 | // @(negedge portVar.$clk); | |
307 | // } | |
308 | // } | |
309 | // | |
310 | // // while (1) { | |
311 | // // @(negedge portVarC.$clk); | |
312 | // // if (portVarC.$datai[145] == 1) { | |
313 | // // pktHndlC.loadPkt(portVarC.$datai, myPort); | |
314 | // // if (gParam.ccxPktPrint[PP_PCX] || | |
315 | // // gParam.ccxPktPrint[PP_SPC] || | |
316 | // // gParam.ccxPktPrintMask[myPort]) pktHndlC.print(myPort); | |
317 | // // } | |
318 | // // } | |
319 | // } join none | |
320 | // | |
321 | // } // if | |
322 | // } | |
323 | // | |
324 | ||
325 | // Create/config Interrupt Pkt. this is really a store packet to a certain | |
326 | // I/O adddress at the NCU. The NCU then does an interrupt to the target. | |
327 | task CLASSNAME::sendIntr(reg [5:0] tid, | |
328 | reg [1:0] type, | |
329 | reg [5:0] vect) | |
330 | { | |
331 | PcxPkt reqPkt; | |
332 | ||
333 | reqPkt = new(); | |
334 | reqPkt.createIntr(tid,type,vect); | |
335 | reqPkt.sendPorts = 1 << myPort; | |
336 | reqPkt.targetPorts = 1 << tid[5:3]; | |
337 | reqPkt.send(1); | |
338 | } | |
339 |