Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / n2 / lib / cpu / src / N2_Tlb.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: N2_Tlb.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
//
// The above named 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 work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
#include <string.h>
#include "N2_Tlb.h"
#include "N2_Core.h"
#include "N2_Strand.h"
N2_Tlb::N2_Tlb( Type type, uint_t size )/*{{{*/
:
SS_Tlb(type,size),
used(0),
used_count(0),
trie(this)
{
clone = n2_clone;
used = new bool[tlb_size];
for (uint_t i=0; i < tlb_size; i++)
used[i] = false;
}
/*}}}*/
N2_Tlb::N2_Tlb( N2_Tlb& tlb )/*{{{*/
:
SS_Tlb(tlb),
used(0),
used_count(tlb.used_count),
trie(tlb.trie,this)
{
used = new bool[tlb_size];
memcpy(used,tlb.used,tlb_size * sizeof(bool));
}
/*}}}*/
N2_Tlb::~N2_Tlb()/*{{{*/
{
delete used;
}
/*}}}*/
SS_Tlb* N2_Tlb::n2_clone( SS_Tlb* _tlb )/*{{{*/
{
return new N2_Tlb(*(N2_Tlb*)_tlb);
}
/*}}}*/
void N2_Tlb::snapshot( SS_SnapShot& ss, const char* prefix, const char* inst )/*{{{*/
{
char tte_tag[SS_SnapShot::LINE_SIZE];
for (int i=0; i < size(); i++)
{
sprintf(tte_tag,"%s.%s_tlb.%d",prefix,inst,i);
ptr_table[i]->snapshot(ss,tte_tag);
}
// Clear the used field to make run after snapshot
// and run after restore behave the same.
clear_used();
if (ss.do_load())
{
// Populate the trie TLB after loading. To make sure that
// we make an exact restore of the original trie we insert
// the pages size by smaller first and biggest last:
// the page size (psz) 0 (8K) first, then page size 1 (64K),
// 3, and 5. Page size 2,4,6,7 are not used by N2.
for (int psz = 0; psz <=5; psz++)
{
if ((psz == 2) or (psz == 4))
continue;
for (int i=0; i < size(); i++)
if (ptr_table[i]->valid() && (ptr_table[i]->page_size() == psz))
trie.insert(0,ptr_table[i],0);
}
}
}
/*}}}*/
void N2_Tlb::insert( SS_Tte* tte )/*{{{*/
{
uint_t idx;
SS_Tte* old_tte;
SS_Tte* new_tte;
tlb_access_lock();
idx = get_free_tte();
old_tte = ptr_table[idx];
assert(old_tte->index == idx);
new_tte = alloc_tte(idx);
*new_tte = *tte;
new_tte->index = idx;
new_tte->adapt();
trie.insert(0,tte,old_tte);
set_used(idx);
ptr_table[idx] = new_tte;
flush_tte(0,old_tte);
tlb_access_unlock();
}
/*}}}*/
SS_Tte* N2_Tlb::insert_tsb_tte( SS_Strand* strand, uint16_t pid, uint64_t tag, uint64_t data, SS_Vaddr va, int idx, int r )/*{{{*/
{
SS_Tte* old_tte;
SS_Tte* new_tte;
tlb_access_lock();
if (idx < 0)
idx = get_free_tte();
else
idx = idx & (size() - 1);
old_tte = ptr_table[idx];
assert(old_tte->index == idx);
new_tte = alloc_tte(idx);
new_tte->insert_tsb_tte(pid,tag,data,va);
new_tte->real_bit(r);
N2_Strand* n2_strand = (N2_Strand *)strand;
if (n2_strand->sim_state.ras_enabled())
{
N2_Core& n2_core = n2_strand->core;
if (n2_core.error_inject.ene())
{
int tp_error = 0;
int dp_error = 0;
if (n2_core.error_inject.imtu() | n2_core.error_inject.dmtu())
tp_error = 1;
if (n2_core.error_inject.imdu() | n2_core.error_inject.dmdu())
dp_error = 1;
new_tte->tag_parity_error(tp_error);
new_tte->data_parity_error(dp_error);
}
}
// Insert the TTE into the trie so that the non mutexed
// lookup can find it. Note lookup does not use mutexes which
// means that insert and demap have to be coded carefully.
// The old TTE can be flushed after the new TTE is available.
trie.insert(strand,new_tte,old_tte);
ptr_table[idx] = new_tte;
set_used(idx);
flush_tte(strand,old_tte);
// Trace insertion of tte into this tlb
if (strand->trc_hook)
strand->trc_hook->tlb_update(true,this,new_tte->index,new_tte);
tlb_access_unlock();
return new_tte;
}
/*}}}*/
void N2_Tlb::demap_virt( SS_Strand* strand, uint_t pid, uint_t context, SS_Vaddr va )/*{{{*/
{
tlb_access_lock();
trie.demap_virt(strand,pid,context,va);
tlb_access_unlock();
}
/*}}}*/
void N2_Tlb::demap_virt( SS_Strand* strand, uint_t pid, uint_t context )/*{{{*/
{
tlb_access_lock();
trie.demap_virt(strand,pid,context);
tlb_access_unlock();
}
/*}}}*/
void N2_Tlb::demap_virt( SS_Strand* strand, uint_t pid )/*{{{*/
{
tlb_access_lock();
trie.demap_virt(strand,pid);
tlb_access_unlock();
}
/*}}}*/
void N2_Tlb::demap_real( SS_Strand* strand, uint_t pid, SS_Vaddr va )/*{{{*/
{
tlb_access_lock();
trie.demap_real(strand,pid,va);
tlb_access_unlock();
}
/*}}}*/
void N2_Tlb::demap_real( SS_Strand* strand, uint_t pid )/*{{{*/
{
tlb_access_lock();
trie.demap_real(strand,pid);
tlb_access_unlock();
}
/*}}}*/
void N2_Tlb::demap_all( SS_Strand* strand, uint_t pid )/*{{{*/
{
tlb_access_lock();
trie.demap_all(strand,pid);
tlb_access_unlock();
}
/*}}}*/