Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / siu / vera / monitors / siu_order_checker.vr
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: siu_order_checker.vr
// 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
// have any questions.
//
// ========== Copyright Header End ============================================
#include "siumon.if.vrh"
#include "siumon_ports_binds.vrh"
#include "std_display_class.vrh"
// added these #ifndefs for excluding code for NIU
#ifndef FC_NO_NIU_T2
#include "siu_niu_packet.vrh"
#endif
#include "siu_dmu_packet.vrh"
#include "siu_ncu_packet.vrh"
#include "siu_l2_packet.vrh"
#include "siu_monitor.vrh"
#include "siu_jtag_packet.vrh"
//extern bit siu_RDDord_pass_niuord_diffbank;
//extern bit siu_RDDord_not_pass_niuord_samebank;
//extern bit siu_WRIord_not_pass_niuord;
//extern bit siu_niubyp_pass_niubyp_diffbank;
//extern bit siu_niubyp_not_pass_niubyp_samebank;
//extern bit siu_niubyp_pass_niuord_diffbank;
//extern bit siu_RDDbyp_pass_RDDord_samebank;
//extern bit siu_WRIbyp_not_pass_niuord_samebank;
// added this
#ifndef FC_NO_NIU_T2
ExternVeraList(siu_niu_packet);
#endif
ExternVeraList(siu_dmu_packet);
class siu_order_checker {
// FIFO
// added this
#ifndef FC_NO_NIU_T2
VeraList_siu_niu_packet niu_fifo;
VeraListIterator_siu_niu_packet niu_fifo_ptr;
#endif
VeraList_siu_dmu_packet dmu_ordered_list, dmu_bypass_list;
VeraListIterator_siu_dmu_packet dmu_ordered_ptr, dmu_bypass_ptr;
// mailbox id
// added this
#ifndef FC_NO_NIU_T2
integer niu_snd_mbox;
integer niu_rec_mbox;
#endif
integer dmu_snd_mbox;
integer dmu_rec_mbox;
integer ncu_rec_mbox;
integer l2_snd_mbox[];
integer l2_rec_mbox[];
// added this
#ifndef FC_NO_NIU_T2
public bit siu_RDDord_pass_niuord_diffbank = 0;
public bit siu_RDDord_not_pass_niuord_samebank = 0;
public bit siu_WRIord_not_pass_niuord = 0;
public bit siu_niubyp_pass_niubyp_diffbank = 0;
public bit siu_niubyp_not_pass_niubyp_samebank = 0;
public bit siu_niubyp_pass_niuord_diffbank = 0;
public bit siu_RDDbyp_pass_RDDord_samebank = 0;
public bit siu_WRIbyp_not_pass_niuord_samebank = 0;
#endif
local integer wrm_in_progress;
local bit checker_disabled;
local bit ibl2_checker_proceed[8];
local bit obl2_checker_proceed[8];
siu_jtag_packet pending_jtag;
StandardDisplay dbg;
string myname;
task new (
// added this
#ifndef FC_NO_NIU_T2
integer niu_snd_mbox,
integer niu_rec_mbox,
#endif
integer dmu_snd_mbox,
integer dmu_rec_mbox,
integer ncu_rec_mbox,
integer l2_snd_mbox_0,
integer l2_rec_mbox_0,
integer l2_snd_mbox_1,
integer l2_rec_mbox_1,
integer l2_snd_mbox_2,
integer l2_rec_mbox_2,
integer l2_snd_mbox_3,
integer l2_rec_mbox_3,
integer l2_snd_mbox_4,
integer l2_rec_mbox_4,
integer l2_snd_mbox_5,
integer l2_rec_mbox_5,
integer l2_snd_mbox_6,
integer l2_rec_mbox_6,
integer l2_snd_mbox_7,
integer l2_rec_mbox_7,
StandardDisplay dbg);
// added this
#ifndef FC_NO_NIU_T2
task check_niu_snd();
task check_niu_rec();
#endif
task check_dmu_snd();
task check_dmu_rec();
task check_l2_snd(integer i);
task check_l2_rec(integer i);
task check_ncu_rec();
local function integer check_inbound_l2_order(Siu_L2_Packet packet, integer i);
local function integer check_outbound_l2_order(Siu_L2_Packet packet, integer i);
local function integer check_inbound_ncu_order(siu_ncu_packet packet);
local function integer check_outbound_order(siu_basic_packet packet);
// added this
#ifndef FC_NO_NIU_T2
local function integer check_niu_order_rules(Siu_Packet_Type btype, bit[39:0] bpa, bit bbypass,
Siu_Packet_Type ttype, bit[39:0] tpa, bit tbypass);
#endif
local function integer check_dmu_order_rules(Siu_Packet_Type btype, bit[39:0] bpa, Siu_Packet_Type ttype, bit[39:0] tpa);
}
task siu_order_checker::new(
// added this
#ifndef FC_NO_NIU_T2
integer niu_snd_mbox,
integer niu_rec_mbox,
#endif
integer dmu_snd_mbox,
integer dmu_rec_mbox,
integer ncu_rec_mbox,
integer l2_snd_mbox_0,
integer l2_rec_mbox_0,
integer l2_snd_mbox_1,
integer l2_rec_mbox_1,
integer l2_snd_mbox_2,
integer l2_rec_mbox_2,
integer l2_snd_mbox_3,
integer l2_rec_mbox_3,
integer l2_snd_mbox_4,
integer l2_rec_mbox_4,
integer l2_snd_mbox_5,
integer l2_rec_mbox_5,
integer l2_snd_mbox_6,
integer l2_rec_mbox_6,
integer l2_snd_mbox_7,
integer l2_rec_mbox_7,
StandardDisplay dbg)
{
integer i;
this.dbg = dbg;
myname = "siu-ord-chk";
// added this
#ifndef FC_NO_NIU_T2
this.niu_snd_mbox = niu_snd_mbox;
this.niu_rec_mbox = niu_rec_mbox;
#endif
this.dmu_snd_mbox = dmu_snd_mbox;
this.dmu_rec_mbox = dmu_rec_mbox;
this.ncu_rec_mbox = ncu_rec_mbox;
this.l2_snd_mbox[0] = l2_snd_mbox_0;
this.l2_rec_mbox[0] = l2_rec_mbox_0;
this.l2_snd_mbox[1] = l2_snd_mbox_1;
this.l2_rec_mbox[1] = l2_rec_mbox_1;
this.l2_snd_mbox[2] = l2_snd_mbox_2;
this.l2_rec_mbox[2] = l2_rec_mbox_2;
this.l2_snd_mbox[3] = l2_snd_mbox_3;
this.l2_rec_mbox[3] = l2_rec_mbox_3;
this.l2_snd_mbox[4] = l2_snd_mbox_4;
this.l2_rec_mbox[4] = l2_rec_mbox_4;
this.l2_snd_mbox[5] = l2_snd_mbox_5;
this.l2_rec_mbox[5] = l2_rec_mbox_5;
this.l2_snd_mbox[6] = l2_snd_mbox_6;
this.l2_rec_mbox[6] = l2_rec_mbox_6;
this.l2_snd_mbox[7] = l2_snd_mbox_7;
this.l2_rec_mbox[7] = l2_rec_mbox_7;
wrm_in_progress = 0;
checker_disabled = 0;
if ( get_plus_arg(CHECK, "siu_order_chk_off") ) {
checker_disabled = 1;
dbg.dispmon(myname, MON_NORMAL, psprintf ("siu order checker off!"));
}
else
dbg.dispmon(myname, MON_NORMAL, psprintf ("siu order checker ready!"));
// added this
#ifndef FC_NO_NIU_T2
niu_fifo = new();
#endif
dmu_ordered_list = new();
dmu_bypass_list = new();
pending_jtag = new(JRD,0,0);
for (i=0; i<8; i++)
{
ibl2_checker_proceed[i] = 1;
obl2_checker_proceed[i] = 1;
}
// added this
#ifndef FC_NO_NIU_T2
fork { check_niu_snd(); } join none
fork { check_niu_rec(); } join none
#endif
fork { check_dmu_snd(); } join none
fork { check_dmu_rec(); } join none
fork { check_ncu_rec(); } join none
fork { check_l2_snd(0); } join none
fork { check_l2_snd(1); } join none
fork { check_l2_snd(2); } join none
fork { check_l2_snd(3); } join none
fork { check_l2_snd(4); } join none
fork { check_l2_snd(5); } join none
fork { check_l2_snd(6); } join none
fork { check_l2_snd(7); } join none
fork { check_l2_rec(0); } join none
fork { check_l2_rec(1); } join none
fork { check_l2_rec(2); } join none
fork { check_l2_rec(3); } join none
fork { check_l2_rec(4); } join none
fork { check_l2_rec(5); } join none
fork { check_l2_rec(6); } join none
fork { check_l2_rec(7); } join none
}
// added this
#ifndef FC_NO_NIU_T2
task siu_order_checker::check_niu_snd()
{
siu_niu_packet niu_pkt, tmp_pkt;
integer mb_var;
while (1)
{
mb_var = mailbox_get(WAIT, niu_snd_mbox, tmp_pkt);
niu_pkt = tmp_pkt.object_copy();
niu_fifo.push_back(niu_pkt);
}
}
task siu_order_checker::check_niu_rec()
{
siu_niu_packet niu_pkt;
integer mb_var;
integer fail = 0;
while (!fail)
{
mb_var = mailbox_get(WAIT, niu_rec_mbox, niu_pkt);
// check outbound ordering rule
fail = check_outbound_order(niu_pkt);
}
}
#endif
task siu_order_checker::check_dmu_snd()
{
siu_dmu_packet dmu_pkt;
integer mb_var;
while (1)
{
mb_var = mailbox_get(WAIT, dmu_snd_mbox, dmu_pkt);
if (dmu_pkt.bypass)
dmu_bypass_list.push_back(dmu_pkt);
else
dmu_ordered_list.push_back(dmu_pkt);
}
}
task siu_order_checker::check_dmu_rec()
{
siu_dmu_packet dmu_pkt;
integer mb_var;
integer fail = 0;
while (!fail)
{
mb_var = mailbox_get(WAIT, dmu_rec_mbox, dmu_pkt);
// check outbound ordering rule
fail = check_outbound_order(dmu_pkt);
}
}
task siu_order_checker::check_ncu_rec()
{
siu_ncu_packet ncu_pkt;
integer mb_var;
integer fail = 0;
while (!fail)
{
mb_var = mailbox_get(WAIT, ncu_rec_mbox, ncu_pkt);
// check inbound ordering
fail = check_inbound_ncu_order(ncu_pkt);
}
}
task siu_order_checker::check_l2_rec(integer i)
{
Siu_L2_Packet l2_pkt;
integer mb_var;
integer fail;
while (ibl2_checker_proceed[i] && obl2_checker_proceed[i])
{
mb_var = mailbox_get(WAIT, this.l2_rec_mbox[i], l2_pkt);
fail = check_inbound_l2_order(l2_pkt, i);
}
}
task siu_order_checker::check_l2_snd(integer i)
{
Siu_L2_Packet l2_pkt;
integer mb_var;
integer fail;
while (ibl2_checker_proceed[i] && obl2_checker_proceed[i])
{
mb_var = mailbox_get(WAIT, this.l2_snd_mbox[i], l2_pkt);
fail = check_outbound_l2_order(l2_pkt, i);
}
}
function integer siu_order_checker::check_outbound_l2_order(Siu_L2_Packet l2_pkt, integer i)
{
integer fail = 0;
integer found = 0;
if (checker_disabled) {
check_outbound_l2_order = 1;
return;
}
if (l2_pkt.type == JRD || l2_pkt.type == JWR)
{
if (pending_jtag.valid == 0)
dbg.dispmon (myname, MON_ERR, psprintf ("l2 send jtag packet but no pending jtag packet pa=%x", l2_pkt.pa));
else
{
fail = (pending_jtag.type != l2_pkt.type) ? 1 : 0;
pending_jtag.valid = 0;
}
}
check_outbound_l2_order = fail;
obl2_checker_proceed[i] = ~fail;
}
function integer siu_order_checker::check_inbound_l2_order(Siu_L2_Packet l2_pkt, integer i)
{
// added this
#ifndef FC_NO_NIU_T2
siu_niu_packet niu_pkt;
#endif
siu_dmu_packet dmu_pkt;
integer fail = 0;
integer found = 0;
if (checker_disabled) {
check_inbound_l2_order = 1;
return;
}
if (l2_pkt.type == JRD || l2_pkt.type == JWR)
{
if (pending_jtag.valid == 1)
dbg.dispmon (myname, MON_ERR, psprintf (" more than one jtag packet, pending jtag packet pa=%x", pending_jtag.pa));
else
{
pending_jtag.type = l2_pkt.type;
pending_jtag.pa = l2_pkt.pa;
pending_jtag.data = l2_pkt.data[0];
pending_jtag.valid = 1;
}
}
else
if (l2_pkt.source == 1) // dmu
{
dbg.dispmon (myname, MON_NORMAL, psprintf ("chk dmu pkt[%x] pa=%x", l2_pkt.id, l2_pkt.pa));
dmu_ordered_ptr = dmu_ordered_list.start();
if (dmu_ordered_list.size() == 0)
{
// check wrm
if (l2_pkt.type == WRM && wrm_in_progress)
fail = 0;
else
{
fail = 1;
dbg.dispmon (myname, MON_ERR, psprintf ("l2 receive dmu pkt[%x] but dmu list is empty!", l2_pkt.id));
}
}
while (!found && dmu_ordered_ptr != null && !fail)
{
dmu_pkt = dmu_ordered_ptr.data();
// check for wrm
if (wrm_in_progress)
{
if (l2_pkt.type == WRM)
found = 1;
else
wrm_in_progress = 0;
}
// if I found the packet, then no problem
if (!found)
{
if ((dmu_pkt.id === l2_pkt.id) || (dmu_pkt.type == WRM && l2_pkt.type == WRM))
{
wrm_in_progress = (l2_pkt.type == WRM) ? 1 : 0;
found = 1;
dbg.dispmon (myname, MON_NORMAL, psprintf ("dmu order chkP pkt[%x]", dmu_pkt.id));
dmu_ordered_ptr = dmu_ordered_list.erase(dmu_ordered_ptr);
}
else // I shall check can my pkt pass this packet in the list
{
dbg.dispmon (myname, MON_NORMAL, psprintf ("chk rules for bypassing pkt[%x] pa=%x bp=%1d", dmu_pkt.id, dmu_pkt.pa, dmu_pkt.bypass));
fail = check_dmu_order_rules(l2_pkt.type, l2_pkt.pa, dmu_pkt.type, dmu_pkt.pa);
dmu_ordered_ptr.next();
}
}
}
if (found)
{
// compare packet
}
}
// added this
#ifndef FC_NO_NIU_T2
else // niu
{
dbg.dispmon (myname, MON_NORMAL, psprintf ("chk niu pkt[%x] pa=%x", l2_pkt.id, l2_pkt.pa));
niu_fifo_ptr = niu_fifo.start();
while (!found && niu_fifo_ptr != null && !fail)
{
niu_pkt = niu_fifo_ptr.data();
// if I found the packet, then no problem
if (niu_pkt.id === l2_pkt.id)
{
found = 1;
dbg.dispmon (myname, MON_NORMAL, psprintf ("niu order chkP pkt[%x]", niu_pkt.id));
niu_fifo_ptr = niu_fifo.erase(niu_fifo_ptr);
}
else // I shall check can my pkt pass this packet in the list
{
dbg.dispmon (myname, MON_NORMAL, psprintf ("chk rules for bypassing pkt[%x] pa=%x bp=%1d", niu_pkt.id, niu_pkt.pa, niu_pkt.bypass));
fail = check_niu_order_rules(l2_pkt.type, l2_pkt.pa, l2_pkt.bypass, niu_pkt.type, niu_pkt.pa, niu_pkt.bypass);
niu_fifo_ptr.next();
}
}
if (found)
{
// compare packet
}
}
#endif
//if (!fail) dbg.dispmon (myname, MON_NORMAL, psprintf ("order chkP pkt[%x]", l2_pkt.id));
check_inbound_l2_order = fail;
ibl2_checker_proceed[i] = ~fail;
}
function integer siu_order_checker::check_inbound_ncu_order(siu_ncu_packet ncu_pkt)
{
}
function integer siu_order_checker::check_outbound_order(siu_basic_packet packet)
{
}
// added this
#ifndef FC_NO_NIU_T2
function integer siu_order_checker::check_niu_order_rules(Siu_Packet_Type btype, bit[39:0] bpa, bit bbypass, Siu_Packet_Type ttype, bit[39:0] tpa, bit tbypass)
{
integer fail = 1;
if (bbypass == 0)
{
// ord RDD pkt can bypass other order WRI pkt, if the addr is different
// ord RDD pkt can bypass other order RDD pkt, if the addr is different
if (btype == RDD && tbypass == 0)
{
if (bpa[38:6] !== tpa[38:6])
{
fail = 0;
dbg.dispmon (myname, MON_INFO, psprintf ("RDD order pkt can bypass order pkt in different bank %x:%x", bpa, tpa));
siu_RDDord_pass_niuord_diffbank = 1;
}
else {
dbg.dispmon (myname, MON_NORMAL, psprintf ("RDD order pkt cannot bypass order pkt in same bank %x:%x", bpa, tpa));
siu_RDDord_not_pass_niuord_samebank = 1;
}
}
else {
dbg.dispmon (myname, MON_NORMAL, psprintf ("WRI order pkt cannot bypass"));
siu_WRIord_not_pass_niuord = 1;
}
}
else
{
// bp pkt can bypass other bp pkt, if other are for different banks
// bp pkt can bypass order pkt, if no address dependency
// bp RDD pkt can bypass order RDD pkt, with the same address
if (tbypass == 1)
{
if (bpa[38:6] !== tpa[38:6])
{
fail = 0;
dbg.dispmon (myname, MON_INFO, psprintf ("bypass pkt can bypass bypass pkt in different bank %x:%x", bpa, tpa));
siu_niubyp_pass_niubyp_diffbank = 1;
}
else {
dbg.dispmon (myname, MON_NORMAL, psprintf ("bypass pkt cannot bypass bypass pkt in same bank "));
siu_niubyp_not_pass_niubyp_samebank = 1;
}
}
else
{
if (bpa[38:6] !== tpa[38:6])
{
fail = 0;
dbg.dispmon (myname, MON_INFO, psprintf ("bypass pkt can bypass order pkt in different bank %x:%x", bpa, tpa));
siu_niubyp_pass_niuord_diffbank = 1;
}
else
{
if (btype == RDD && ttype == RDD)
{
fail = 0;
dbg.dispmon (myname, MON_INFO, psprintf ("bypass RDD pkt can bypass order RDD pkt in same bank %x:%x", bpa, tpa));
siu_RDDbyp_pass_RDDord_samebank = 1;
}
else {
dbg.dispmon (myname, MON_NORMAL, psprintf ("WRI bypass pkt cannot bypass order pkt in same bank "));
siu_WRIbyp_not_pass_niuord_samebank = 1;
}
}
}
}
check_niu_order_rules = fail;
}
#endif
// For N2, dmu only use order queue for DMA and Mondo interrupt, so we do not check the bypass queue
function integer siu_order_checker::check_dmu_order_rules(Siu_Packet_Type btype, bit[39:0] bpa, Siu_Packet_Type ttype, bit[39:0] tpa)
{
integer fail = 1;
// RDD pkt can bypass other order WRI pkt, if the addr is different
// RDD pkt can bypass other order RDD pkt, if the addr is different
if (btype == RDD)
{
if (bpa[38:6] !== tpa[38:6])
{
fail = 0;
dbg.dispmon (myname, MON_INFO, psprintf ("RDD order pkt can bypass order pkt in different bank %x:%x", bpa, tpa));
//RDDord_pass_niuord_diffbank = 1;
}
else {
dbg.dispmon (myname, MON_NORMAL, psprintf ("RDD order pkt cannot bypass order pkt in same bank %x:%x", bpa, tpa));
//RDDord_not_pass_niuord_samebank = 1;
}
}
else {
dbg.dispmon (myname, MON_NORMAL, psprintf ("WRI order pkt cannot bypass"));
//WRIord_not_pass_niuord = 1;
}
check_dmu_order_rules = fail;
}