// ========== 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 #include #include #include #include #include //---------------------------------------------------------- //---------------------------------------------------------- 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 //----------------------------------------------------------