// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: N2fcilupeuIngressDmaWrStr.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
// ========== Copyright Header End ============================================
#include "ios_l2_stub.vrh"
extern VeraList_l2_packet l2_list0;
extern VeraList_l2_packet l2_list1;
extern VeraList_l2_packet l2_list2;
extern VeraList_l2_packet l2_list3;
extern VeraList_l2_packet l2_list4;
extern VeraList_l2_packet l2_list5;
extern VeraList_l2_packet l2_list6;
extern VeraList_l2_packet l2_list7;
extern ios_l2_stub l2_stub[];
extern StandardDisplay dbg;
class N2fcDmaWrPEUStr extends PEUStrBase {
local bit [63:0] N2fcSAddr;
local bit [63:0] N2fcEAddr;
local bit N2fcAddrSpecified;
bit [511:0] write_data = 0;
bit [63:0] start_data = 0;
integer f_len; // The packet's payload length
bit[3:0] f_firstDWBE; // It's "first DWBE" field
bit[3:0] f_lastDWBE; // It's "last DWBE" field
integer f_bndy; // The address' boundary
bit f_lenSpecified; // Was a length specified?
bit f_firstSpecified; // Was a "firstDWBE" specified?
bit f_lastSpecified; // Was a "lastDWBE" specified?
bit f_bndySpecified; // Was an addr bndy specified?
integer f_tc; // The packet's traffic class
function bit [63:0] hashpa (bit [63:0] pa) {
if (probe_if.hashing && ~pa[39])
hashpa = {pa[63:18], pa[32:28] ^ pa[17:13], pa[19:18] ^ pa[12:11], pa[10:0]};
task new( PEUTestEnv a_env) {
if (!get_plus_arg(CHECK, "DISABLE_L2_CHECKER")) {
for ( index=0; index <8; index++){
l2_stub[index].enable_l2_checker = 1;
l2_stub[index].enable_l2_wr_checker = 1;
printf ("%0d- N2fcDmaWrPEUStr:new first random # = %0h\n", get_time(LO), random() );
task SetLen( integer a_len )
task SetFirstDWBE( bit[3:0] a_dwbe )
task SetLastDWBE( bit[3:0] a_dwbe )
task SetAddrBndy( integer a_bndy )
task N2fcSetAddr( bit [63:0] i_saddr, bit [63:0] i_eaddr )
//-------------------------------------------------------------------
//-------------------------------------------------------------------
function bit[31:0] gen_4bytes_exp_data (bit [31:0] data, bit [3:0] bytemask){
for (index =0; index < 4; index++){
gen_4bytes_exp_data[31-8*index:32-8*(index+1)] = data[31-8*index:32-8*(index+1)];
gen_4bytes_exp_data[31-8*index:32-8*(index+1)] = 8'hx;
//-------------------------------------------------------------------
//-------------------------------------------------------------------
task gen_exp_l2_pkt8bytes(
bit [31:0] dma_dword_len,
l2_packet l2_pkt = new("L2Expect", dbg);
reg [3:0] pbank = {probe_if.ba67, probe_if.ba45, probe_if.ba23, probe_if.ba01};
for (j = 0; j < dma_dword_len; j++) {
tmp_data = f_env.nextPayloadDW( ingressData );
if (j == 0 && !bypass_first_word){ // modify for first words
bytemask [3:0] = {f_firstDWBE[0],f_firstDWBE[1],f_firstDWBE[2],f_firstDWBE[3]};
bytemask [7:4] = {f_firstDWBE[0],f_firstDWBE[1],f_firstDWBE[2],f_firstDWBE[3]};
} else if (j == dma_dword_len-1 && !bypass_last_word){ // modify for last words
bytemask[3:0] = {f_lastDWBE[0], f_lastDWBE[1], f_lastDWBE[2], f_lastDWBE[3]};
bytemask[7:4] = {f_lastDWBE[0], f_lastDWBE[1], f_lastDWBE[2], f_lastDWBE[3]};
write_data[63:32] = gen_4bytes_exp_data(tmp_data, bytemask[7:4]);
if (j == dma_dword_len-1){
write_data[31:0] = gen_4bytes_exp_data(tmp_data, bytemask[3:0]);
write_data[31:0] = gen_4bytes_exp_data(tmp_data, bytemask[3:0]);
write_data[63:32] = gen_4bytes_exp_data(tmp_data, bytemask[7:4]);
last_packet = ((j == dma_dword_len - 1) || (address[5:2] == 4'b1111));
if(index%2 == 1 || j == dma_dword_len -1 ){
l2_pkt.set("tag", ingressTag);
l2_pkt.set("address", hashpa({address[63:3], 3'h0}) );
l2_pkt.set("data", write_data);
l2_pkt.set("bytemask", bytemask);
l2_pkt.set("opes", 4'b1101);
// printf("last_packet is %0b", last_packet);
l2_pkt.set("last_packet", last_packet);
//bank_number = address[8:6];
bank_number = address[8:6];
if (probe_if.pm === 1'b1)
bank_number = pbank_sel(pbank, bank_number);
l2_pkt.set("bank_number", bank_number);
l2_pkt.display("Putting a packet on the L2 Expect Queue");
0: l2_list0.push_back(l2_pkt.copy());
1: l2_list1.push_back(l2_pkt.copy());
2: l2_list2.push_back(l2_pkt.copy());
3: l2_list3.push_back(l2_pkt.copy());
4: l2_list4.push_back(l2_pkt.copy());
5: l2_list5.push_back(l2_pkt.copy());
6: l2_list6.push_back(l2_pkt.copy());
7: l2_list7.push_back(l2_pkt.copy());
//-------------------------------------------------------------------
//-------------------------------------------------------------------
bit [63:0] address = 64'b0; // Virtual address
bit [39:0] pa = 40'b0; // Physical address
bit [63:0] response = 64'b0;
bit[PEC_PCI__HDR] ingressHdr; // The ingress TLP's header
integer ingressData; // A payload descriptor
bit[7:0] ingressTag; // The tag for the TLP
reg [3:0] pbank = {probe_if.ba67, probe_if.ba45, probe_if.ba23, probe_if.ba01};
if (N2fcAddrSpecified == 1) {
error ("N2fcDmaWrPEUStr::Execute() : the start and end address must be specifed\n");
// First, get in line for a DMA tag...
f_env.allocDmaTag( ingressTag );
f_env.genIngressWrReq( ingressTag, ingressHdr, ingressData, f_len );
error ("N2fcDmaWrPEUStr::Execute() : the length must be specifed\n");
if( address[63:32] != 32'h00000000 ) {
ingressHdr[PEC_PCI__FMT_4DW] = 1; // 4DW hdr fmt, 64-bit address
ingressHdr[PEC_PCI__ADDR] = address;
ingressHdr[PEC_PCI__FMT_4DW] = 0; // 3DW hdr fmt, 32-bit address
ingressHdr[PEC_PCI__ADDR32] = address[31:0];
ingressHdr[PEC_PCI__TC] = f_tc;
printf ("%0d- UDEBUG N2fcDmaWrPEUStr:Execute Address = %0h Byp = %0h, Len = 'd%0d\n",
get_time(LO), address, address[63:39], f_len);
// ...and set fields as requested
f_env.setAddrBndy( ingressHdr, f_bndy, 4 );
ingressHdr[PEC_PCI__FIRST_DWBE] = f_firstDWBE;
ingressHdr[PEC_PCI__LAST_DWBE] = f_lastDWBE;
ingressData = start_data;
f_env.drivePCIE( ingressHdr, ingressData, *,*,*,*,*,1 );
bus_id = ingressHdr[ILUPEU_TLP_HDR_REQ_BUS_NUM_BITS];
gen_msi_exp_data(address, ingressData, ingressTag, ingressHdr[PEC_PCI__REQ_ID]);
((f_len == 1) && ingressHdr[PEC_PCI__FIRST_DWBE])) {
bit bypass_first_word = 0;
l2_pkt = new("L2Expect", dbg);
if (MMU.get_physical_address(address, pa, bus_id, 1)) {
address = pa; // use the physical address from here on
printf("N2fcDmaWrPEUStr:Execute problem found during translation, so no L2 expects will be setup.\n");
start_add = address[5:0] ;
if ((f_len >(64-start_add+3)/4 ) && (start_add !==0)){
gen_exp_l2_pkt8bytes((64-start_add+3)/4, address, 0,1, ingressData,ingressTag);
f_len = f_len - (64-start_add+3)/4 ;
} // align to catch line start address
if (f_len > 16 && (address[5:0] == 0)){
} else if (f_len === 16 && (address[5:0] == 0)){
while (do_cache_line){ // f_len is dword length
for (index=0; index <64/4; index++){
write_data[511-32*index:512-32*(index+1)] = f_env.nextPayloadDW( ingressData );
//last_packet = (f_len == 64/4);
l2_pkt.set("tag", ingressTag);
l2_pkt.set("address", hashpa(address) );
l2_pkt.set("data", write_data);
l2_pkt.set("bytemask", bytemask);
l2_pkt.set("opes", 4'b1101);
//printf("last_packet is %0b", last_packet);
l2_pkt.set("last_packet", last_packet);
bank_number = address[8:6];
if (probe_if.pm === 1'b1)
bank_number = pbank_sel(pbank, bank_number);
l2_pkt.set("bank_number", bank_number);
l2_pkt.display("Putting catch line packet on the L2 Expect Queue");
0: l2_list0.push_back(l2_pkt.copy());
1: l2_list1.push_back(l2_pkt.copy());
2: l2_list2.push_back(l2_pkt.copy());
3: l2_list3.push_back(l2_pkt.copy());
4: l2_list4.push_back(l2_pkt.copy());
5: l2_list5.push_back(l2_pkt.copy());
6: l2_list6.push_back(l2_pkt.copy());
7: l2_list7.push_back(l2_pkt.copy());
response = response + 64;
if (f_len > 16 && (address[5:0] == 0)){
} else if (f_len === 16 && (address[5:0] == 0)){
gen_exp_l2_pkt8bytes(f_len, address, bypass_first_word,0,ingressData,ingressTag);
f_env.freeDmaTag( ingressTag );
//-------------------------------------------------------------------
// Method Name: pbank_sel
// Description: Calculate the bank number based on the partial bank
//-------------------------------------------------------------------
function reg[2:0] pbank_sel(reg[3:0] pbank, reg[2:0] bank_sel)
reg [2:0] result = bank_sel;
4'b0001: result[2:1] = 2'b00;
4'b0010: result[2:1] = 2'b01;
4'b0011: result[2] = 1'b0;
4'b0100: result[2:1] = 2'b10;
4'b0101: result[2:1] = {bank_sel[1], 1'b0};
4'b0110: result[2:1] = {bank_sel[1], ~bank_sel[1]};
4'b1000: result[2:1] = 2'b11;
4'b1001: result[2:1] = {bank_sel[1], bank_sel[1]};
4'b1010: result[2:1] = {bank_sel[1], 1'b1};
4'b1100: result[2:1] = {1'b1, bank_sel[1]};
4'b1111: result = bank_sel;
error ("ERROR! illegal partial bank selection: %0b\n", pbank);
//-------------------------------------------------------------------
// Method Name: gen_msi_exp_data
// Description: Generate the expected L2 write packet for an MSI msg.
//-------------------------------------------------------------------
task gen_msi_exp_data (bit [63:0] msiaddress,
integer MSI_num = msidata[7:0];
bit [39:0] pa = 40'b0; // Physical address
reg [3:0] pbank = {probe_if.ba67, probe_if.ba45, probe_if.ba23, probe_if.ba01};
// Figure out if the MSI is mapped
if( !PiuCsrs.MsiIsValid(MSI_num) ) return;
// If an MSI has been sent to the EQ, but not cleared,
if( PiuCsrs.MsiIsEqWr(MSI_num) ) return;
EQ_num = PiuCsrs.GetMsiEqNum(MSI_num);
//if( PiuCsrs.EQBaseAddr[63:39] != 25'b1111_1111_1111_1100_0000_0000_0) {
// error("ERROR: N2fcDmaWrPEUStr::gen_msi_exp_data - a non-bypass EQ BASE address is not supported!");
// check if the EQ table is full
tmpEQTail = PiuCsrs.EQTail[EQ_num] + 1;
if (tmpEQTail == PiuCsrs.EQHead[EQ_num]) {
printf("Not writting to EQ[%d] for MSI %d because it is full\n", EQ_num, MSI_num);
address = PiuCsrs.EQBaseAddr[63:0] + (EQ_num * 8*1024) + (PiuCsrs.EQTail[EQ_num] * 64);
if (MMU.get_physical_address(address, pa, bus_id, 1)) {
address = pa; // use the physical address from here on
printf("N2fcDmaWrPEUStr:gen_msi_exp_data problem found during translation, so no L2 expects will be setup.\n");
PiuCsrs.SetMsiEqWr(MSI_num);
PiuCsrs.EQTail[EQ_num]++;
// set up the msi data that will be sent
msidata[15: 8] = msidata[7:0] + 1;
msidata[23:16] = msidata[7:0] + 2;
msidata[31:24] = msidata[7:0] + 3;
// set up expected data (from table 16-19 of the PRM)
word0[62:56] = (msiaddress[63:32]==0) ? 7'b1011000 : 7'b1111000; // FMT/TYPE
word0[55:46] = 1; // LENGTH in DW
word0[45:32] = msiaddress[15:2]; // ADDR[15:2]
word0[31:16] = rid; word0[15: 0] = msidata[15:0]; // DATA
word1[63:16] = msiaddress[63:16]; // ADDR[63:16]
word1[15: 0] = msidata[31:16]; // DATA
write_data[511-64*0:512-64*1] = word0;
write_data[511-64*1:512-64*2] = word1;
write_data[511-64*2:512-64*3] = 0;
write_data[511-64*3:512-64*4] = 0;
write_data[511-64*4:512-64*5] = 0;
write_data[511-64*5:512-64*6] = 0;
write_data[511-64*6:512-64*7] = 0;
write_data[511-64*7:512-64*8] = 0;
l2_pkt = new("L2Expect", dbg);
l2_pkt.set("tag", ingressTag);
l2_pkt.set("address", hashpa(address) );
l2_pkt.set("data", write_data);
l2_pkt.set("bytemask", bytemask);
l2_pkt.set("opes", 4'b1101);
l2_pkt.set("last_packet", 1);
bank_number = address[8:6];
if (probe_if.pm === 1'b1)
bank_number = pbank_sel(pbank, bank_number);
l2_pkt.set("bank_number", bank_number);
l2_pkt.display("Putting cache line packet on the L2 Expect Queue");
0: l2_list0.push_back(l2_pkt.copy());
1: l2_list1.push_back(l2_pkt.copy());
2: l2_list2.push_back(l2_pkt.copy());
3: l2_list3.push_back(l2_pkt.copy());
4: l2_list4.push_back(l2_pkt.copy());
5: l2_list5.push_back(l2_pkt.copy());
6: l2_list6.push_back(l2_pkt.copy());
7: l2_list7.push_back(l2_pkt.copy());