Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / ilu_peu / vera / N2fc / N2fcilupeuIngressDmaWrStr.vr
// ========== 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
// have any questions.
//
// ========== Copyright Header End ============================================
#include "l2_packet.vrh"
#include "ios_l2_stub.vrh"
#include "fc_top.if.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;
local bit [31:0] length;
local bit [31:0] dat;
bit [511:0] write_data = 0;
bit [63:0] start_data = 0;
bit msi_dma = 0;
N2fcIommuMgr MMU;
bit [7:0] bus_id;
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]};
else
hashpa = pa;
}
task new( PEUTestEnv a_env) {
bit [3:0] index;
super.new( a_env );
if (!msi_dma){
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;
}
}
}
f_lenSpecified = 0;
f_firstSpecified = 0;
f_lastSpecified = 0;
f_bndySpecified = 0;
N2fcAddrSpecified = 0;
f_tc = -1;
MMU = new();
printf ("%0d- N2fcDmaWrPEUStr:new first random # = %0h\n", get_time(LO), random() );
}
task SetLen( integer a_len )
{
f_len = a_len;
f_lenSpecified = 1;
}
task SetFirstDWBE( bit[3:0] a_dwbe )
{
f_firstDWBE = a_dwbe;
f_firstSpecified = 1;
}
task SetLastDWBE( bit[3:0] a_dwbe )
{
f_lastDWBE = a_dwbe;
f_lastSpecified = 1;
}
task SetAddrBndy( integer a_bndy )
{
f_bndy = a_bndy;
f_bndySpecified = 1;
}
task N2fcSetAddr( bit [63:0] i_saddr, bit [63:0] i_eaddr )
{
N2fcAddrSpecified = 1;
N2fcSAddr = i_saddr;
N2fcEAddr = i_eaddr;
}
//-------------------------------------------------------------------
// Method Name:
// Description:
//-------------------------------------------------------------------
function bit[31:0] gen_4bytes_exp_data (bit [31:0] data, bit [3:0] bytemask){
integer index;
for (index =0; index < 4; index++){
if (bytemask[3-index]) {
gen_4bytes_exp_data[31-8*index:32-8*(index+1)] = data[31-8*index:32-8*(index+1)];
} else {
gen_4bytes_exp_data[31-8*index:32-8*(index+1)] = 8'hx;
}
}
}
//-------------------------------------------------------------------
// Method Name:
// Description:
//-------------------------------------------------------------------
task gen_exp_l2_pkt8bytes(
bit [31:0] dma_dword_len,
var bit [63:0] address,
bit bypass_first_word,
bit bypass_last_word,
var integer ingressData,
bit [7:0] ingressTag
){
integer i, j;
bit [7:0] bytemask;
l2_packet l2_pkt = new("L2Expect", dbg);
bit last_packet = 0;
bit [2:0] bank_number;
reg [3:0] pbank = {probe_if.ba67, probe_if.ba45, probe_if.ba23, probe_if.ba01};
integer index;
write_data = 0;
for (j = 0; j < dma_dword_len; j++) {
bit [31:0] tmp_data;
if (j==0 && address[2]){
index = 1;
} else if (j == 0 ){
index = 0;
}
if (index%2 == 0){
bytemask = 8'hff;
}
tmp_data = f_env.nextPayloadDW( ingressData );
if (j == 0 && !bypass_first_word){ // modify for first words
if (address[2]){
bytemask [3:0] = {f_firstDWBE[0],f_firstDWBE[1],f_firstDWBE[2],f_firstDWBE[3]};
bytemask [7:4] = 0;
} else {
bytemask [7:4] = {f_firstDWBE[0],f_firstDWBE[1],f_firstDWBE[2],f_firstDWBE[3]};
if (dma_dword_len == 1){
bytemask [3:0] = 0;
}
}
} else if (j == dma_dword_len-1 && !bypass_last_word){ // modify for last words
if (address[2]){
// bytemask[7:4] = 0;
bytemask[3:0] = {f_lastDWBE[0], f_lastDWBE[1], f_lastDWBE[2], f_lastDWBE[3]};
} else {
bytemask[7:4] = {f_lastDWBE[0], f_lastDWBE[1], f_lastDWBE[2], f_lastDWBE[3]};
bytemask [3:0] = 0;
}
}
if (index%2 == 0){
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]);
}
} else {
write_data[31:0] = gen_4bytes_exp_data(tmp_data, bytemask[3:0]);
if (j == 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");
case (bank_number) {
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());
}
}
address = address + 4;
index++;
}
}
//-------------------------------------------------------------------
// Method Name:
// Description:
//-------------------------------------------------------------------
task Execute()
{
bit [63:0] address = 64'b0; // Virtual address
bit [39:0] pa = 40'b0; // Physical address
bit [63:0] response = 64'b0;
bit [5:0] start_add;
l2_packet l2_pkt;
bit [7:0] bytemask;
bit [2:0] bank_number;
bit last_packet;
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) {
address = N2fcSAddr;
}
else {
error ("N2fcDmaWrPEUStr::Execute() : the start and end address must be specifed\n");
}
// First, get in line for a DMA tag...
f_env.allocDmaTag( ingressTag );
// Then build a TLP
if ( f_lenSpecified )
f_env.genIngressWrReq( ingressTag, ingressHdr, ingressData, f_len );
else
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;
}
else {
ingressHdr[PEC_PCI__FMT_4DW] = 0; // 3DW hdr fmt, 32-bit address
ingressHdr[PEC_PCI__ADDR32] = address[31:0];
}
// set the Traffic Class
if( f_tc != -1 ) {
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
// by the caller.
if ( f_bndySpecified )
f_env.setAddrBndy( ingressHdr, f_bndy, 4 );
if ( f_firstSpecified )
ingressHdr[PEC_PCI__FIRST_DWBE] = f_firstDWBE;
if ( f_lastSpecified )
ingressHdr[PEC_PCI__LAST_DWBE] = f_lastDWBE;
// add for MSI data
if (msi_dma) {
ingressData = start_data;
}
// add for MSI data
f_env.drivePCIE( ingressHdr, ingressData, *,*,*,*,*,1 );
bus_id = ingressHdr[ILUPEU_TLP_HDR_REQ_BUS_NUM_BITS];
if (msi_dma) {
gen_msi_exp_data(address, ingressData, ingressTag, ingressHdr[PEC_PCI__REQ_ID]);
}
else if ((f_len > 1) ||
((f_len == 1) && ingressHdr[PEC_PCI__FIRST_DWBE])) {
integer index;
bit bypass_first_word = 0;
bit do_cache_line;
l2_pkt = new("L2Expect", dbg);
if (MMU.get_physical_address(address, pa, bus_id, 1)) {
address = pa; // use the physical address from here on
}
else {
printf("N2fcDmaWrPEUStr:Execute problem found during translation, so no L2 expects will be setup.\n");
return;
}
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);
bypass_first_word = 1;
f_len = f_len - (64-start_add+3)/4 ;
address[5:0] = 0;
} // align to catch line start address
if (f_len > 16 && (address[5:0] == 0)){
do_cache_line =1;
} else if (f_len === 16 && (address[5:0] == 0)){
if (&f_lastDWBE){
do_cache_line = 1;
} else {
do_cache_line = 0;
}
} else {
do_cache_line = 0;
}
while (do_cache_line){ // f_len is dword length
bytemask = 8'h0;
write_data = 0;
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);
last_packet = 1;
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");
case (bank_number) {
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());
}
address = address + 64;
response = response + 64;
f_len = f_len - 64/4;
if (f_len > 16 && (address[5:0] == 0)){
do_cache_line =1;
} else if (f_len === 16 && (address[5:0] == 0)){
if (&f_lastDWBE){
do_cache_line = 1;
} else {
do_cache_line = 0;
}
} else {
do_cache_line = 0;
}
bypass_first_word = 1;
}
if (f_len >0) {
gen_exp_l2_pkt8bytes(f_len, address, bypass_first_word,0,ingressData,ingressTag);
}
}
f_env.freeDmaTag( ingressTag );
} /* end Execute */
//-------------------------------------------------------------------
// Method Name: pbank_sel
// Description: Calculate the bank number based on the partial bank
// controls.
//-------------------------------------------------------------------
function reg[2:0] pbank_sel(reg[3:0] pbank, reg[2:0] bank_sel)
{
reg [2:0] result = bank_sel;
case (pbank) {
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;
default:
error ("ERROR! illegal partial bank selection: %0b\n", pbank);
}
pbank_sel = result;
}
//-------------------------------------------------------------------
// 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,
bit [31:0] msidata,
bit [ 7:0] ingressTag,
bit [15:0] rid)
{
integer MSI_num = msidata[7:0];
integer EQ_num;
bit [63:0] address;
bit [39:0] pa = 40'b0; // Physical address
bit [63:0] word0, word1;
bit [7:0] bytemask = 0;
bit [2:0] bank_number;
reg [3:0] pbank = {probe_if.ba67, probe_if.ba45, probe_if.ba23, probe_if.ba01};
bit [6:0] tmpEQTail;
l2_packet l2_pkt;
// 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,
// we can't do it again
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);
return;
}
// all seems well ...
address = PiuCsrs.EQBaseAddr[63:0] + (EQ_num * 8*1024) + (PiuCsrs.EQTail[EQ_num] * 64);
MMU.set_msi(1);
if (MMU.get_physical_address(address, pa, bus_id, 1)) {
address = pa; // use the physical address from here on
}
else {
printf("N2fcDmaWrPEUStr:gen_msi_exp_data problem found during translation, so no L2 expects will be setup.\n");
MMU.set_msi(0);
return;
}
MMU.set_msi(0);
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[63] = 0;
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");
case (bank_number) {
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());
}
}
}