// ========== 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
// ========== Copyright Header End ============================================
#include <vera_defines.vrh>
#include <std_display_defines.vri>
#include <std_display_class.vrh>
//----------------------------------------------------------
//----------------------------------------------------------
reg [2:0] max_tag; // 7 or 3
reg [6:0] max_line; // 63 or 127
reg [239:0] tag_mem [128];
//----------------------------------------------------------
// Initialize memory - all entries are invalid
for (i=0; i<=max_line; i=i+1) {
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) {
if (msglevel>=MON_NORMAL) {
PR_NORMAL(name, MON_NORMAL,
psprintf("--- C%0d D$ TAG MEMORY (valid entries only) --- ",instance));
PR_NORMAL(name, MON_NORMAL,
psprintf("--- C%0d I$ TAG MEMORY (valid entries only) --- ",instance));
psprintf("--- C%0d D$ TAG MEMORY (valid entries only) --- ",instance));
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);
//----------------------------------------------------------
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;
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"},
valid3,tag3,valid2,tag2,valid1,tag1,valid0,tag0,why));
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"},
valid7,tag7,valid6,tag6,valid5,tag5,valid4,tag4,why));
psprintf({"C%0d tag_mem[%2h] ",
"w3-w0 V:T %b:%h %b:%h %b:%h %b:%h [dump_line]%s"},
valid3,tag3,valid2,tag2,valid1,tag1,valid0,tag0,why));
psprintf({"C%0d tag_mem[%2h] ",
"w7-w4 V:T %b:%h %b:%h %b:%h %b:%h [dump_line]%s"},
valid7,tag7,valid6,tag6,valid5,tag5,valid4,tag4,why));
psprintf({"C%0d tag_mem[%2h] ",
"w3-w0 V:T %b:%h %b:%h %b:%h %b:%h (adr) [dump_line]%s"},
valid3,tag3>>1,valid2,tag2>>1,valid1,tag1>>1,valid0,tag0>>1,why));
psprintf({"C%0d tag_mem[%2h] ",
"w7-w4 V:T %b:%h %b:%h %b:%h %b:%h (adr) [dump_line]%s"},
valid7,tag7>>1,valid6,tag6>>1,valid5,tag5>>1,valid4,tag4>>1,why));
//----------------------------------------------------------
// Print lines in a group (cache line).
// index must be normalized between 0..31
task dump_group (string why, reg [5:0] index) {
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);
dump_line(why, (index*2+0), MON_INFO);
dump_line(why, (index*2+1), MON_INFO);
//----------------------------------------------------------
task write_tag (reg [2:0] way,
old_line = tag_mem[index];
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};
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;
// is the L1 allocating when it doesn't need to? L1 should have hit!
if (old_line == new_line && hitCheck) {
dump_line ("write: Old ",index,MON_NORMAL);
psprintf ("C%0d L1 should have hit! index=%h tag=%h PA[39:0]=%h",instance,index,tag,pa));
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
for (i=0;i<8;i++) if (new_line[30*i+29:30*i] == {1'b1,tag}) count++;
dump_line ("Multiple hits in line",index,MON_NORMAL);
psprintf ("C%0d Multiple hits in tag table for a single line! PA[39:0]=%h",
psprintf({"C%0d tag_mem[%0h] tag=0x%h way=0x%h PA[39:0]=0x%h [write_tag]"},
instance,index,tag,way,pa));
//----------------------------------------------------------
// 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 [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;
if ((type==INSTR_TAG)&&(index>63)) {
psprintf ("C%0d index=%0d. It cannot be >63 for I_tag table.",instance,index));
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);
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'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));
psprintf ("C%0d Out of range hit in D$ tag table. One of the bits (7:4) is 1 and shouldn't be. ",instance));
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));
psprintf ("C%0d Multiple hits in tag table for a single line! PA[39:0]=%h",
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
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));
psprintf ("C%0d Multiple hits in tag table for a single line! PA[39:0]=%h",
if (gDbg.info) dump_line (why,index,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) {
index = random() % (max_line+1);
while ((cnt<=max_line)&&!valid) {
valid = line_valid (index);
PR_DEBUG (name, MON_DEBUG,
psprintf("C%0d count = %0h index = %0h valid = %0b ",instance,cnt,index,valid));
psprintf("C%0d No valid entry found in tag table. [search_tagmem]",instance));
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;
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,
//----------------------------------------------------------
// 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) {
get_pa = {tag,index[6:0],4'h0};
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;
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,
if ((type==DATA_TAG)&&(way>3)) {
psprintf ("C%0d way=%0d. It cannot be >3 for D_tag table.",instance,way));
if ((type==INSTR_TAG)&&(index>63)) {
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,
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];
//----------------------------------------------------------
// Index is normalized to be 0..31 (pointer to L2 cache line - top of group)
task evict_group (reg [28:0] evict_tag,
var reg [111:0] inv_vect) {
reg [31:0] vect0,vect1,vect2,vect3;
dump_group("Before Evict",evict_index);
// 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
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)
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);
// 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
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)
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);
create_vector (WAY_4BIT, way[1], vect2);
inv_vect = {vect3[23:0],vect2,vect1[23:0],vect0};
dump_group("After Evict",evict_index);
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------