Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / api / pli / src / SS_TlbSync.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: SS_TlbSync.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_TlbSync.h"
SS_TlbSync::SS_TlbSync( SS_Strand* _strand, SS_TimedTlb* _inst_tlb, SS_TimedTlb* _data_tlb )/*{{{*/
:
strand(_strand),
inst_tlb(_inst_tlb),
data_tlb(_data_tlb),
debug_level(0),
socket(NULL)
{
strand->tlb_sync = this;
strand->inst_tlb_read = inst_tlb_read;
strand->inst_tlb_write = inst_tlb_write;
strand->inst_tlb_lookup = inst_tlb_lookup;
strand->data_tlb_read = data_tlb_read;
strand->data_tlb_write = data_tlb_write;
strand->data_tlb_lookup = data_tlb_lookup;
}
/*}}}*/
void SS_TlbSync::pli_inst_tlb_read( uint32_t time )/*{{{*/
{
inst_tlb_read_time.push_back(time);
}
/* }}}*/
void SS_TlbSync::pli_inst_tlb_write( uint32_t time, int8_t entry )/*{{{*/
{
inst_tlb_write_time.push_back(time);
inst_tlb_write_entry.push_back(entry);
}
/*}}}*/
void SS_TlbSync::pli_inst_hwtw( uint32_t time, SS_Vaddr va, int8_t entry )/*{{{*/
{
if (inst_tlb_read_time.size())
{
uint32_t read_time = inst_tlb_read_time.front();
inst_tlb_read_time.pop_front();
strand->inst_tlb = inst_tlb->lookup(read_time);
if (debug_level)
{
fprintf(stdout,"TLB: IHWTW-ITLBREAD tid=%d rtime=%d ::",strand->strand_id(),read_time);
std::list<uint32_t>::const_iterator i;
for (i = inst_tlb_read_time.begin(); i != inst_tlb_read_time.end(); i++)
fprintf(stdout," %d",(*i));
fprintf(stdout,"\n");
}
inst_tlb_write_time.push_front(time);
inst_tlb_write_entry.push_front(entry);
SS_Trap::Type tt = (strand->inst_hwtw)(strand,va,entry);
if (tt)
{
report_error("ERROR: PLI_IHWTW: failed to insert an entry through HWTW: tt=%d",tt);
}
}
else if (debug_level)
{
fprintf(stdout,"WARNING: TLB: IHWTW-ITLBREAD tid=%d queue empty\n",strand->strand_id());
}
}
/*}}}*/
void SS_TlbSync::pli_data_tlb_read( uint32_t time )/*{{{*/
{
data_tlb_read_time.push_back(time);
}
/*}}}*/
void SS_TlbSync::pli_data_tlb_read_pop( uint32_t time )/*{{{*/
{
if (data_tlb_read_time.size())
{
data_tlb_read_time.pop_back();
}
else
{
report_error("ERROR: dtlb_pop: miss DTLB pop, tid=%d",strand->strand_id());
}
}
/*}}}*/
void SS_TlbSync::pli_data_tlb_write( uint32_t time, int8_t entry )/*{{{*/
{
data_tlb_write_time.push_back(time);
data_tlb_write_entry.push_back(entry);
}
/*}}}*/
void SS_TlbSync::pli_data_hwtw( uint32_t time, SS_Vaddr va, uint8_t asi, int8_t entry )/*{{{*/
{
// data_tlb_read_time queue can be empty at this point, so check the
// inst_tlb_read_time queue independently.
if (inst_tlb_read_time.size())
{
uint32_t read_time = inst_tlb_read_time.front();
inst_tlb_read_time.pop_front();
if (debug_level)
{
fprintf(stdout,"TLB: DHWTW-ITLBREAD tid=%d rtime=%d ::",strand->strand_id(),read_time);
std::list<uint32_t>::const_iterator i;
for (i = inst_tlb_read_time.begin(); i != inst_tlb_read_time.end(); i++)
fprintf(stdout," %d",(*i));
fprintf(stdout,"\n");
}
}
else if (debug_level)
{
fprintf(stdout,"WARNING: TLB: DHWTW-ITLBREAD tid=%d queue empty\n",strand->strand_id());
}
if (data_tlb_read_time.size())
{
uint32_t read_time = data_tlb_read_time.front();
data_tlb_read_time.pop_front();
strand->data_tlb = data_tlb->lookup(read_time);
if (debug_level)
{
fprintf(stdout,"TLB: DHWTW-DTLBREAD tid=%d rtime=%d ::",strand->strand_id(),read_time);
std::list<uint32_t>::const_iterator i;
for (i = data_tlb_read_time.begin(); i != data_tlb_read_time.end(); i++)
fprintf(stdout," %d",(*i));
fprintf(stdout,"\n");
}
data_tlb_write_time.push_front(time);
data_tlb_write_entry.push_front(time);
SS_Trap::Type tt = (strand->data_hwtw)(strand,va,asi,entry);
if (tt)
{
report_error("ERROR: PLI: DHWTW: failed to insert an entry through HWTW: tt=%d",tt);
}
}
else if (debug_level)
{
fprintf(stdout,"WARNING: TLB: DHWTW-DTLBREAD tid=%d queue empty\n",strand->strand_id());
}
}
/*}}}*/
void SS_TlbSync::pli_tlb_lookup( uint32_t time, uint8_t asi )/*{{{*/
{
tlb_lookup_time.push_back(time);
tlb_lookup_asi.push_back(asi);
}
/*}}}*/
void SS_TlbSync::pli_flush()/*{{{*/
{
// Clear the sync messages that are buffered up. This is done
// for example when the processor gets into and error state,
// say, DATA_ACCESS_ERROR or PROCESSOR_INTERNAL_ERROR
inst_tlb_read_time.clear();
inst_tlb_write_time.clear();
inst_tlb_write_entry.clear();
data_tlb_read_time.clear();
data_tlb_write_time.clear();
data_tlb_write_entry.clear();
tlb_lookup_time.clear();
tlb_lookup_asi.clear();
}
/*}}}*/
void SS_TlbSync::data_tlb_read( void* tlb_sync )/*{{{*/
{
SS_TlbSync* self = (SS_TlbSync*)tlb_sync;
if (self->data_tlb_read_time.size())
{
uint32_t read_time = self->data_tlb_read_time.front();
self->data_tlb_read_time.pop_front();
if (self->debug_level)
{
fprintf(stdout,"TLB: DTLBREAD tid=%d rtime=%d ::",self->strand->strand_id(),read_time);
std::list<uint32_t>::const_iterator i;
for (i = self->data_tlb_read_time.begin(); i != self->data_tlb_read_time.end(); i++)
fprintf(stdout," %d",(*i));
fprintf(stdout,"\n");
}
self->strand->data_tlb = self->data_tlb->lookup(read_time);
}
else if (self->debug_level)
{
fprintf(stdout,"WARNING: TLB: DTLBREAD tid=%d queue empty\n",self->strand->strand_id());
}
}
/*}}}*/
int SS_TlbSync::data_tlb_write( void* tlb_sync )/*{{{*/
{
SS_TlbSync* self = (SS_TlbSync*)tlb_sync;
if (self->data_tlb_write_time.size())
{
uint32_t write_time = self->data_tlb_write_time.front();
int8_t write_entry = self->data_tlb_write_entry.front();
self->data_tlb_write_time.pop_front();
self->data_tlb_write_entry.pop_front();
self->strand->data_tlb = self->data_tlb->modify(write_time);
return write_entry;
}
return -1;
}
/*}}}*/
void SS_TlbSync::data_tlb_lookup( void* tlb_sync )/*{{{*/
{
SS_TlbSync* self = (SS_TlbSync*)tlb_sync;
if (self->tlb_lookup_time.size())
{
uint32_t read_time = self->tlb_lookup_time.front();
uint8_t read_asi = self->tlb_lookup_asi.front();
self->tlb_lookup_time.pop_front();
self->tlb_lookup_asi.pop_front();
if (self->debug_level)
{
fprintf(stdout,"TLB: DTLBLOOKUP tid=%d rtime=%d ::",self->strand->strand_id(),read_time);
std::list<uint32_t>::const_iterator i;
for (i = self->tlb_lookup_time.begin(); i != self->tlb_lookup_time.end(); i++)
fprintf(stdout," %d",(*i));
fprintf(stdout,"\n");
}
self->strand->data_tlb = self->data_tlb->lookup(read_time);
}
else if (self->debug_level)
{
fprintf(stdout,"WARNING: TLB: DTLBLOOKUP tid=%d queue empty\n",self->strand->strand_id());
}
}
/*}}}*/
void SS_TlbSync::inst_tlb_read( void* tlb_sync )/*{{{*/
{
SS_TlbSync* self = (SS_TlbSync*)tlb_sync;
if (self->inst_tlb_read_time.size())
{
uint32_t read_time = self->inst_tlb_read_time.front();
self->inst_tlb_read_time.pop_front();
if (self->debug_level)
{
fprintf(stdout,"TLB: ITLBREAD tid=%d rtime=%d ::",self->strand->strand_id(),read_time);
for (std::list<uint32_t>::const_iterator i = self->inst_tlb_read_time.begin(); i != self->inst_tlb_read_time.end(); i++)
fprintf(stdout," %d",(*i));
fprintf(stdout,"\n");
}
SS_Tlb* tlb = self->inst_tlb->lookup(read_time);
self->strand->inst_tlb_set(tlb);
assert(self->strand->inst_tlb);
}
else if (self->debug_level)
{
fprintf(stdout,"WARNING: TLB: ITLBREAD tid=%d queue empty\n",self->strand->strand_id());
}
}
/*}}}*/
int SS_TlbSync::inst_tlb_write( void* tlb_sync )/*{{{*/
{
SS_TlbSync* self = (SS_TlbSync*)tlb_sync;
if (self->inst_tlb_write_time.size())
{
uint32_t write_time = self->inst_tlb_write_time.front();
int8_t write_entry = self->inst_tlb_write_entry.front();
self->inst_tlb_write_time.pop_front();
self->inst_tlb_write_entry.pop_front();
self->strand->inst_tlb = self->inst_tlb->modify(write_time);
return write_entry;
}
return -1;
}
/*}}}*/
void SS_TlbSync::inst_tlb_lookup( void* tlb_sync )/*{{{*/
{
SS_TlbSync* self = (SS_TlbSync*)tlb_sync;
if (self->tlb_lookup_time.size())
{
uint32_t read_time = self->tlb_lookup_time.front();
uint8_t read_asi = self->tlb_lookup_asi.front();
self->tlb_lookup_time.pop_front();
self->tlb_lookup_asi.pop_front();
if (self->debug_level)
{
fprintf(stdout,"TLB: ITLBLOOKUP tid=%d rtime=%d ::",self->strand->strand_id(),read_time);
std::list<uint32_t>::const_iterator i;
for (i = self->tlb_lookup_time.begin(); i != self->tlb_lookup_time.end(); i++)
fprintf(stdout," %d",(*i));
fprintf(stdout,"\n");
}
self->strand->inst_tlb = self->inst_tlb->lookup(read_time);
}
else if (self->debug_level)
{
fprintf(stdout,"WARNING: TLB: ITLBLOOKUP tid=%d queue empty\n",self->strand->strand_id());
}
}
/*}}}*/
void SS_TlbSync::report_error(const char *fmt, ...)/*{{{*/
{
char format[256];
va_list args;
va_start(args, fmt);
sprintf(format, "%s\n", fmt);
vfprintf(stdout, format, args);
// write the error message to RTL testbench, so that it can show in
// the right place in sims.log and vcs.log
if (socket)
{
socket->write_err(format, args);
// if pli-socket condition is bad, we should not process pli commands any further
socket->pli_stop();
}
va_end(args);
}