Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / tcu / vera / classes / ucb_monitor.vr
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: ucb_monitor.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#include <ListMacros.vrh> // Vera's linked list
37#include "std_display_class.vrh"
38#include "ucb_defines.vri"
39#include "ucb___packet.vrh"
40#include "ucb_top.vri"
41
42// creating a list. NOTE: it's a macro, so no ';'
43MakeVeraList(UCB___packet)
44
45class UCB_monitor {
46 //---public vars---
47 event req_begin; // triggered when NCU starts a new request
48 event rsp_begin; // triggered when target blk starts a response to NCU
49 event req_end; // triggered when NCU completes a request. Also, req_pkt is updated
50 event rsp_end; // triggered when target blk completes a response. Also, rsp_pkt is updated.
51 integer ignore_err = 0; // ignore all errors
52 //---ports and classes---
53 local UCB_port ucb_port; // UCB port
54 local StandardDisplay dbg; // Standard display for printing
55 //---local vars---
56 local string dispScope; // for standard display
57 local integer bus_width; // width of data bus. Valid values: 4 or 8 bits
58 local bit [127:0] req_pkt; // the latest request pkt which is updated when a new req is completed
59 local bit [127:0] rsp_pkt; // the latest response pkt which is updated when a new rsp is completed
60 VeraList_UCB___packet pend_rd_reqs; // list of pending read requests
61 local bit [7:0] g_asi; // global addr identifier (ie. [39:32] of PA or UCB pkt bits [54:47])
62 local integer ntransfer; // number of data transfers for one req/rsp (ie. 128/bus_width)
63 local integer num_req; // number of requests
64 local integer num_rsp; // number of responses
65 local integer running; // init to 0. Set to 1 when this monitor starts
66 local integer error_cnt; // Error count. Init to 0. WARN: become negative if exeed max integer
67 local integer max_error_printed; // stop print out error message when (error_cnt > max_error_printed)
68 local integer semaphore_id; // semaphore for accessing Vera list pend_rd_reqs
69
70 //---public subroutines---
71 task new(string dispScope="UCB_monitor", StandardDisplay dbg, UCB_port ucb_port, integer bus_width, bit [7:0] g_asi, integer start_it=0);
72 task start(); // start the monitor. Do nothing if the monitor is already running
73 function UCB___packet get_req_pkt();
74 function UCB___packet get_rsp_pkt();
75 function integer get_error_cnt() { get_error_cnt = this.error_cnt; }
76 task ignore_errors() { this.ignore_err = 1; }
77
78 //--- local subroutines ---
79 local task monitor_req(); // monitor the request bus
80 local task monitor_rsp(); // monitor the response bus
81 local function bit [127:0] get_request_pkt(); // return this.req_pkt
82 local function bit [127:0] get_response_pkt(); // return this.rsp_pkt
83 task print_error_msg(integer err_cnt, string error_msg);
84}
85
86//################################################################
87//######### implementation of subroutines ###########
88//################################################################
89
90task UCB_monitor::new(string dispScope="UCB_monitor", StandardDisplay dbg, UCB_port ucb_port, integer bus_width, bit [7:0] g_asi, integer start_it=0) {
91 //---from arg list---
92 this.dispScope = dispScope;
93 this.dbg = dbg;
94 this.ucb_port = ucb_port;
95 this.bus_width = bus_width;
96 this.g_asi = g_asi;
97 //---the rest---
98 this.req_pkt = 128'h0; // init to bad value
99 this.rsp_pkt = 128'h0; // init to bad value
100 this.pend_rd_reqs = new(); // empty list
101 this.ntransfer = 128 / bus_width;
102 this.num_req = 0;
103 this.num_rsp = 0;
104 this.running = 0; // monitor is not running yet
105 this.error_cnt = 0;
106 this.max_error_printed = 10;
107 semaphore_id = alloc(SEMAPHORE, 0, 1, 1); // 0: semaphore ID, 1: semaphore count, 1: one key initially
108 if (semaphore_id == 0)
109 dbg.dispmon(this.dispScope, MON_ERR, "alloc(SEMAPHORE, 0, 1, 1) : failed");
110
111 //---sanity check---
112 if ((bus_width != 4) && (bus_width != 8)) {
113 dbg.dispmon(this.dispScope, MON_ERR, psprintf("ucb bus width %0d <= monitor only supports 4/8-bit bus", this.bus_width));
114 this.error_cnt++;
115 }
116 //---start back ground threads---
117 if (start_it)
118 this.start(); // start the monitor
119}
120
121//==========================================================
122// WHAT: start the monitor
123//==========================================================
124task UCB_monitor::start() {
125 if (running) {
126 return; // monitor is already running
127 }
128 dbg.dispmon(this.dispScope, MON_INFO, "UCB monitor starts");
129 fork { monitor_req(); } join none
130 fork { monitor_rsp(); } join none
131 running = 1; // monitor is now running
132}
133
134//==========================================================
135// WHAT: monitor the requests from NCU to target unit.
136// WARNING: per NCU and UCB specs, NCU must deassert ncu_xxx_vld
137// for at least one cycle before sending the next request.
138//==========================================================
139task UCB_monitor::monitor_req() {
140 while (1) {
141 @(posedge ucb_port.$req_vld); // wait for new request
142 this.num_req++;
143 trigger(this.req_begin); // inform the caller
144 this.req_pkt = get_request_pkt(); // get the pkt
145 trigger(this.req_end); // inform the caller
146 }
147}
148
149//==========================================================
150// WHAT: monitor the response from target unit to NCU.
151// WARNING: per NCU and UCB specs, target unit must deassert
152// xxx_ncu_vld for at least one cycle before sending the next response.
153//==========================================================
154task UCB_monitor::monitor_rsp() {
155 while (1) {
156 @(posedge ucb_port.$rsp_vld); // wait for new response
157 this.num_rsp++;
158 trigger(this.rsp_begin); // inform the caller
159 this.rsp_pkt = get_response_pkt(); // get the pkt
160 trigger(this.rsp_end); // inform the caller
161 }
162}
163
164//==========================================================
165// WHAT: get the request packet (ie. 128-bit pkt NCU sends to target block
166// WARNING: per NCU and UCB specs, NCU must deassert ncu_xxx_vld
167// for at least one cycle before sending the next request.
168//==========================================================
169function bit [127:0] UCB_monitor::get_request_pkt() {
170 integer i, lsb=0, req_err_cnt = 0;
171 bit [127:0] data;
172 string pkt_type_str;
173 UCB___packet pkt;
174
175 //---get req pkt from the bus---
176 fork {
177 @(negedge ucb_port.$req_vld);
178 dbg.dispmon(this.dispScope, MON_ERR, "NCU deasserts ncu_xxx_vld before ucb req pkt completed");
179 }
180 {
181 for (i = 0; i < this.ntransfer; i++) {
182 if (ucb_port.$req_stall == 1'b1)
183 @(negedge ucb_port.$req_stall);
184 data[lsb + bus_width - 1 : lsb] = ucb_port.$req_data;
185 if (i != (this.ntransfer - 1)) // not the last data transfer
186 @(posedge ucb_port.$clk);
187 lsb = lsb + bus_width; // for next data transfer
188 }
189 } join any
190 terminate;
191 //--- NCU must deassert ncu_xxx_vld for at least one cycle----
192 fork {
193 @(posedge ucb_port.$clk);
194 if (ucb_port.$req_vld != 1'b0)
195 dbg.dispmon(this.dispScope, MON_ERR, "NCU does not deassert ncu_xxx_vld after request completed");
196 } join none
197 //---print out req for info---
198 pkt = new(*, data);
199 case (pkt.pkt_type) {
200 UCB_PKT_READ_REQ: pkt_type_str = "rd req";
201 UCB_PKT_WRITE_REQ: pkt_type_str = "wr req";
202 default: pkt_type_str = "unkown req";
203 }
204 dbg.dispmon(this.dispScope, MON_INFO, psprintf("%s : addr=0x%h, payload=0x%h, threadID=0x%h, cpuID=0x%h, bufferID=0x%h",
205 pkt_type_str, pkt.addr, pkt.payload, pkt.thread_id, pkt.cpu_id, pkt.buffer_id));
206 //---check for protocol/restriction violations---
207 if (pkt.req_size !== UCB_PKT_REQSIZE__8B)
208 print_error_msg(req_err_cnt++, psprintf("ucb req pkt=0x%h <= not 8B req", data));
209 if ((pkt.pkt_type != UCB_PKT_READ_REQ) && (pkt.pkt_type != UCB_PKT_WRITE_REQ))
210 print_error_msg(req_err_cnt++, psprintf("ucb req pkt=0x%h <= not rd/wr req", data));
211 if (pkt.addr[39:32] != this.g_asi)
212 print_error_msg(req_err_cnt++, psprintf("ucb req pkt=0x%h <= global asi or [54:47] is not 0x%h ", data, this.g_asi));
213 if ((pkt.buffer_id != 2'b00) && (pkt.buffer_id != 2'b01))
214 print_error_msg(req_err_cnt++, psprintf("ucb req pkt=0x%h <= buffer ID or [11:10] is bad", data));
215 //---for read request---
216 if (pkt.pkt_type == UCB_PKT_READ_REQ) {
217 void = semaphore_get(WAIT, semaphore_id, 1); // only one thread can access pending rd list.
218 this.pend_rd_reqs.push_back(pkt); // add new rd req to the end of the list
219 semaphore_put(semaphore_id, 1);
220 }
221 //---return value---
222 get_request_pkt = data;
223}
224
225//==========================================================
226// WHAT: get the response packet (ie. 128-bit pkt target block sent to NCU)
227// WARNING: per NCU and UCB specs, target unit must deassert
228// xxx_ncu_vld for at least one cycle before sending the next response.
229//==========================================================
230function bit [127:0] UCB_monitor::get_response_pkt() {
231 integer i, lsb=0, rsp_err_cnt=0;
232 bit [127:0] data;
233 bit [3:0] pkt_type;
234 string pkt_type_str;
235 UCB___packet pkt, oldest_rd_pkt;
236 integer is_rd_nack=0; // 1: read_nack rsp, 0: not a read_nack rsp
237 integer nbits=0; // number of bits transferred
238
239 //--- sanity check ---
240 if (pend_rd_reqs.size() < 1)
241 print_error_msg(0, "got rd rsp, but there is no pending rd req");
242 //---get response pkt---
243 fork {
244 @(negedge ucb_port.$rsp_vld);
245 dbg.dispmon(this.dispScope, MON_ERR, "target unit deasserts *_ncu_vld before completing rd response pkt");
246 }
247 {
248 for (i = 0; i < this.ntransfer; i++) {
249 if (ucb_port.$rsp_stall == 1'b1)
250 @(negedge ucb_port.$rsp_stall);
251 data[lsb + bus_width - 1 : lsb] = ucb_port.$rsp_data;
252 nbits += this.bus_width;
253 //---check for READ_NACK---
254 if (i == 0) {
255 pkt_type = data[UCB_PKT_PKTTYPE__MSB:UCB_PKT_PKTTYPE__LSB];
256 case (pkt_type) {
257 UCB_PKT_READ_ACK : is_rd_nack = 0;
258 UCB_PKT_READ_NACK : is_rd_nack = 1;
259 default :
260 print_error_msg(rsp_err_cnt++, psprintf("ucb rsp pkt type=0x%h <= not READ_ACK nor READ_NACK rsp", pkt_type));
261 }
262 }
263 //---for next data transfer---
264 if ((is_rd_nack) && (nbits >= 64))
265 break; // in read_nack, client sends UCB pkt without payload (ie. 64-bit pkt only)
266 if (i != (this.ntransfer - 1)) // not the last response
267 @(posedge ucb_port.$clk);
268 lsb = lsb + bus_width;
269 }
270 } join any
271 terminate;
272 //---- target unit must deassert xxx_ncu_vld for at least one cycle---
273 fork {
274 @(negedge ucb_port.$clk);
275 if (ucb_port.$rsp_vld != 1'b0)
276 dbg.dispmon(this.dispScope, MON_ERR, "target unit does not deassert *_ncu_vld after rd response completed");
277 } join none
278 //----print out rsp pkt for info----
279 pkt = new(*, data);
280 case (pkt.pkt_type) {
281 UCB_PKT_READ_ACK : pkt_type_str = "rd rsp";
282 UCB_PKT_READ_NACK : pkt_type_str = "rd nack";
283 default: pkt_type_str = "unkown rsp";
284 }
285 dbg.dispmon(this.dispScope, MON_INFO, psprintf("%s : payload=0x%h, threadID=0x%h, cpuID=0x%h, bufferID=0x%h",
286 pkt_type_str, pkt.payload, pkt.thread_id, pkt.cpu_id, pkt.buffer_id));
287 //---check rsp pkt header matches rd req pkt---
288 if (pend_rd_reqs.size() > 0) { // check only when there is a pending rd req
289 void = semaphore_get(WAIT, semaphore_id, 1); // only one thread can access pending rd list.
290 oldest_rd_pkt = pend_rd_reqs.front();
291 if (pkt.buffer_id != oldest_rd_pkt.buffer_id)
292 print_error_msg(0, psprintf("ucb rsp pkt=0x%h, req pkt=0x%h <= buffer ID or [11:10] not matched", data, oldest_rd_pkt.pkt));
293 if (pkt.cpu_id != oldest_rd_pkt.cpu_id)
294 print_error_msg(0, psprintf("ucb rsp pkt=0x%h, req pkt=0x%h <= CPU ID or [9:7] not matched", data, oldest_rd_pkt.pkt));
295 if (pkt.thread_id != oldest_rd_pkt.thread_id)
296 print_error_msg(0, psprintf("ucb rsp pkt=0x%h, req pkt=0x%h <= thread ID or [6:4] not matched", data, oldest_rd_pkt.pkt));
297 pend_rd_reqs.pop_front(); // remove oldest pending read req from list, no matter rsp matches or not
298 semaphore_put(semaphore_id, 1);
299 }
300 //---rd req is now completed---
301 get_response_pkt = data;
302}
303
304//=============================================================
305// WHAT: print error message
306// NOTE:
307// err_cnt is local error count of a particular error type.
308// this.error_cnt is global error count of this vera class.
309//=============================================================
310task UCB_monitor::print_error_msg(integer err_cnt, string error_msg) {
311 this.error_cnt++; // increment global error count
312 if (this.ignore_err)
313 return;
314 if (err_cnt <= max_error_printed)
315 dbg.dispmon(this.dispScope, MON_ERR, error_msg);
316}
317
318//=============================================================
319// Return the req pkt to the caller
320//=============================================================
321function UCB___packet UCB_monitor::get_req_pkt() {
322 UCB___packet ucb_pkt = new(*, this.req_pkt); // create a separate copy
323 get_req_pkt = ucb_pkt;
324}
325
326//=============================================================
327// Return rsp pkt to the caller
328//=============================================================
329function UCB___packet UCB_monitor::get_rsp_pkt() {
330 UCB___packet ucb_pkt = new(*, this.rsp_pkt); // create a separate copy
331 get_rsp_pkt = ucb_pkt;
332}
333
334