Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / lib / cpu / src / SS_Tte.h
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: SS_Tte.h
* 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 ============================================
*/
#ifndef __SS_Tte_h__
#define __SS_Tte_h__
#include "SS_Types.h"
#include "SS_State.h"
class SS_Tte;
class SS_Tte
{
public:
SS_Tte() : tte_is_real(0), tte_is_virt(0), usage_count(0), tte_flags(0) {}
// The first part of the SS_Tte object, the virt/phys_page/mask is for caching the TTE
// and applying fast matching (match()) and translation (trans()). All the TTE specifics
// should have been tested by the inst_mmu or data_mmu functions respectively in the strand.
// The adapt() function is used when the tag or taddr ( translated address) is updated.
SS_Vaddr virt_page;
SS_Vaddr virt_mask;
SS_Paddr phys_page;
SS_Paddr phys_mask;
bool match( SS_Vaddr a ) const { return (a & virt_mask) == virt_page; }
SS_Paddr trans( SS_Vaddr a ) const { return (a &~ phys_mask) | phys_page; }
void adapt()
{
virt_mask = ~SS_Vaddr(0) << (tte_page_size * 3 + 13);
virt_page = tte_tag & virt_mask;
phys_page = tte_taddr & virt_mask;
phys_mask = virt_mask;
}
SS_Tte* next; // Next pointer in the free tte list in the tlb class
uint_t index; // The index in the TLB where this tte is located.
// The usage_count is 1 when the TTE is valid. Just before a TTE is demapped
// we set the usage_count to the number of strands that might use the TTE.
// When we are in tracing mode the usage_count is bumped to 2 and back to 1,
// this to prevent accidental cases where the TTE is being demapped and we
// we need it to produce trace output.
int_t usage_count; // A count used to hold on to the TTE
// The third part of the TTE is the actual TTE information as per architecture.
// E.g all the associated bits.
enum Flags
{
INVALID = 0x0000,
PRIVILEGED = 0x0001, // p
EXECUTABLE = 0x0002, // x (ep)
WRITEABLE = 0x0004, // w
NONFAULT = 0x0008, // nfo
INV_ENDIAN = 0x0010, // ie
CP = 0x0020, // cp
CV = 0x0040, // cv
SIDE_EFFECT = 0x0080, // e
TAG_PARITY = 0x0100, // tag parity
DATA_PARITY = 0x0200, // data parity
VALID_BIT = 0x0400, // v
REAL_BIT = 0x0800, // r
LOCK_BIT = 0x1000, // l
MULTI_HIT = 0x2000, // a condition that is set when TTE is looked up
VALID_ERROR = 0x4000 // duplicated valid bit mismatch
};
int valid() { return tte_is_real || tte_is_virt; }
int is_real() { return tte_is_real; }
int is_virt() { return tte_is_virt; }
uint8_t pid() { return tte_pid; }
uint16_t context() { return tte_context; }
uint8_t page_size() { return tte_page_size; }
SS_Vaddr tag() { return tte_tag; }
SS_Paddr taddr() { return tte_taddr; }
private:
void assign_flag( Flags bit, int val ) { if (val) tte_flags |= bit; else tte_flags &= ~bit; }
int test_flag( Flags bit ) { return 0 != (tte_flags & bit); }
public:
int p() { return test_flag(PRIVILEGED); }
int x() { return test_flag(EXECUTABLE); }
int w() { return test_flag(WRITEABLE); }
int nfo() { return test_flag(NONFAULT); }
int ie() { return test_flag(INV_ENDIAN); }
int cp() { return test_flag(CP); }
int cv() { return test_flag(CV); }
int e() { return test_flag(SIDE_EFFECT); }
int lock() { return test_flag(LOCK_BIT); }
int valid_bit() { return test_flag(VALID_BIT); }
int real_bit() { return test_flag(REAL_BIT); }
int multi_hit() { return test_flag(MULTI_HIT); }
int tag_parity_error() { return test_flag(TAG_PARITY); }
int data_parity_error() { return test_flag(DATA_PARITY); }
int valid_bit_error() { return test_flag(VALID_ERROR); }
void p( int f ) { assign_flag(PRIVILEGED,f); }
void x( int f ) { assign_flag(EXECUTABLE,f); }
void w( int f ) { assign_flag(WRITEABLE,f); }
void nfo( int f ) { assign_flag(NONFAULT,f); }
void ie( int f ) { assign_flag(INV_ENDIAN,f); }
void cp( int f ) { assign_flag(CP,f); }
void cv( int f ) { assign_flag(CV,f); }
void e( int f ) { assign_flag(SIDE_EFFECT,f); }
void lock( int f ) { assign_flag(LOCK_BIT,f); }
void valid_bit( int f ) { assign_flag(VALID_BIT,f); virt_real_update(); }
void real_bit( int f ) { assign_flag(REAL_BIT,f); virt_real_update(); }
void multi_hit( int f ) { assign_flag(MULTI_HIT,f); }
void tag_parity_error( int f ) { assign_flag(TAG_PARITY,f); }
void data_parity_error( int f ) { assign_flag(DATA_PARITY,f); }
void valid_bit_error( int f ) { assign_flag(VALID_ERROR,f); }
void virt_real_update()
{
// We keep two one hot bits for faster checking for
// valid real or valid virt TTEs. However for interface reasons
// we need to keep the valid and real bit as is. Just internally
// we use the one bit test is_real, is_virt flags.
if (valid_bit())
{
if (real_bit())
{
tte_is_real = true;
tte_is_virt = false;
}
else
{
tte_is_real = false;
tte_is_virt = true;
}
}
else
{
tte_is_real = false;
tte_is_virt = false;
}
}
void virt( int v ) { tte_is_virt = v; }
void real( int r ) { tte_is_real = r; }
void pid( uint8_t p ) { tte_pid = p; }
void context( uint16_t c ) { tte_context = c; }
void page_size( uint8_t p ) { tte_page_size = p; adapt(); }
void tag( SS_Vaddr t ) { tte_tag = t; adapt(); }
void taddr( SS_Paddr t ) { tte_taddr = t; adapt(); }
void set_real( uint16_t pid, uint8_t ps, SS_Vaddr tag, SS_Paddr dst )
{
valid_bit(true);
real_bit(true);
tte_pid = pid;
tte_page_size = ps;
tte_tag = tag;
tte_taddr = dst;
adapt();
}
void set_virt( uint16_t pid, uint16_t context, uint8_t ps, SS_Vaddr tag, SS_Paddr dst )
{
valid_bit(true);
real_bit(false);
tte_pid = pid;
tte_page_size = ps;
tte_tag = tag;
tte_context = context;
tte_taddr = dst;
adapt();
}
bool match_real( SS_Vaddr ra, uint_t pid ) const
{
return tte_is_real && match(ra) && (tte_pid == pid);
}
bool match_virt( SS_Vaddr va, uint64_t ctxt, uint_t pid ) const
{
return tte_is_virt && (tte_context == ctxt) && match(va) && (tte_pid == pid);
}
bool match_virt( SS_Vaddr va, uint64_t ctxt0, uint64_t ctxt1, uint_t pid ) const
{
return tte_is_virt && ((tte_context == ctxt0) || (tte_context == ctxt1)) && match(va) && (tte_pid == pid);
}
// This routine checks if there is a multi hit error or a tag parity error or data parity error
bool has_errors()
{
return multi_hit() | tag_parity_error() | data_parity_error() | valid_bit_error();
}
// insert_tsb_tte() inserts a sun4v TTE into this TTE. The vpn of the TTE is extended
// with bits 21:13 of the va, as the vpn in the TSB only has bit 63:22.
void insert_tsb_tte( uint16_t pid, uint64_t tag, uint64_t data, SS_Vaddr addr )
{
SS_TsbTteTag tsb_tag;
SS_TsbTteData tsb_data;
tte_flags = 0;
tsb_tag = tag;
tsb_data = data;
real_bit(0);
valid_bit(tsb_data.v());
tte_pid = pid;
tte_context = tsb_tag.context();
tte_page_size = tsb_data.size();
p( tsb_data.p());
x( tsb_data.x());
w( tsb_data.w());
nfo(tsb_data.nfo());
ie( tsb_data.ie());
cp( tsb_data.cp());
cv( tsb_data.cv());
e( tsb_data.e());
tte_tag = ((tsb_tag.va() << 9) | ((addr >> 13) & 0x1ff)) << 13;
tte_taddr = tsb_data.pa() << 13;
adapt();
}
// insert_sun4u_tsb_tte() inserts a sun4u TTE into the TTE. The vpn of the TTE is extended
// with bits 21:13 of the va, as the vpn in the TSB only has bit 63:22.
void insert_sun4u_tsb_tte( uint16_t pid, uint64_t tag, uint64_t data, SS_Vaddr addr )
{
// TODO for Ch and N1, see above
}
void snapshot( SS_SnapShot& ss, const char* prefix );
void dump(FILE *fp=stdout);
protected:
uint8_t tte_is_real; // Nonzero for valid real TTE
uint8_t tte_is_virt; // Nonzero for valid virt TTE
uint8_t tte_pid; // The partition for which this TTE is valid
uint8_t tte_page_size; // 0=8Kb, 1=64Kb, ...
uint16_t tte_context; // The context for virt TTE
uint16_t tte_flags; // The flags p,w,x,ie,nfo ...
SS_Vaddr tte_tag; // The TTE tag (va or ra)
SS_Paddr tte_taddr; // The TTE target address (pa or ra)
};
#endif