// ========== 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; }