Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / api / sam / src / SS_VirtualStrand.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: SS_VirtualStrand.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 "SS_VirtualStrand.h"
#include "SS_Tlb.h"
SS_VirtualStrand::SS_VirtualStrand()
:
strand(0),
tracer(this)
{}
int SS_VirtualStrand ::interrupt( Sam::VCPU_InterruptRequest* p)
{
bool raise = p->isid & 1; // uses this, N2 ignores it ...
(*strand->external_interrupt)(strand,p->data,raise);
return 0;
}
int SS_VirtualStrand ::read_mem ( uint64_t addr, uint64_t *value, int size, int asi, int is_physical )
{
uint64_t paddr = addr;
if ( !is_physical )
{
paddr = strand->va2pa(addr);
if (paddr == 0)
return 1;
}
*value = this->sys_intf.mem->ld64(paddr);
return 0;
}
int SS_VirtualStrand ::write_mem ( uint64_t addr, uint64_t value, int size, int asi, int is_physical )
{
uint64_t paddr = addr;
if ( !is_physical )
{
paddr = strand->va2pa(addr);
if (paddr == 0)
return 1;
}
this->sys_intf.mem->st64 ( paddr, value);
return 0;
}
int SS_VirtualStrand ::set_breakpoint ( int *bp_id, Sam::VCPU_BpType type, uint64_t value, Sam::VCPU_BpActionFn action, uint64_t mask)
{
switch (type)
{
case Sam::VCPU_BP_INSTR_ADDR:
*bp_id = strand->break_on_inst_va( value );
return 0;
case Sam::VCPU_BP_TRAP:
*bp_id = strand->break_on_trap( value );
return 0;
case Sam::VCPU_BP_RED:
*bp_id = strand->break_on_red_mode();
return 0;
default:
return 1;
}
}
// remove breakpoint bp_id
int SS_VirtualStrand ::delete_breakpoint ( int bp_id )
{
SS_BreakPoint* bp = strand->break_points;
if (bp==NULL)
return 1; // there is no breakpoint set
if(bp_id == ~(0))
{
// remove all breakpoints
while (bp)
{
int id = bp->id;
bp = bp->next;
strand->break_delete(id);
}
return 0;
}
else // remove bp_id
{
return strand->break_delete(bp_id);
}
}
// print breakpoint list
int SS_VirtualStrand ::print_breakpoints ( FILE *fp )
{
SS_BreakPoint* bp = strand->break_points;
if (bp==NULL)
{
fprintf(fp, "No breakpoints set for cpu[%i] \n", strand->strand_id());
}
else for (; bp; bp = bp->next)
{
fprintf(fp, "cpu[%i] : bp_id = %i : value = 0x%llx : type = %i \n",
strand->strand_id(), bp->id, bp->va, bp->type);
}
return 0;
}
// output all valid tlb entries
int SS_VirtualStrand ::print_tlbs (FILE *fp)
{
SS_Tlb* itlb = strand->inst_tlb;
SS_Tlb* dtlb = strand->data_tlb;
fprintf(fp,"%s entries\n", itlb==dtlb ? "UTLB" : "ITLB");
itlb->dump(fp);
if (dtlb != itlb)
{
fprintf(fp,"DTLB entries\n");
dtlb->dump(fp);
}
return 0;
}
int SS_VirtualStrand::get_tlb_entries(Sam::VCPU_TLB * &return_array)
{
SS_Tlb * itlb = strand->inst_tlb;
SS_Tlb * dtlb = strand->data_tlb;
int count = itlb->size();
if (itlb != dtlb) {
count += dtlb->size();
}
return_array = new Sam::VCPU_TLB [count];
memset(return_array, 0, count*sizeof(Sam::VCPU_TLB));
int idx = 0;
int i;
for (i=0; i<itlb->size(); i++) {
SS_Tte * tte = itlb->get(i);
Sam::VCPU_TLB & tlb_rec = return_array[idx];
tlb_rec.format = 1; // sun4u
// IMPORTANT: the caller must fill in the tlb_rec.cpuid field before tracing
tlb_rec.demap = 0;
tlb_rec.tlb_type = (itlb==dtlb)? 2: 0; // itlb/unified
tlb_rec.tlb_index = i;
tlb_rec.tlb_no = itlb->tlb_id();
tlb_rec.tte_tag = tte->tag();
// data: v:63 nfo:62 taddr: 55-13 ie:12 e:11 cp:10 cv:9 p:8 ep:7 w:6 sz:3-0
tlb_rec.tte_data = tte->taddr() & (0x7ffffffffull << 13);
if (tte->valid_bit()) tlb_rec.tte_data |= (1ull<<63);
if (tte->nfo()) tlb_rec.tte_data |= (1ull << 62);
if (tte->ie()) tlb_rec.tte_data |= (1ull << 12);
if (tte->e()) tlb_rec.tte_data |= (1ull << 11);
if (tte->cp()) tlb_rec.tte_data |= (1ull << 10);
if (tte->cv()) tlb_rec.tte_data |= (1ull << 9);
if (tte->p()) tlb_rec.tte_data |= (1ull << 8);
if (tte->x()) tlb_rec.tte_data |= (1ull << 7);
if (tte->w()) tlb_rec.tte_data |= (1ull << 6);
tlb_rec.tte_data |= tte->page_size();
tlb_rec.is_real = tte->real_bit();
tlb_rec.partid = tte->pid();
tlb_rec.tte_page_size = tte->page_size();
tlb_rec.tte_context = tte->context();
idx++;
}
if (itlb != dtlb) {
for (i=0; i<dtlb->size(); i++) {
SS_Tte * tte = dtlb->get(i);
Sam::VCPU_TLB & tlb_rec = return_array[idx];
tlb_rec.format = 1; // sun4u
// IMPORTANT: the caller fills in the cpuid field before tracing
tlb_rec.demap = 0;
tlb_rec.tlb_type = 1; // dtlb
tlb_rec.tlb_index = i;
tlb_rec.tlb_no = dtlb->tlb_id();
tlb_rec.tte_tag = tte->tag();
// data: v:63 nfo:62 taddr: 55-13 ie:12 e:11 cp:10 cv:9 p:8 ep:7 w:6 sz:3-0
tlb_rec.tte_data = tte->taddr() & (0x7ffffffffull << 13);
if (tte->valid_bit()) tlb_rec.tte_data |= (1ull<<63);
if (tte->nfo()) tlb_rec.tte_data |= (1ull << 62);
if (tte->ie()) tlb_rec.tte_data |= (1ull << 12);
if (tte->e()) tlb_rec.tte_data |= (1ull << 11);
if (tte->cp()) tlb_rec.tte_data |= (1ull << 10);
if (tte->cv()) tlb_rec.tte_data |= (1ull << 9);
if (tte->p()) tlb_rec.tte_data |= (1ull << 8);
if (tte->x()) tlb_rec.tte_data |= (1ull << 7);
if (tte->w()) tlb_rec.tte_data |= (1ull << 6);
tlb_rec.tte_data |= tte->page_size();
tlb_rec.is_real = tte->real_bit();
tlb_rec.partid = tte->pid();
tlb_rec.tte_page_size = tte->page_size();
tlb_rec.tte_context = tte->context();
idx++;
}
}
assert (idx==count);
return count;
}