Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / niu / vera / ncu_drv / ncu_stub.vr
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: ncu_stub.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>
37#include "ncu_stub.if.vrh"
38#include "niu_int_qmgr.vrh"
39
40extern CNiuIntrQMgr NiuIntrQ;
41
42
43// NCU_STUB Class
44
45/*
46 Some of the tasks needed
47 - send_ucb( Wucb, Rucb ) -- writes a ucb packet into NIU.
48 - Task caller has to package the ucb packet
49 If the packet type is set to be a write request, the return value
50 of RUcb is null. If the pkt type is set to be of read req, the
51 return value of Rucb would be what is retured from NIU.
52
53 - write(addr,data, size) -- Creates a ucb packet and writes into NIU
54 - What should be the values for other fields in the ucb packet
55 - Size ( in bytes) is an optional value. Default is 8 byte
56 but other values can be set for error generations
57
58 - read ( addr, data, size, status) -- Function creates a ucb read request pkt.
59 - Status indicates the ack type. ( nack/ack)
60 - data indicates the payload field received in the returned ucb packet
61 - Other fields?
62 - default value of size is 8 bytes, but can be over loaded for error creation
63
64 - Config (TBD)
65 - Primarily used for configuring the stall signal behavior
66
67 - How to set other fields in the ucb packet such as thread id, cpu id etc
68 - Interrupt packets?
69
70
71
72*/
73
74// Defines for Requests
75#define NCU_READ_REQ 4'b0100
76#define NCU_WRITE_REQ 4'b0101
77#define NCU_IFILL_REQ 4'b0110
78
79// Defines for Acks
80#define NCU_READ_NACK 4'b0000
81#define NCU_READ_ACK 4'b0001
82#define NCU_WRITE_ACK 4'b0010
83#define NCU_IFILL_ACK 4'b0011
84#define NCU_IFILL_NACK 4'b0111
85
86// Defines for Interrupt
87#define NCU_INT 4'b1000
88#define NCU_INT_VEC 4'b1100
89
90
91
92class Cucb_packet {
93
94 reg [63:0] payload;
95 reg [8:0] reserved;
96 reg [39:0] addr;
97 reg [2:0] size;
98 reg [1:0] buf_id;
99 reg [2:0] cpu_id;
100 reg [2:0] thread_id;
101 reg [3:0] pkt_type;
102 reg [9:0] device_id;
103 reg [5:0] interrupt_vector;
104
105 reg [127:0] pkt;
106
107 task new() {
108 reserved = 9'b0; thread_id = 3'h0; cpu_id = 3'h0; buf_id = 2'h0;
109
110 }
111 task create_pkt() {
112 pkt = { payload,reserved,addr,size,buf_id,cpu_id,thread_id,pkt_type};
113 }
114 task parse_pkt() {
115 payload = pkt[127:64];
116 addr = pkt[54:15];
117 size = pkt[14:12];
118 buf_id = pkt[11:10];
119 cpu_id = pkt[9:7];
120 thread_id = pkt[6:4];
121 pkt_type = pkt[3:0];
122 if(pkt_type == NCU_INT) {
123 device_id = pkt[18:10];
124 }
125 // {payload,reserved,addr,size,buf_id,cpu_id,thread_id,pkt_type} = pkt;
126
127 }
128
129 task set_size ( integer s) {
130
131 case(s) {
132 1: size = 3'b000;
133 2: size = 3'b001;
134 4: size = 3'b010;
135 8: size = 3'b011;
136 16: size = 3'b100;
137 default: size = 3'bx;
138 }
139 }
140}
141
142class Cncu_requests {
143// This queues up all the read requests and will be used to match the responses
144// coming back from the niu block with the queued up requests.
145// This will also include timers per requests to see if the response comes back
146// within the specfied time
147
148 Cucb_packet read_packets;
149 integer no_of_pendingreqs;
150 // To add Timers, tokens etc
151 task new() {
152 no_of_pendingreqs = 0;
153 }
154}
155
156MakeVeraList(Cncu_requests) // que'd list of read requests
157
158
159
160class Cncu_stub {
161 integer NCU_NIU_SEMAPHORE_ID;
162 integer READ_RESP_TRIGGER;
163 integer read_mailbox_id;
164 integer int_mailbox_id;
165 ncu_port niu_ncu;
166 integer stall;
167 integer hi_time;
168 integer lo_time;
169
170 VeraList_Cncu_requests read_req_que;
171
172 task new( ncu_port ncu);
173 // ucb_packet ucb;
174 task write_ucb( Cucb_packet ucb );
175 task write_data( bit [39:0] addr, bit[63:0] data, (integer size = 8) );
176 task read_data( bit [39:0] addr, var bit[63:0] data, var integer status,
177 (bit exp_pio_err = 0), (integer size=8));
178 function Cucb_packet get_intpacket();
179 function Cucb_packet get_readpacket();
180 task config(integer hi_time, integer lo_time);
181 task gen_stall();
182 local task set_stall_delays(integer hi_time, integer lo_time);
183 local function integer get_hi_time();
184 local function integer get_lo_time();
185 local function bit [63:0] swap ( bit [63:0] d);
186 task get_int_packet();
187 task get_niu_packet();
188
189
190}
191
192task Cncu_stub:: get_int_packet() {
193// A free running task which monitors for Interrupt packets and send it up accordingly
194//
195 Cucb_packet int_packet;
196 CniuGenIntrMsg IntrMsg;
197
198 while(1) {
199 int_packet = get_intpacket();
200 if(int_packet.pkt_type== NCU_INT) {
201 printf(" Interrupt from NCU-- Packet received - DeviceID %x \n",int_packet.device_id);
202 IntrMsg = new();
203 IntrMsg.device_id = int_packet.device_id;
204 NiuIntrQ.addIntrMsg(IntrMsg);
205 printf("Cncu_stub:: get_int_packet Added New message into interrupt queue -\n");
206 }
207 @(posedge CLOCK);
208 }
209
210
211
212}
213function bit[63:0] Cncu_stub:: swap(bit [63:0] d) {
214
215 swap[7:0] = d[63:56];
216 swap[15:8] = d[55:48];
217 swap[23:16] = d[47:40];
218 swap[31:24] = d[39:32];
219 swap[39:32] = d[31:24];
220 swap[47:40] = d[23:16];
221 swap[55:48] = d[15:8];
222 swap[63:56] = d[ 7:0 ];
223
224}
225function integer Cncu_stub:: get_lo_time() {
226 if(lo_time==-1) get_lo_time = random()%10 + 1;
227 else get_lo_time = lo_time;
228}
229function integer Cncu_stub:: get_hi_time() {
230 if(hi_time==-1) get_hi_time = random()%10 + 1;
231 else get_hi_time = hi_time;
232}
233task Cncu_stub::gen_stall() {
234
235 if((hi_time ==0) | (lo_time==0)) {
236 stall = 0;
237 niu_ncu.$ncu_niu_stall= stall;
238
239 } else {
240 while(1) {
241 repeat(get_hi_time()) @(posedge niu_ncu.$clk);
242 niu_ncu.$ncu_niu_stall= 1;
243 @(posedge niu_ncu.$clk);
244 stall = 1;
245 repeat(get_lo_time()) @(posedge niu_ncu.$clk);
246 niu_ncu.$ncu_niu_stall= 0;
247 @(posedge niu_ncu.$clk);
248 stall = 0;
249 }
250 }
251}
252
253task Cncu_stub::config(integer h, integer l) {
254
255 // Configure the NCU driver
256 set_stall_delays(h, l);
257}
258task Cncu_stub::set_stall_delays(integer h, integer l) {
259
260 hi_time = h;
261 lo_time = l;
262}
263
264task Cncu_stub::write_data( bit [39:0] addr, bit[63:0] data, (integer size = 8)) {
265
266// Default value of size if 8 bytes
267
268 Cucb_packet write_ucb_pkt;
269 // printf("Cncu_stub::write_data : addr - %x Time - %d\n",addr,{get_time(HI), get_time(LO)});
270 write_ucb_pkt = new(/* cpu_id,buf_id, thread_id */);
271 write_ucb_pkt.addr = addr;
272 write_ucb_pkt.payload = swap(data);
273 write_ucb_pkt.set_size(size);
274 write_ucb_pkt.pkt_type = NCU_WRITE_REQ;
275 write_ucb_pkt.create_pkt();
276 write_ucb(write_ucb_pkt);
277 printf(" NCU-PIO Writes: Time%d -- Address = %x, Data = %x \n",{get_time(HI), get_time(LO)},addr,data);
278 // printf(" Done with Write \n");
279
280}
281
282task Cncu_stub::read_data( bit [39:0] addr, var bit[63:0] data, var integer status,
283 (bit exp_pio_err = 0), (integer size = 8)) {
284
285// Default value of size if 8 bytes
286 Cucb_packet readcmd_ucb_pkt;
287 Cucb_packet readresp_ucb_pkt;
288 bit [39:0] raddr;
289 bit [63:0] rdata;
290
291 shadow bit [1:0] buf_id;
292 shadow bit [2:0] cpu_id;
293 shadow bit [2:0] thread_id;
294
295 integer read_resp_packet_received;
296
297 // printf("Cncu_stub::read_data : addr - %x Time - %d\n",addr,{get_time(HI), get_time(LO)});
298 readcmd_ucb_pkt = new(/* cpu_id,buf_id, thread_id */);
299 readcmd_ucb_pkt.addr = addr;
300 readcmd_ucb_pkt.payload = 64'hdeadbeef_deadbeef;
301 readcmd_ucb_pkt.set_size(size);
302 readcmd_ucb_pkt.pkt_type = NCU_READ_REQ;
303 buf_id = random();
304 cpu_id = random();
305 thread_id = random();
306 readcmd_ucb_pkt.buf_id = buf_id;
307 readcmd_ucb_pkt.cpu_id = cpu_id;
308 readcmd_ucb_pkt.thread_id = thread_id;
309 readcmd_ucb_pkt.create_pkt();
310 write_ucb(readcmd_ucb_pkt);
311 // printf(" Done with Writing Read Command time - %d \n",{get_time(HI), get_time(LO)});
312
313
314 /*
315 In order to use the pending req ques
316 read_req_que.push_back(readcmd_ucb_pkt);
317 // printf(" No of requests = %d \n",read_req_que.size);
318
319 */
320
321
322 // printf(" Waiting for return data from Read Command Time - %d Addr - %x \n",{get_time(HI), get_time(LO)},addr);
323 // sync(ALL,READ_RESP_TRIGGER);
324 // trigger(OFF,READ_RESP_TRIGGER);
325 semaphore_get(WAIT,READ_RESP_TRIGGER,1);
326
327 raddr = addr;
328 read_resp_packet_received = 0;
329 while(read_resp_packet_received==0) {
330 readresp_ucb_pkt = get_readpacket();
331 printf("Cncu_stub::read_data DEBUG address - %x rdata - %x Time - %d \n",addr,readresp_ucb_pkt.pkt,{get_time(HI), get_time(LO)});
332 if( (readresp_ucb_pkt.pkt_type == NCU_READ_ACK ) | ( readresp_ucb_pkt.pkt_type == NCU_READ_NACK))
333 read_resp_packet_received = 1;
334 else read_resp_packet_received = 0; // received an interrup packet so go back
335
336 }
337
338 // parse the resp packet, check integrity of the packet and return the data and status
339
340
341 if(readresp_ucb_pkt.buf_id !== buf_id) {
342 printf(" ERROR - buf_id incorrect \n");
343 }
344 if(readresp_ucb_pkt.cpu_id !== cpu_id) {
345 printf(" ERROR - cpu_id incorrect \n");
346 }
347 if(readresp_ucb_pkt.thread_id !== thread_id) {
348 printf(" ERROR - thread_id incorrect \n");
349 }
350
351 rdata = swap(readresp_ucb_pkt.payload);
352 if(readresp_ucb_pkt.pkt_type == NCU_READ_ACK)
353 status = 1;
354 else if( readresp_ucb_pkt.pkt_type == NCU_READ_NACK)
355 status = 0;
356 else status = -1;
357
358 // if( readresp_ucb_pkt.pkt_type == NCU_READ_NACK)
359 // printf(" Received a NACK Packet from pio_read from address -%x - Time - %d \n",raddr,{get_time(HI), get_time(LO)});
360 // printf(" Done with get_packet Status = %d read data = %x \n",status,rdata);
361
362 if(status)
363 printf(" NCU-PIO Reads: Time%d -- Address = %x, Data = %x \n",{get_time(HI), get_time(LO)},raddr,rdata);
364
365 // added code for pio_err tests
366
367 if((exp_pio_err == 1'b0) && (status == 0))
368 printf("ERROR: pio_rd error seen when not expected\n");
369 if((exp_pio_err == 1'b1) && (status == 1))
370 printf("ERROR: pio_rd error not seen when expected\n");
371
372 // trigger(ON,READ_RESP_TRIGGER);
373 semaphore_put(READ_RESP_TRIGGER,1);
374
375 data = rdata;
376}
377
378
379task Cncu_stub::write_ucb( Cucb_packet ucb) {
380
381 integer cnt;
382
383// Writes to NIU
384// For a write from NCU to NIU, NCU tramits the
385// UCB packet. The transfer occurs in 4 cycles since the UCB
386// Packet is of 128 bits.
387
388 // niu_ncu.$ncu_niu_vld = 0;
389
390 // printf("Cncu_stub::write_ucb : addr - %x type %d Time - %d\n",ucb.addr,ucb.pkt_type,{get_time(HI), get_time(LO)});
391 semaphore_get(WAIT,NCU_NIU_SEMAPHORE_ID,1);
392
393 for(cnt= 0;cnt <4; cnt ++) {
394 niu_ncu.$ncu_niu_vld= 1;
395 while(niu_ncu.$niu_ncu_stall) {
396 @(posedge niu_ncu.$clk);
397 }
398 niu_ncu.$ncu_niu_data= ucb.pkt[ 31 + ( cnt*32) : 0 + (cnt*32) ] ;
399
400 // printf(" Write Data = %x \n",ucb.pkt[ 31 + ( cnt*32) : 0 + (cnt*32) ]);
401 @(posedge niu_ncu.$clk);
402 }
403 niu_ncu.$ncu_niu_vld= 0;
404 @(posedge niu_ncu.$clk);
405 semaphore_put(NCU_NIU_SEMAPHORE_ID,1);
406
407}
408
409task Cncu_stub::get_niu_packet() {
410 integer cnt;
411 integer tmp;
412 reg [127:0] rdata;
413 Cucb_packet resp_ucb;
414
415 repeat(100)@(posedge niu_ncu.$clk);
416 while(1) {
417 cnt = 0;
418 rdata = 0;
419 // Wait for Valid
420 while(!niu_ncu.$niu_ncu_vld) @(posedge niu_ncu.$clk);
421 while(niu_ncu.$niu_ncu_vld ) {
422 if(!stall ) {
423 if(cnt <4)
424 rdata[31 + (cnt*32) : (cnt*32)] = niu_ncu.$niu_ncu_data;
425 // printf("get_niu_packet DEBUG - cnt - %d rdata - %x Time - %d \n",cnt,rdata,{get_time(HI), get_time(LO)});
426 cnt ++;
427 if(cnt==2) {
428 /* If this is an interrupt packet reset the counter */
429 if(rdata[3:0] == NCU_INT) {
430 printf("get_niu_packet DEBUG- Received an interrupt packet in the middle of a pending read response!!! \n");
431 }
432 }
433 @(posedge niu_ncu.$clk);
434 } else {
435 @(posedge niu_ncu.$clk);
436 }
437 }
438
439 if(cnt>4) {
440 printf(" ERROR vld asserted for more that %d clock cycles \n",cnt);
441 rdata[127:0] = 128'bx;
442 }
443 resp_ucb = new();
444 resp_ucb.pkt = rdata;
445 resp_ucb.parse_pkt();
446 // printf("Cncu_stub::get_niu_packet DEBUG rdata - %x Time - %d \n",rdata,{get_time(HI), get_time(LO)});
447 if(cnt == 2) {
448 if(resp_ucb.pkt_type == NCU_READ_NACK ) {
449 // printf(" Received a NACK Packet from pio_read - Time - %d \n",{get_time(HI), get_time(LO)});
450 tmp = 1;
451 }else if(resp_ucb.pkt_type == NCU_INT) {
452 printf(" Received an Interrupt Packet - Time - %d \n",{get_time(HI), get_time(LO)});
453 }
454 else {
455 printf(" ERROR - niu_ncu_vld asserted in correctly \n");
456 }
457 }
458 if(resp_ucb.pkt_type == NCU_INT) {
459 mailbox_put(int_mailbox_id, resp_ucb);
460 } else {
461 mailbox_put(read_mailbox_id, resp_ucb);
462 }
463
464 }
465}
466function Cucb_packet Cncu_stub::get_intpacket( ) {
467 Cucb_packet packet;
468 integer status;
469// TOADD - TIMOUT
470 status = mailbox_get(WAIT, int_mailbox_id, packet);
471 get_intpacket = new packet;
472}
473
474function Cucb_packet Cncu_stub::get_readpacket( ) {
475 Cucb_packet packet;
476 integer status;
477// TOADD - TIMOUT
478 status = mailbox_get(WAIT, read_mailbox_id, packet);
479 get_readpacket = new packet;
480}
481
482task Cncu_stub::new( ncu_port ncu_bind)
483{
484 //
485 niu_ncu = ncu_bind;
486 niu_ncu.$ncu_niu_data= 0;
487 niu_ncu.$ncu_niu_vld= 0;
488 niu_ncu.$ncu_niu_stall= 0;
489 if (get_plus_arg(CHECK, "GEN_RANDOM_NCU_STALL"))
490 config(-1,-1);
491 else
492 config(4,4);
493 stall = 0;
494 NCU_NIU_SEMAPHORE_ID=alloc(SEMAPHORE,0,1,1);
495 READ_RESP_TRIGGER=alloc(SEMAPHORE,0,1,1);
496 read_mailbox_id = alloc(MAILBOX,0,1);
497 int_mailbox_id = alloc(MAILBOX,0,1);
498 read_req_que = new();
499 // trigger(ON,READ_RESP_TRIGGER);
500
501 fork{
502 if (get_plus_arg(CHECK, "GEN_NCU_STALL"))
503 gen_stall();
504 } join none
505
506 fork{
507 if (get_plus_arg(CHECK, "GEN_RANDOM_NCU_STALL"))
508 gen_stall();
509 } join none
510
511 fork {
512 get_int_packet();
513 } join none
514 fork {
515 get_niu_packet();
516 } join none
517
518}
519
520/************************
521
522program ncu_stub_test
523{ // start of top block
524
525 Cncu_stub ncu;
526
527 Cucb_packet ucb;
528 bit [63:0] rdata;
529 bit [39:0] address;
530 integer status;
531
532
533 ucb = new();
534 ncu = new(ncu_bind);
535
536 repeat(50) @(posedge ncu.niu_ncu.$clk );
537
538 // printf(" I am here \n");
539 @(posedge ncu.niu_ncu.$clk );
540 @(posedge ncu.niu_ncu.$clk );
541 @(posedge ncu.niu_ncu.$clk );
542 address[39:24] = 0;
543 address[23:20] = 4'h1;
544 address[19:0] = 20'h00040;
545
546 ncu.write_data(address,64'h12345678);
547 @(posedge ncu.niu_ncu.$clk );
548 address = address + 8;
549
550 ncu.write_data(address ,64'h12345678);
551 @(posedge ncu.niu_ncu.$clk );
552 @(posedge ncu.niu_ncu.$clk );
553 address = address + 16;
554 ncu.write_data(address,64'h12345678);
555 @(posedge ncu.niu_ncu.$clk );
556 @(posedge ncu.niu_ncu.$clk );
557 ncu.write_data(40'habcdef,64'h12345678);
558 @(posedge ncu.niu_ncu.$clk );
559 @(posedge ncu.niu_ncu.$clk );
560 ncu.write_data(40'habcdef,64'h12345678);
561 @(posedge ncu.niu_ncu.$clk );
562 @(posedge ncu.niu_ncu.$clk );
563 ncu.write_data(40'habcdef,64'h12345678);
564 @(posedge ncu.niu_ncu.$clk );
565 @(posedge ncu.niu_ncu.$clk );
566 ncu.write_data(40'habcdef,64'h12345678);
567 @(posedge ncu.niu_ncu.$clk );
568 @(posedge ncu.niu_ncu.$clk );
569 ncu.write_data(40'habcdef,64'h12345678);
570 @(posedge ncu.niu_ncu.$clk );
571 @(posedge ncu.niu_ncu.$clk );
572 ncu.write_data(40'habcdef,64'h12345678);
573 @(posedge ncu.niu_ncu.$clk );
574 @(posedge ncu.niu_ncu.$clk );
575
576
577
578 ucb.pkt = 128'habcd0000_12345678;
579
580 ncu.write_ucb(ucb);
581
582 @(posedge ncu.niu_ncu.$clk );
583
584 ucb.pkt = 128'habcd0000_12345678;
585 ncu.write_ucb(ucb);
586
587 @(posedge ncu.niu_ncu.$clk );
588
589 ucb.pkt = 128'habcd0000_12345678;
590 ncu.write_ucb(ucb);
591
592 @(posedge ncu.niu_ncu.$clk );
593
594 ucb.pkt = 128'habcd0000_12345678;
595 ncu.write_ucb(ucb);
596
597
598
599
600
601 @(posedge ncu.niu_ncu.$clk );
602 @(posedge ncu.niu_ncu.$clk );
603 ncu.write_data(40'habcdef,64'h12345678);
604
605
606 @(posedge ncu.niu_ncu.$clk );
607 @(posedge ncu.niu_ncu.$clk );
608 ncu.read_data(40'habcdef,rdata,status);
609 printf(" Read Data received = %x \n",rdata);
610 @(posedge ncu.niu_ncu.$clk );
611 @(posedge ncu.niu_ncu.$clk );
612 @(posedge ncu.niu_ncu.$clk );
613
614}
615*****************************/
616
617
618