Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / vera / classes / ccx_tag_class.vr
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: ccx_tag_class.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 <vera_defines.vrh>
#include <globals.vri>
#include <ccx.vri>
#include <defines.vri>
#include <std_display_defines.vri>
#include <std_display_class.vrh>
//----------------------------------------------------------
//----------------------------------------------------------
class TAG_MEM {
local integer instance;
string name;
reg type; // I$ or D$
reg [2:0] max_tag; // 7 or 3
reg [6:0] max_line; // 63 or 127
reg [239:0] tag_mem [128];
//----------------------------------------------------------
task new (reg new_type,
reg [6:0] new_max_line,
reg [2:0] new_max_tag,
integer inst=0) {
integer i,j;
type = new_type;
max_tag = new_max_tag;
max_line = new_max_line;
if (type==DATA_TAG) {
name = "dtag";
} else {
name = "itag";
}
instance = inst;
// Initialize memory - all entries are invalid
for (i=0; i<=max_line; i=i+1) {
tag_mem[i] = 0;
}
PR_DEBUG(name, MON_DEBUG, psprintf("C%0d type = %b max_line = %d max_tag = %d ",instance,type,max_line,max_tag));
}
//----------------------------------------------------------
// Print all valid entries in the table
task dump_mem (integer msglevel) {
integer i,j;
if (msglevel>=MON_NORMAL) {
if (type==DATA_TAG) {
PR_NORMAL(name, MON_NORMAL,
psprintf("--- C%0d D$ TAG MEMORY (valid entries only) --- ",instance));
} else {
PR_NORMAL(name, MON_NORMAL,
psprintf("--- C%0d I$ TAG MEMORY (valid entries only) --- ",instance));
}
} else {
if (type==DATA_TAG) {
PR_INFO(name, MON_INFO,
psprintf("--- C%0d D$ TAG MEMORY (valid entries only) --- ",instance));
} else {
PR_INFO(name, MON_INFO,
psprintf("--- C%0d I$ TAG MEMORY (valid entries only) --- ",instance));
}
}
for (i=0; i<=max_line; i=i+1) {
if (tag_mem[i] !== 0) dump_line ("Dump",i,msglevel);
}
}
//----------------------------------------------------------
// Print the line
task dump_line (string why, reg [6:0] index,integer msglevel) {
reg [28:0] tag0,tag1,tag2,tag3,tag4,tag5,tag6,tag7;
reg valid0,valid1,valid2,valid3,valid4,valid5,valid6,valid7;
error_check(0,index);
read_line (index,
tag0,tag1,tag2,tag3,
tag4,tag5,tag6,tag7,
valid0,valid1,valid2,valid3,
valid4,valid5,valid6,valid7);
if (msglevel>=MON_NORMAL) {
PR_NORMAL(name, MON_NORMAL,
psprintf({"C%0d tag_mem[%2h] ",
"w3-w0 V:T %b:%h %b:%h %b:%h %b:%h [dump_line]%s"},
instance,index,
valid3,tag3,valid2,tag2,valid1,tag1,valid0,tag0,why));
if (type!=DATA_TAG) {
PR_NORMAL(name, MON_NORMAL,
psprintf({"C%0d tag_mem[%2h] ",
"w7-w4 V:T %b:%h %b:%h %b:%h %b:%h [dump_line]%s"},
instance,index,
valid7,tag7,valid6,tag6,valid5,tag5,valid4,tag4,why));
}
} else {
PR_INFO(name, MON_INFO,
psprintf({"C%0d tag_mem[%2h] ",
"w3-w0 V:T %b:%h %b:%h %b:%h %b:%h [dump_line]%s"},
instance,index,
valid3,tag3,valid2,tag2,valid1,tag1,valid0,tag0,why));
if (type!=DATA_TAG) {
PR_INFO(name, MON_INFO,
psprintf({"C%0d tag_mem[%2h] ",
"w7-w4 V:T %b:%h %b:%h %b:%h %b:%h [dump_line]%s"},
instance,index,
valid7,tag7,valid6,tag6,valid5,tag5,valid4,tag4,why));
}
}
#ifdef TAG_DEBUG
PR_INFO(name, MON_INFO,
psprintf({"C%0d tag_mem[%2h] ",
"w3-w0 V:T %b:%h %b:%h %b:%h %b:%h (adr) [dump_line]%s"},
instance,index,
valid3,tag3>>1,valid2,tag2>>1,valid1,tag1>>1,valid0,tag0>>1,why));
if (type!=DATA_TAG) {
PR_INFO(name, MON_INFO,
psprintf({"C%0d tag_mem[%2h] ",
"w7-w4 V:T %b:%h %b:%h %b:%h %b:%h (adr) [dump_line]%s"},
instance,index,
valid7,tag7>>1,valid6,tag6>>1,valid5,tag5>>1,valid4,tag4>>1,why));
}
#endif
}
//----------------------------------------------------------
// Print lines in a group (cache line).
// Itag - 2 lines
// Dtag - 4 lines
// index must be normalized between 0..31
task dump_group (string why, reg [5:0] index) {
if (type==DATA_TAG) {
dump_line(why, (index*4+0), MON_INFO);
dump_line(why, (index*4+1), MON_INFO);
dump_line(why, (index*4+2), MON_INFO);
dump_line(why, (index*4+3), MON_INFO);
} else {
dump_line(why, (index*2+0), MON_INFO);
dump_line(why, (index*2+1), MON_INFO);
}
}
//----------------------------------------------------------
task write_tag (reg [2:0] way,
reg [6:0] index,
reg [28:0] tag,
reg valid,
reg hitCheck=0) {
reg [239:0] old_line;
reg [239:0] new_line;
integer i,count;
reg [39:0] pa;
error_check(way,index);
// Read/Modify/Write
old_line = tag_mem[index];
new_line = old_line;
#ifdef TAG_DEBUG
if (valid) {
#endif
case (way) {
0: new_line [ 29: 0] = {valid,tag};
1: new_line [ 59: 30] = {valid,tag};
2: new_line [ 89: 60] = {valid,tag};
3: new_line [119: 90] = {valid,tag};
4: new_line [149:120] = {valid,tag};
5: new_line [179:150] = {valid,tag};
6: new_line [209:180] = {valid,tag};
7: new_line [239:210] = {valid,tag};
}
#ifdef TAG_DEBUG
} else {
case (way) {
0: new_line [ 29] = valid;
1: new_line [ 59] = valid;
2: new_line [ 89] = valid;
3: new_line [119] = valid;
4: new_line [149] = valid;
5: new_line [179] = valid;
6: new_line [209] = valid;
7: new_line [239] = valid;
}
}
#endif
pa = get_pa(tag,index);
// is the L1 allocating when it doesn't need to? L1 should have hit!
if (old_line == new_line && hitCheck) {
printf("\n");
dump_line ("write: Old ",index,MON_NORMAL);
PR_ERROR(name, MON_ERR,
psprintf ("C%0d L1 should have hit! index=%h tag=%h PA[39:0]=%h",instance,index,tag,pa));
printf("\n");
}
if (gDbg.info) dump_line ("write_tag: Old ",index,MON_INFO);
tag_mem[index] = new_line;
if (gDbg.info) dump_line ("write_tag: New ",index,MON_INFO);
// check if Multiple hits in tag line that was just written
count = 0;
for (i=0;i<8;i++) if (new_line[30*i+29:30*i] == {1'b1,tag}) count++;
if (count > 1) {
printf("\n");
dump_line ("Multiple hits in line",index,MON_NORMAL);
PR_ERROR(name, MON_ERR,
psprintf ("C%0d Multiple hits in tag table for a single line! PA[39:0]=%h",
instance,pa));
printf("\n");
dump_mem(MON_NORMAL);
}
PR_INFO(name, MON_INFO,
psprintf({"C%0d tag_mem[%0h] tag=0x%h way=0x%h PA[39:0]=0x%h [write_tag]"},
instance,index,tag,way,pa));
#ifdef TAG_DEBUG
dump_mem(MON_INFO);
#endif
}
//----------------------------------------------------------
// Read tag line and return way if tag hit
// way[3:0] is in the format required for the inval.vector in Vack field of CPX pkt
function reg [3:0] get_way ( string why,
reg [6:0] index,
reg [28:0] tag ) {
reg [239:0] line;
reg [28:0] tag0,tag1,tag2,tag3,tag4,tag5,tag6,tag7;
reg valid0,valid1,valid2,valid3,valid4,valid5,valid6,valid7;
reg hit0,hit1,hit2,hit3,hit4,hit5,hit6,hit7;
reg hit;
reg [39:0] pa;
if ((type==INSTR_TAG)&&(index>63)) {
PR_ERROR(name, MON_ERR,
psprintf ("C%0d index=%0d. It cannot be >63 for I_tag table.",instance,index));
}
pa = get_pa(tag,index);
read_line (index,
tag0,tag1,tag2,tag3,
tag4,tag5,tag6,tag7,
valid0,valid1,valid2,valid3,
valid4,valid5,valid6,valid7);
hit0 = {tag,1'b1}=={tag0,valid0};
hit1 = {tag,1'b1}=={tag1,valid1};
hit2 = {tag,1'b1}=={tag2,valid2};
hit3 = {tag,1'b1}=={tag3,valid3};
hit4 = {tag,1'b1}=={tag4,valid4};
hit5 = {tag,1'b1}=={tag5,valid5};
hit6 = {tag,1'b1}=={tag6,valid6};
hit7 = {tag,1'b1}=={tag7,valid7};
hit = (hit0 | hit1 | hit2 | hit3 | hit4 | hit5 | hit6 | hit7);
if (type==DATA_TAG) {
case ({hit7,hit6,hit5,hit4,hit3,hit2,hit1,hit0}) {
8'b00000000: get_way = 4'b0000; // n/a, bittom 2 always 10 if hit
8'b00000001: get_way = 4'b0010; // 0
8'b00000010: get_way = 4'b0110; // 1
8'b00000100: get_way = 4'b1010; // 2
8'b00001000: get_way = 4'b1110; // 3
8'b00010000,
8'b00100000,
8'b01000000,
8'b10000000: {printf("\n");
dump_line (why,index,MON_NORMAL);
PR_NORMAL(name, MON_NORMAL,
psprintf({"C%0d hit[7:0] = %b index = %h tag = %h "},
instance,{hit7,hit6,hit5,hit4,hit3,hit2,hit1,hit0},index,tag));
PR_ERROR(name, MON_ERR,
psprintf ("C%0d Out of range hit in D$ tag table. One of the bits (7:4) is 1 and shouldn't be. ",instance));
}
default : {printf("\n");
dump_line ("Multiple hits in line",index,MON_NORMAL);
PR_NORMAL(name, MON_NORMAL,
psprintf({"C%0d hit[7:0] = %b index = %h tag = %h "},
instance,{hit7,hit6,hit5,hit4,hit3,hit2,hit1,hit0},index,tag));
PR_ERROR(name, MON_ERR,
psprintf ("C%0d Multiple hits in tag table for a single line! PA[39:0]=%h",
instance, pa));
printf("\n");
dump_mem(MON_NORMAL);
}
}
} else {
case ({hit7,hit6,hit5,hit4,hit3,hit2,hit1,hit0}) {
8'b00000000: get_way = 4'b0000; // N/A, bottom bit always 1 is hit
8'b00000001: get_way = 4'b0001; // 0
8'b00000010: get_way = 4'b0011; // 1
8'b00000100: get_way = 4'b0101;
8'b00001000: get_way = 4'b0111;
8'b00010000: get_way = 4'b1001;
8'b00100000: get_way = 4'b1011;
8'b01000000: get_way = 4'b1101;
8'b10000000: get_way = 4'b1111; // 7
default : {printf("\n");
dump_line ("Multiple hits in line",index,MON_NORMAL);
PR_NORMAL(name, MON_NORMAL,
psprintf({"C%0d hit[7:0] = %b index = %h tag = %h "},
instance,{hit7,hit6,hit5,hit4,hit3,hit2,hit1,hit0},index,tag));
PR_ERROR(name, MON_ERR,
psprintf ("C%0d Multiple hits in tag table for a single line! PA[39:0]=%h",
instance, pa));
printf("\n");
dump_mem(MON_NORMAL);
}
}
}
if (gDbg.info) dump_line (why,index,MON_INFO);
PR_INFO(name, MON_INFO,
psprintf({"C%0d way[3:0]=%b hit[7:0]=%b index=%0h tag=%h pa=%h [get_way]%s"},
instance,get_way,{hit7,hit6,hit5,hit4,hit3,hit2,hit1,hit0},index,tag,pa,why));
}
//----------------------------------------------------------
// Return index that points to the line with a valid entry
task search_tagmem (var reg valid, var reg [6:0] index) {
integer cnt;
cnt = 0;
index = random() % (max_line+1);
valid = 0;
while ((cnt<=max_line)&&!valid) {
if (index==max_line) {
index = 0;
} else {
index = index + 1;
}
valid = line_valid (index);
PR_DEBUG (name, MON_DEBUG,
psprintf("C%0d count = %0h index = %0h valid = %0b ",instance,cnt,index,valid));
cnt = cnt + 1;
}
if (!valid) {
PR_INFO (name, MON_INFO,
psprintf("C%0d No valid entry found in tag table. [search_tagmem]",instance));
} else {
PR_INFO (name, MON_INFO,
psprintf("C%0d Valid entry found in tag table at index = %0h valid = %b [search_tagmem]",instance,index,valid));
}
}
//----------------------------------------------------------
// Search line and return tag on any valid entry
// Return 0's if no valid entry found
task get_tag (reg [6:0] index, var reg valid, var reg [28:0] tag) {
reg [28:0] tag0,tag1,tag2,tag3,tag4,tag5,tag6,tag7;
reg valid0,valid1,valid2,valid3,valid4,valid5,valid6,valid7;
valid = 1'b0;
read_line (index,
tag0,tag1,tag2,tag3,
tag4,tag5,tag6,tag7,
valid0,valid1,valid2,valid3,
valid4,valid5,valid6,valid7);
casex ({valid7,valid6,valid5,valid4,valid3,valid2,valid1,valid0}) {
8'bxxxxxxx1: { tag = tag0; valid = 1'b1;}
8'bxxxxxx10: { tag = tag1; valid = 1'b1;}
8'bxxxxx100: { tag = tag2; valid = 1'b1;}
8'bxxxx1000: { tag = tag3; valid = 1'b1;}
8'bxxx10000: { tag = tag4; valid = 1'b1;}
8'bxx100000: { tag = tag5; valid = 1'b1;}
8'bx1000000: { tag = tag6; valid = 1'b1;}
8'b10000000: { tag = tag7; valid = 1'b1;}
8'b00000000: { tag = 29'b0; valid = 1'b0;}
default: PR_ERROR(name, MON_ERR,
psprintf ("C%0d BENCH Problem: get_tag should not hit case default.",instance));
}
}
//----------------------------------------------------------
// Read line and return individual fields in the line
task read_line (reg [6:0] index,
var reg [28:0] tag0,
var reg [28:0] tag1,
var reg [28:0] tag2,
var reg [28:0] tag3,
var reg [28:0] tag4,
var reg [28:0] tag5,
var reg [28:0] tag6,
var reg [28:0] tag7,
var reg valid0,
var reg valid1,
var reg valid2,
var reg valid3,
var reg valid4,
var reg valid5,
var reg valid6,
var reg valid7
) {
reg [239:0] line;
line = tag_mem [index];
tag0 = line [ 28: 0];
tag1 = line [ 58: 30];
tag2 = line [ 88: 60];
tag3 = line [118: 90];
tag4 = line [148:120];
tag5 = line [178:150];
tag6 = line [208:180];
tag7 = line [238:210];
valid0 = line [ 29];
valid1 = line [ 59];
valid2 = line [ 89];
valid3 = line [119];
valid4 = line [149];
valid5 = line [179];
valid6 = line [209];
valid7 = line [239];
}
//----------------------------------------------------------
// Use this function to calculate the pa from the tag & index
function reg [39:0] get_pa (reg [28:0] tag, reg [6:0] index) {
if (type==DATA_TAG) {
get_pa = {tag,index[6:0],4'h0};
} else {
get_pa = {tag,index[5:0],5'h0};
}
}
//----------------------------------------------------------
function reg line_valid (reg [6:0] index) {
reg [28:0] tag0,tag1,tag2,tag3,tag4,tag5,tag6,tag7;
reg valid0,valid1,valid2,valid3,valid4,valid5,valid6,valid7;
read_line (index,
tag0,tag1,tag2,tag3,
tag4,tag5,tag6,tag7,
valid0,valid1,valid2,valid3,
valid4,valid5,valid6,valid7);
line_valid = valid0 | valid1 | valid2 | valid3 |
valid4 | valid5 | valid6 | valid7;
}
//----------------------------------------------------------
task error_check (reg [2:0] way,
reg [6:0] index) {
if ((type==DATA_TAG)&&(way>3)) {
PR_ERROR(name, MON_ERR,
psprintf ("C%0d way=%0d. It cannot be >3 for D_tag table.",instance,way));
}
if ((type==INSTR_TAG)&&(index>63)) {
PR_ERROR(name, MON_ERR,
psprintf ("C%0d index=%0d. It cannot be >63 for I_tag table.",instance,index));
}
}
//----------------------------------------------------------
// Create 32 or 24 bit invalidation vector to be used in response data field
// Can be used for Vack or Vinv in CPX packets
task create_vector (reg format,
reg [3:0] way,
var reg [31:0] vect) {
vect = 32'b0;
if (format==WAY_3BIT) {
case (instance) {
0: vect[ 2: 0] = way[3:1];
1: vect[ 5: 3] = way[3:1];
2: vect[ 8: 6] = way[3:1];
3: vect[11: 9] = way[3:1];
4: vect[14:12] = way[3:1];
5: vect[17:15] = way[3:1];
6: vect[20:18] = way[3:1];
7: vect[23:21] = way[3:1];
}
} else {
case (instance) {
0: vect[ 3: 0] = way;
1: vect[ 7: 4] = way;
2: vect[11: 8] = way;
3: vect[15:12] = way;
4: vect[19:16] = way;
5: vect[23:20] = way;
6: vect[27:24] = way;
7: vect[31:28] = way;
}
}
}
//----------------------------------------------------------
// Index is normalized to be 0..31 (pointer to L2 cache line - top of group)
task evict_group (reg [28:0] evict_tag,
reg [4:0] evict_index,
var reg [111:0] inv_vect) {
reg [6:0] index [4];
reg [3:0] way [4];
reg [3:0] tmp_way;
reg [31:0] vect0,vect1,vect2,vect3;
integer i;
dump_group("Before Evict",evict_index);
//--------------------
// Default values
vect0 = 32'b0;
vect1 = 32'b0;
vect2 = 32'b0;
vect3 = 32'b0;
inv_vect = 112'b0;
for (i=0; i<=3; i=i+1) {
index[i] = 5'b0;
way[i] = 4'b0;
}
//--------------------
// dtag
if (type==DATA_TAG) {
//--------------------
// Setup Indexes for the group of lines that we are going to evict
index[0] = (evict_index * 4);
index[1] = (evict_index * 4) + 1;
index[2] = (evict_index * 4) + 2;
index[3] = (evict_index * 4) + 3;
//--------------------
// Repeat get_way for all lines in the L2 cache line
// Get the way for the tag (even if no valid entry)
// since it is returned in inval vector
for (i=0; i<=3; i=i+1) {
way[i] = get_way ("Get_evict",index[i],evict_tag);
}
//--------------------
// Invalidate the entries in the eviction group
// (for the lines that had a valid entry)
for (i=0; i<=3; i=i+1) {
tmp_way = way[i];
if (tmp_way!=4'b0) {
tmp_way = {2'b0,tmp_way[3:2]};
write_tag (tmp_way[2:0],index[i],29'b0,TAG_INVAL);
}
}
create_vector (WAY_4BIT, way[0], vect0);
create_vector (WAY_3BIT, way[1], vect1);
create_vector (WAY_4BIT, way[2], vect2);
create_vector (WAY_3BIT, way[3], vect3);
//--------------------
// itag
} else {
//--------------------
// Setup Indexes for the group of lines that we are going to evict
index[0] = (evict_index * 2);
index[1] = (evict_index * 2) + 1;
//--------------------
// Repeat get_way for all lines in the L2 cache line
// Get the way for the tag (even if no valid entry)
// since it is returned in inval vector
for (i=0; i<=1; i=i+1) {
way[i] = get_way ("Get_evict",index[i],evict_tag);
}
// Invalidate the entries in the eviction group
// (for the lines that had a valid entry)
for (i=0; i<=1; i=i+1) {
tmp_way = way[i];
if (tmp_way!=4'b0) {
tmp_way = {1'b0,tmp_way[3:1]};
write_tag (tmp_way[2:0],index[i],29'b0,TAG_INVAL);
}
}
create_vector (WAY_4BIT, way[0], vect0);
vect1 = 32'b0;
create_vector (WAY_4BIT, way[1], vect2);
vect3 = 32'b0;
}
inv_vect = {vect3[23:0],vect2,vect1[23:0],vect0};
dump_group("After Evict",evict_index);
}
//----------------------------------------------------------
} // end class CCX_REQ
//----------------------------------------------------------
// END OF FILE
//----------------------------------------------------------