Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / exe / nas / bin / SS_Main.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: SS_Main.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 ============================================
/************************************************************************
**
** Copyright (C) 2006, Sun Microsystems, Inc.
**
** Sun considers its source code as an unpublished, proprietary
** trade secret and it is available only under strict license provisions.
** This copyright notice is placed here only to protect Sun in the event
** the source is deemed a published work. Disassembly, decompilation,
** or other means of reducing the object code to human readable form
** is prohibited by the license agreement under which this code is
** provided to the user or company in possession of this copy.
**
*************************************************************************/
//
// @-ARCH-@_Main.cc is automatically generated from
// ss/exe/nas/bin/Bl_Main.cc, do not modify @-ARCH-@_Main.cc
// make necessary changes in ss/exe/nas/bin/Bl_Main.cc instead.
//
#include <string>
#include "Python.h"
#include "spix_sparc.h"
#include "MemorySync.h"
#include "SS_PliCommand.h"
#include "SS_IrqSync.h"
#include "SS_TlbSync.h"
#include "SS_ValSync.h"
#include "SS_ConfigObject.h"
#include "SS_PliSocket.h"
#include "SS_TrcStrand.h"
#include "SS_GoodBadTrap.h"
#include "@-ARCH-@_Model.h"
#include "@-ARCH-VF-@_Cpu.h"
#include "@-ARCH-VF-@_Core.h"
#include "@-ARCH-VF-@_Strand.h"
#include "@-ARCH-@_RegCompare.h"
#include "@-ARCH-@_Csr.h"
#include "@-ARCH-@_CsrReadWrite.h"
#define MAIN_ARCH_@-ARCH-@
static char error_buffer[80];
using namespace std;
class @-ARCH-@_Main : public @-ARCH-@_Model/*{{{*/
{
public:
@-ARCH-@_Main();
void init( int record, int replay );
uint_t step( uint_t n );
void dump_regs( );
int set_record;
int set_replay;
int set_trace;
protected:
SS_TrcStrand* trc_strand[@-ARCH-@_Model::NO_STRANDS];
@-ARCH-@_RegCompare* reg_comp[@-ARCH-@_Model::NO_STRANDS];
SS_PliSocket pli_socket;
SS_TimedTlb* inst_tlb[@-ARCH-@_Model::NO_CORES];
SS_TimedTlb* data_tlb[@-ARCH-@_Model::NO_CORES];
SS_TlbSync* tlb_sync[@-ARCH-@_Model::NO_STRANDS];
SS_IrqSync* irq_sync[@-ARCH-@_Model::NO_STRANDS];
SS_ValSync* val_sync[@-ARCH-@_Model::NO_STRANDS];
MemorySync* mem_sync;
@-ARCH-@_Csr* csr;
@-ARCH-@_CsrReadWrite* csr_sync;
std::string cfg_replay_fn;
std::string cfg_record_fn;
int cfg_socket;
int cfg_cosim;
int cfg_replay;
int cfg_record;
int cfg_reg_comp; // Nonzero means send state changes to the pli socket (DUT)
int cfg_tlb_sync; // Nonzero means perform tlb syncing
int cfg_mem_sync; // Nonzero means perform mem syncing
int cfg_pli_debug; // Debug pli socket commands
int cfg_mem_debug; // Debug memory sync and tso checker
int cfg_tso_debug; // Nonzero means perform tso checking
int cfg_tlb_debug;
int cfg_standalone; // Nonzero means there is no RTL or replay
int cfg_rstv_mask;
int cfg_dump_regs;
int cfg_tlb_sync_size; // max number of TimedTlb to keep
inline int check_strand( int strand_id );
void create_cpu_extra( int new_cpu_cnt, int no_core );
int count_core( string mask );
void cmp_init( int cpu_id, string mask, int ii=0 );
void cmp_write( int cpu_id, SS_PliCommand_CMP_WRITE& arg );
void pli_trace( uint_t tid );
void pli_trace_0x0( uint_t tid, uint64_t trc_pc );
SS_Registers::Index asr2index( uint8_t idx );
void set_cmpr_list(string sub, bool exclude);
uint_t step_count;
SS_GoodBadTrap gbt;
// INTP '00 00' is used to indicate a system-wide POR or warm-reset, the
// first time it shows up is before any 'STEP' command is issued, which
// indicates a POR. If it shows up again later, then it means a warm-reset,
// we will have to set the system to a warm-reset state in such case.
int intp0_count;
// the first INTP 'xx 01' for each strand is considered POW, after that
// it is WMR
bool first_intp1[@-ARCH-@_Model::NO_STRANDS];
};
/* }}}*/
@-ARCH-@_Main::@-ARCH-@_Main()/*{{{*/
:
set_record(0),
set_replay(0),
cfg_replay_fn(),
cfg_record_fn(),
cfg_cosim(0),
cfg_replay(0),
cfg_record(false),
cfg_reg_comp(0),
cfg_tlb_sync(0),
cfg_mem_sync(0),
cfg_pli_debug(0),
cfg_mem_debug(0),
cfg_tso_debug(0),
cfg_tlb_debug(0),
cfg_socket(0),
step_count(0),
set_trace(0),
cfg_standalone(0),
intp0_count(0),
cfg_tlb_sync_size(0)
{
int c, s;
csr_sync = new @-ARCH-@_CsrReadWrite();
csr = new @-ARCH-@_Csr();
csr->model = this;
mem_sync = 0; // Allocate in init() as it needs conf info in constructor
}
/*}}}*/
inline int @-ARCH-@_Main::check_strand( int strand_id )/*{{{*/
{
// when detect a un-initialized strand pointer, force a cosim miscompare
// on PC
if (!trc_strand[strand_id])
{
if (pli_socket.pli_ok())
{
fprintf(stderr, "ERROR: strand %d is not initialized, use -sas_run_args=-DTHREAD_MASK to specify valid strands.\n", strand_id);
sprintf(error_buffer, "%d: [swvp0,th%02d] <v:%016llx> <p:%016llx> [%08x] %s\n", 0, strand_id, 0, 0, 0, "ERROR");
pli_socket.write(error_buffer);
sprintf(error_buffer, "STEP: %d C %d %016llx\n", strand_id, 32, 0);
pli_socket.write(error_buffer);
pli_socket.flush();
pli_socket.pli_stop();
}
return -1;
}
return 0;
}
/*}}}*/
// by default we only instantiate one cpu, if more are needed, then those
// are instantiated on the fly, along with related objects.
void @-ARCH-@_Main::create_cpu_extra( int new_cpu_cnt, int no_core )/*{{{*/
{
int c, s;
int current_cpu_cnt = cpu_cnt();
if ((current_cpu_cnt >= new_cpu_cnt) ||
(@-ARCH-@_Model::NO_CPUS < new_cpu_cnt))
{
// current cpu count is no less than the new cpu count, do nothing.
return;
}
// create new cpu(s)
create_cpu_dynamic((new_cpu_cnt - current_cpu_cnt), no_core);
c = current_cpu_cnt * @-ARCH-@_Model::NO_CORES_PER_CPU;
for (; c < (new_cpu_cnt*@-ARCH-@_Model::NO_CORES_PER_CPU); c++)
{
// global cpu id
int pid = c / @-ARCH-@_Model::NO_CORES_PER_CPU;
// core id within a cpu
int cid = c % @-ARCH-@_Model::NO_CORES_PER_CPU;
@-ARCH-VF-@_Core* core = cpu_ptr(pid)->core[cid];
if (core)
{
inst_tlb[c] = new SS_TimedTlb(&core->inst_tlb, cfg_tlb_sync_size);
data_tlb[c] = new SS_TimedTlb(&core->data_tlb, cfg_tlb_sync_size);
}
}
s = current_cpu_cnt * @-ARCH-@_Model::NO_STRANDS_PER_CPU;
for (; s < (new_cpu_cnt*@-ARCH-@_Model::NO_STRANDS_PER_CPU); s++)
{
// global cpu id
int pid = s / @-ARCH-@_Model::NO_STRANDS_PER_CPU;
// global core id
int gcid = s / @-ARCH-@_Model::NO_STRANDS_PER_CORE;
// core id within a cpu
int cid = gcid % @-ARCH-@_Model::NO_CORES_PER_CPU;
// strand id iwthin a cpu
int sid = s % @-ARCH-@_Model::NO_STRANDS_PER_CPU;
@-ARCH-VF-@_Core* core = cpu_ptr(pid)->core[cid];
if (core && (cpu[pid]->strand[sid]))
{
core->inst_tlb.add_strand(cpu[pid]->strand[sid]);
core->data_tlb.add_strand(cpu[pid]->strand[sid]);
trc_strand[s] = new SS_TrcStrand(cpu[pid]->strand[sid]);
tlb_sync[s] = new SS_TlbSync(cpu[pid]->strand[sid],inst_tlb[gcid],data_tlb[gcid]);
irq_sync[s] = new SS_IrqSync(cpu[pid]->strand[sid]);
val_sync[s] = new SS_ValSync(cpu[pid]->strand[sid]);
reg_comp[s] = new @-ARCH-@_RegCompare((@-ARCH-VF-@_Strand*)cpu[pid]->strand[sid],&pli_socket);
// ToDo this should be one function call obj + fun passed as arguments.
cpu[pid]->strand[sid]->io->set_access_io(csr->access_io);
cpu[pid]->strand[sid]->io->set_access_io_obj((void*)csr);
// SPU_CWQCSR IR[4], HWE[3], BUSY[1], ENABLED[0]
#ifdef MAIN_ARCH_N2
cpu[pid]->strand[sid]->asi_map.set_asi_va_follow_me_mask(0x40,0x20,0x1f);
#else
cpu[pid]->strand[sid]->asi_map.set_asi_va_follow_me_mask(0x40,0x20,0x1b);
#endif
// SPU_CQ_SYNC ditto
#ifdef MAIN_ARCH_N2
cpu[pid]->strand[sid]->asi_map.set_asi_va_follow_me_mask(0x40,0x30,0x1f);
#else
cpu[pid]->strand[sid]->asi_map.set_asi_va_follow_me_mask(0x40,0x30,0x1b);
#endif
// SPU_MA_CTL IR[26], HWE[22], BUSY[16]
cpu[pid]->strand[sid]->asi_map.set_asi_va_follow_me_mask(0x40,0x80,0x4410000);
// set ASIs that allow multi-entry ASI FOLLOW-ME
val_sync[s]->set_multi_entry(0x53);
val_sync[s]->set_multi_entry(0x55);
val_sync[s]->set_multi_entry(0x56);
val_sync[s]->set_multi_entry(0x5d);
val_sync[s]->set_multi_entry(0x5e);
}
}
s = current_cpu_cnt * @-ARCH-@_Model::NO_STRANDS_PER_CPU;
for (; s < (new_cpu_cnt*@-ARCH-@_Model::NO_STRANDS_PER_CPU); s++)
first_intp1[s] = true;
}
/*}}}*/
void @-ARCH-@_Main::init( int record, int replay )/*{{{*/
{
int s;
// First get the val_xxx parameters from the diag.conf file
SS_ConfigReader config("diag.conf");
SS_ConfigValue* val_socket = config.value("socket0","socket");
SS_ConfigValue* val_pli_log = config.value("socket0","pli_log");
SS_ConfigValue* val_replay_log = config.value("socket0","replay_log");
SS_ConfigValue* val_pli_debug = config.value("socket0","debug_level");
SS_ConfigValue* val_reg_comp = config.value("socket0","reg_cmp");
SS_ConfigValue* val_tlb_sync = config.value("socket0","tlb_sync");
SS_ConfigValue* val_tlb_debug = config.value("socket0","tlb_debug");
SS_ConfigValue* val_mem_sync = config.value("socket0","mem_model");
SS_ConfigValue* val_mem_debug = config.value("swvmem0","debug_level");
SS_ConfigValue* val_tso_check = config.value("swvmem0","tso_checker");
SS_ConfigValue* val_ras_enable = config.value("socket0","ras_enable");
SS_ConfigValue* val_rstv_mask = config.value("socket0","rstv_mask");
SS_ConfigValue* val_dump_regs = config.value("socket0","dump_regs");
SS_ConfigValue* val_cmpr_list = config.value("socket0","cmpr_list");
SS_ConfigValue* val_tlb_sync_size = config.value("socket0","tlb_sync_size");
// we must have this value before creating cpu
cfg_tlb_sync_size = (val_tlb_sync_size && val_tlb_sync_size->is_num()) ? val_tlb_sync_size->num()->value : 128;
// CMP value for asi=0x41/va=0x0, asi=0x41/va=0x50, and other related CMPs.
// the value comes in the fomrat of [0..9,a..f,x],
// e.g., 00xx11 means va=0x0 : 0xff00ff, and va=0x50 : 000011. In other
// words, core0 and core2 are available, and strand0 and strand4 are
// enabled. Every 2 chars (i.e., 8 bits) from the right represents one
// core, if any one of the 2 chars is 'x', then the core is considered
// not available. Any un-specified cores are considered not available. If
// no strand is specified as enabled, then the lowest strand is set to be
// enabled.
// process CPU option, if specified
SS_ConfigValue* val_num_cpu = config.value("swvmem0","cpu");
if (val_num_cpu)
{
int num_cpu = (val_num_cpu->is_num()) ? val_num_cpu->num()->value : 1;
create_cpu_extra(num_cpu, @-ARCH-@_Model::NO_CORES_PER_CPU);
// default is having cpu0 available and cpu0.core0.strand0 enabled.
// If other masking is desired, then THREAD_MASK should be used instead.
cpu_ptr(0)->strand_available.set_unmasked(0xffffffffffffffff);
cpu_ptr(0)->strand_enable_status.set_unmasked(0xffffffffffffffff);
cpu_ptr(0)->strand_enable = 0xffffffffffffffff;
cpu_ptr(0)->xir_steering = 0xffffffffffffffff;
cpu_ptr(0)->strand_running = 0x1;
cpu_ptr(0)->strand_running_update(cpu_ptr(0)->strand[0]->strand_id());
}
if (cpu_cnt() == 0)
{
// if no CPU is specified, then process THREAD_MASKs.
for (int i = 0; i < @-ARCH-@_Model::NO_CPUS; i++)
{
int no_core = 0;
char thd_mask[32];
sprintf(thd_mask, "thread_mask%d", i);
SS_ConfigValue* val_thd_mask0 = config.value("swvmem0",thd_mask);
if ((val_thd_mask0) && (val_thd_mask0->is_str()))
{
no_core = count_core(val_thd_mask0->str()->value);
}
if (val_thd_mask0)
{
if (val_thd_mask0->is_str())
{
if (cpu_cnt() < i+1)
{
create_cpu_extra(i+1, no_core);
}
cmp_init(i, val_thd_mask0->str()->value);
}
else
{
fprintf(stdout, "ERROR: input THREAD_MASK%d is not a string: ", i);
val_thd_mask0->reflect();
}
}
}
}
cfg_socket = val_socket && val_socket->is_num() ? val_socket->num()->value : 0;
cfg_cosim = cfg_socket > 0;
cfg_replay = cfg_socket == 0;
// First get the diag.conf settings.
// If pli_log given and none zero then record
if (!val_pli_log)
cfg_record = false;
else if (val_pli_log->is_num())
cfg_record = val_pli_log->num()->value > 0;
else if (val_pli_log->is_var())
{
cfg_record = true;
cfg_record_fn = val_pli_log->var()->value;
}
else if (val_pli_log->is_str())
{
cfg_record = true;
cfg_record_fn = val_pli_log->str()->value;
}
// If the frontend say we should record we should record !!!
if (record)
cfg_record = true;
// If replay_log is given and none zero then replay
if (!val_replay_log)
cfg_replay = false;
else if (val_replay_log->is_num())
cfg_replay = val_replay_log->num()->value > 0;
else if (val_replay_log->is_var())
{
cfg_replay = true;
cfg_replay_fn = val_replay_log->var()->value;
}
else if (val_replay_log->is_str())
{
cfg_replay = true;
cfg_replay_fn = val_replay_log->str()->value;
}
// If the frontend says we should replay we should replay
if (replay)
cfg_replay = true;
// Digest all the config info in elegant variables
cfg_reg_comp = (val_reg_comp && val_reg_comp->is_num()) ? val_reg_comp->num()->value : 0;
cfg_tlb_sync = (val_tlb_sync && val_tlb_sync->is_num()) ? val_tlb_sync->num()->value : 0;
cfg_mem_sync = (val_mem_sync && val_mem_sync->is_num()) ? val_mem_sync->num()->value : 0;
cfg_pli_debug = (val_pli_debug && val_pli_debug->is_num()) ? val_pli_debug->num()->value : 0;
cfg_tlb_debug = (val_tlb_debug && val_tlb_debug->is_num()) ? val_tlb_debug->num()->value : 0;
cfg_mem_debug = (val_mem_debug && val_mem_debug->is_num()) ? val_mem_debug->num()->value : 0;
cfg_tso_debug = (val_tso_check && val_tso_check->is_num()) ? val_tso_check->num()->value : 0;
cfg_rstv_mask = (val_rstv_mask && val_rstv_mask->is_num()) ? val_rstv_mask->num()->value : 0;
cfg_dump_regs = (val_dump_regs && val_dump_regs->is_num()) ? val_dump_regs->num()->value : 0;
// Now apply the cfg_xxx variables to setup the simulation
if (cfg_replay)
{
pli_socket.open_replay(cfg_replay_fn);
if (cfg_record)
pli_socket.open_record(cfg_record_fn);
}
else if (cfg_cosim)
{
pli_socket.open_cosim(cfg_socket);
if (cfg_record)
pli_socket.open_record(cfg_record_fn);
if (cfg_pli_debug > 0)
for (int s=0;s<(cpu_cnt()*@-ARCH-@_Model::NO_STRANDS_PER_CPU);s++)
if (reg_comp[s])
reg_comp[s]->debug_output(stderr);
}
else
{
// there will be no RTL or replay log to provide execution commands,
// just step through all strands in round robin.
cfg_standalone = true;
gbt.read_good_bad_trap(cpu[0]->strand[0]->va_bits());
}
// set debug flag
pli_socket.debug(cfg_pli_debug, cfg_reg_comp);
for (s = 0; s < (cpu_cnt()*@-ARCH-@_Model::NO_STRANDS_PER_CPU); s++)
{
if (tlb_sync[s])
{
tlb_sync[s]->debug(cfg_tlb_debug);
// set up connection with RTL testbench socket to report error
tlb_sync[s]->socket = &pli_socket;
}
}
// set up connection with RTL testbench socket to report error
for (int c = 0; c < (cpu_cnt()*@-ARCH-@_Model::NO_CORES_PER_CPU); c++)
{
if (inst_tlb[c])
{
inst_tlb[c]->socket = &pli_socket;
data_tlb[c]->socket = &pli_socket;
}
}
mem_sync = new MemorySync((cpu_cnt()*@-ARCH-@_Model::NO_STRANDS_PER_CPU),@-ARCH-@_Model::NO_STRANDS_PER_CORE,@-ARCH-@_Model::NO_CORES_PER_CPU,cfg_mem_debug,cfg_tso_debug,cfg_mem_sync);
// set up connection with RTL testbench socket to report error
mem_sync->socket = &pli_socket;
set_trace = cfg_pli_debug;
// RAS enable for all cpus
if(val_ras_enable) {
for (int i = 0; i < cpu_cnt(); i++)
{
cpu[i]->ras_enable(NULL);
}
}
// RST_VEC_MASK
if (cfg_rstv_mask)
{
for (int p = 0; p < cpu_cnt(); p++)
{
SS_Strand* strand = cpu[p]->strand[0];
strand->asi_map.wr64(strand, 0x45, 0x18, 0x1);
}
hard_reset();
}
// register comparison list
if (val_cmpr_list)
{
string cfg_cmpr_list;
if (val_cmpr_list->is_var())
cfg_cmpr_list = val_cmpr_list->var()->value;
else if (val_cmpr_list->is_str())
cfg_cmpr_list = val_cmpr_list->str()->value;
// G/W/F/PC - only compare those
// -/G/W/F/PC - exclude those from comparison
bool exclude = false;
int start_pos = 0;
if (cfg_cmpr_list[0] == '-')
{
exclude = true;
start_pos = 2;
}
else
{
// turn off comparison on all registers first, then add back the ones
// specified in CMPR_LIST
for (int i = 0; i < @-ARCH-@_Model::NO_STRANDS; i++)
if (reg_comp[i])
reg_comp[i]->cmpr_off();
}
// process the cmpr_list string
bool done = false;
while (!done)
{
string sub;
int end_pos = cfg_cmpr_list.find('/', start_pos);
if (end_pos >= 0)
{
sub = cfg_cmpr_list.substr(start_pos, (end_pos - start_pos));
start_pos = end_pos + 1;
}
else
{
sub = cfg_cmpr_list.substr(start_pos);
done = true;
}
if (sub.size() > 0)
set_cmpr_list(sub, exclude);
}
}
}
/*}}}*/
void @-ARCH-@_Main::set_cmpr_list(string sub, bool exclude)/*{{{*/
{
int ii = reg_comp[0]->name_2_index(sub);
if (exclude)
{
for (int i = 0; i < @-ARCH-@_Model::NO_STRANDS; i++)
if (reg_comp[i])
reg_comp[i]->cmpr_off(ii);
}
else
{
for (int i = 0; i < @-ARCH-@_Model::NO_STRANDS; i++)
if (reg_comp[i])
reg_comp[i]->cmpr_on(ii);
}
}
/*}}}*/
int @-ARCH-@_Main::count_core(string mask)/*{{{*/
{
// CMP masking, e.g., 00xx0031 means core0, core1, and core3 are available,
// strand0, strand4, and strand5 are enabled.
// counting the number of cores to be allocated.
string var2 = mask;
if (var2.size() % 2)
return (var2.size()/2 + 1);
else
return var2.size()/2;
}
void @-ARCH-@_Main::cmp_init(int cid, string mask, int ii)/*{{{*/
{
// CMP masking, e.g., 00xx0031 means core0, core1, and core3 are available,
// strand0, strand4, and strand5 are enabled.
uint64_t available = 0;
uint64_t enabled = 0;
int core = 0;
string var2 = mask;
if (var2.size() % 2)
var2.insert(0, "0");
for (int j = var2.size()-2; j >= 0; j -= 2)
{
string var3 = var2.substr(j, 2);
if ((var3.find("x") == string::npos) && (var3.find("X") == string::npos))
{
// hex value, the core is available
available |= (0xffULL) << (8*core);
enabled |= ((uint64_t)strtoul(var3.c_str(), NULL, 16)) << (8*core);
}
else
{
// with 'x', the core is not available
available |= (0x00) << (8*core);
enabled |= (0x00) << (8*core);
}
core++;
}
// set CMP (0x41) values according to runtime thread_mask options
cpu_ptr(cid)->strand_available.set_unmasked(available);
cpu_ptr(cid)->strand_enable_status.set_unmasked(available);
cpu_ptr(cid)->strand_enable = available;
cpu_ptr(cid)->xir_steering = available;
cpu_ptr(cid)->strand_running = enabled;
cpu_ptr(cid)->strand_running_update(cpu_ptr(cid)->strand[0]->strand_id());
}
/*}}}*/
void @-ARCH-@_Main::dump_regs( )/*{{{*/
{
if (cfg_dump_regs)
for (int p = 0; p < cpu_cnt(); p++)
for (int s = 0; s < @-ARCH-@_Model::NO_STRANDS_PER_CPU; s++)
if (cpu_ptr(p)->strand[s]->running)
reg_comp[(p*@-ARCH-@_Model::NO_STRANDS_PER_CPU)+s]->dump_regs();
}
/*}}}*/
uint_t @-ARCH-@_Main::step( uint_t n )/*{{{*/
{
// step(n) grants the pli socket to step n instructions forward
// When n reaches 0 step() return 0. If a PLI_QUIT command is
// received step() return -1. In all other cases, when something
// went wrong, step() returns the remaining n (n > 0).
if (cfg_standalone)
{
if (cfg_reg_comp)
for (int s = 0; s < (cpu_cnt()*@-ARCH-@_Model::NO_STRANDS_PER_CPU); s++)
if (reg_comp[s])
reg_comp[s]->initialise();
// in standalone mode, just step through all strands in round robin
while (n)
{
for (int p = 0; p < cpu_cnt(); p++)
{
int ss = p * @-ARCH-@_Model::NO_STRANDS_PER_CPU;
for (int s = 0; s < @-ARCH-@_Model::NO_STRANDS_PER_CPU; s++)
{
if (cpu[p] && cpu[p]->strand[s])
{
SS_Strand* strand = cpu[p]->strand[s];
strand->flush_va(strand->pc());
if (strand->trc_step(1) != 0)
{
// likely hit a breakpoint
return -1;
}
if (strand->running)
{
step_count++;
pli_trace(ss+s);
if (cfg_reg_comp)
reg_comp[ss+s]->compare(trc_strand[ss+s]->iw);
}
if (gbt.hit_good_bad_trap(strand->pc()) != 0)
{
// hit a good/bad trap
dump_regs();
return -1;
}
}
}
}
n--;
}
return 0;
}
while (n)
{
// When we set breakpoints in the interactive mode then we
// already have read the plic socket command and the DUT is
// waiting for the results. So jump to the cause ...
if (pli_socket.read(1) == 0)
return -2;
switch (pli_socket.get8(0))
{
case SS_PliCommand::PLI_QUIT:
{
SS_PliCommand_QUIT arg(pli_socket);
pli_socket.close();
return -1;
break;
}
case SS_PliCommand::PLI_SSTEP:
{
step_count++;
SS_PliCommand_SSTEP@-PLICMD-@ arg(pli_socket,&step_count);
n--;
if (check_strand(arg.tid) != 0) break;
if (!reg_comp[arg.tid]->is_initialise() && cfg_reg_comp)
reg_comp[arg.tid]->initialise();
if (cfg_tlb_sync)
SS_TlbSync::inst_tlb_read(tlb_sync[arg.tid]);
int pid = arg.tid / @-ARCH-@_Model::NO_STRANDS_PER_CPU;
int sid = arg.tid % @-ARCH-@_Model::NO_STRANDS_PER_CPU;
SS_Strand* strand = cpu[pid]->strand[sid];
uint64_t trc_pc = strand->pc();
if (!irq_sync[arg.tid]->check())
{
strand->flush_va(strand->pc());
strand->trc_step(1);
pli_trace(arg.tid);
}
else
{
// a pending interrupt is taken, we need to generate an instruciton
// line in cosim log
pli_trace_0x0(arg.tid, trc_pc);
}
if (cfg_reg_comp)
{
if (!pli_socket.pli_ok())
{
// if pli-socket has problem (e.g., msync, tlbsync, etc encounter
// error), we should force cosim to stop as soon as possible, one
// trick is to force %g7 to a weird value.
(strand->set_state)(strand,SS_Registers::G7, 0xffffffffffffffff);
}
reg_comp[arg.tid]->compare(trc_strand[arg.tid]->iw);
}
break;
}
case SS_PliCommand::PLI_SSTEP_N:
{
step_count++;
SS_PliCommand_SSTEP_N@-PLICMD-@ arg(pli_socket,&step_count);
if (check_strand(arg.tid) != 0) break;
if (!reg_comp[arg.tid]->is_initialise() && cfg_reg_comp)
reg_comp[arg.tid]->initialise();
int pid = arg.tid / @-ARCH-@_Model::NO_STRANDS_PER_CPU;
int sid = arg.tid % @-ARCH-@_Model::NO_STRANDS_PER_CPU;
SS_Strand* strand = cpu[pid]->strand[sid];
for (int i = 0; i < arg.count; i++)
{
n--;
if (cfg_tlb_sync)
SS_TlbSync::inst_tlb_read(tlb_sync[arg.tid]);
uint64_t trc_pc = strand->pc();
if (!irq_sync[arg.tid]->check())
{
strand->flush_va(strand->pc());
strand->trc_step(1);
pli_trace(arg.tid);
}
else
{
// a pending interrupt is taken, we need to generate an instruciton
// line in cosim log
pli_trace_0x0(arg.tid, trc_pc);
}
}
if (cfg_reg_comp)
if (!pli_socket.pli_ok())
{
// if pli-socket has problem (e.g., msync, tlbsync, etc encounter
// error), we should force cosim to stop as soon as possible, one
// trick is to force %g7 to a weird value.
(strand->set_state)(strand,SS_Registers::G7, 0xffffffffffffffff);
}
reg_comp[arg.tid]->compare(trc_strand[arg.tid]->iw);
break;
}
case SS_PliCommand::PLI_ITLBREAD:
{
SS_PliCommand_ITLBREAD@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_tlb_sync)
tlb_sync[arg.tid]->pli_inst_tlb_read(arg.rtime);
break;
}
case SS_PliCommand::PLI_ITLBWRITE:
{
SS_PliCommand_ITLBWRITE@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_tlb_sync)
tlb_sync[arg.tid]->pli_inst_tlb_write(arg.wtime,arg.entry);
break;
}
case SS_PliCommand::PLI_DTLBREAD:
{
SS_PliCommand_DTLBREAD@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_tlb_sync)
tlb_sync[arg.tid]->pli_data_tlb_read(arg.rtime);
break;
}
case SS_PliCommand::PLI_DTLBWRITE:
{
SS_PliCommand_DTLBWRITE@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_tlb_sync)
tlb_sync[arg.tid]->pli_data_tlb_write(arg.wtime,arg.entry);
break;
}
case SS_PliCommand::PLI_IHWTW:
{
SS_PliCommand_IHWTW@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_tlb_sync)
tlb_sync[arg.tid]->pli_inst_hwtw(arg.wtime,arg.va,arg.entry);
break;
}
case SS_PliCommand::PLI_DHWTW:
{
SS_PliCommand_DHWTW@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_tlb_sync)
tlb_sync[arg.tid]->pli_data_hwtw(arg.wtime,arg.va,arg.asi,arg.entry);
break;
}
case SS_PliCommand::PLI_TLBLOOKUP:
{
SS_PliCommand_TLBLOOKUP@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_tlb_sync)
tlb_sync[arg.tid]->pli_tlb_lookup(arg.rtime,arg.asi);
break;
}
case SS_PliCommand::PLI_DTLBREAD_POP:
{
SS_PliCommand_DTLBREAD_POP@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_tlb_sync)
tlb_sync[arg.tid]->pli_data_tlb_read_pop(arg.ptime);
break;
}
case SS_PliCommand::PLI_MEM_ST_ISSUE:
{
SS_PliCommand_MEM_ST_ISSUE@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_mem_sync)
{
StoreIssueCmd mem_oper((enum INSTR_TYPE)arg.itype,arg.tid,0,arg.pa,arg.data,arg.size_vec,arg.time);
mem_sync->handleStoreIssue(mem_oper);
}
break;
}
case SS_PliCommand::PLI_MEM_ST_L2_COMMIT:
{
SS_PliCommand_MEM_ST_L2_COMMIT@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
bool cas_cmp = (arg.size_vec == 0) ? false : true;
if (pli_socket.pli_ok() && cfg_mem_sync)
{
StoreCommitCmd mem_oper(arg.tid,arg.inv_vec,0,arg.pa,arg.size_vec,arg.l2hit,cas_cmp,arg.time);
mem_sync->handleStoreCommit(mem_oper);
}
break;
}
case SS_PliCommand::PLI_MEM_ST_INV:
{
SS_PliCommand_MEM_ST_INV@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_mem_sync)
{
StoreInvCmd mem_oper(arg.cid,arg.tid,arg.pa,arg.time);
mem_sync->handleStoreInv(mem_oper);
}
break;
}
case SS_PliCommand::PLI_MEM_ST_UPDATE:
{
SS_PliCommand_MEM_ST_UPDATE@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_mem_sync)
{
StoreUpdateCmd mem_oper(arg.tid,arg.pa,arg.time);
mem_sync->handleStoreUpdate(mem_oper);
}
break;
}
case SS_PliCommand::PLI_MEM_ST_ACK:
{
SS_PliCommand_MEM_ST_ACK@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_mem_sync)
{
StoreAckCmd mem_oper(arg.tid,0,arg.rmo,arg.time);
mem_sync->handleStoreAck(mem_oper);
}
break;
}
case SS_PliCommand::PLI_MEM_LD_ISSUE:
{
SS_PliCommand_MEM_LD_ISSUE@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_mem_sync)
{
LoadIssueCmd mem_oper((enum INSTR_TYPE)arg.itype,arg.tid,0,arg.pa,(1 << arg.size),0,arg.time);
mem_sync->handleLoadIssue(mem_oper);
}
break;
}
case SS_PliCommand::PLI_MEM_LD_DATA:
{
SS_PliCommand_MEM_LD_DATA@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_mem_sync)
{
LoadDataCmd mem_oper(arg.tid,0,arg.pa,0,(enum DATA_SRC)arg.src,0,arg.time);
mem_sync->handleLoadData(mem_oper);
}
break;
}
case SS_PliCommand::PLI_MEM_LD_FILL:
{
SS_PliCommand_MEM_LD_FILL@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_mem_sync)
{
LoadFillCmd mem_oper(arg.tid,0,arg.pa,arg.time);
mem_sync->handleLoadFill(mem_oper);
}
break;
}
case SS_PliCommand::PLI_MEM_EVICT:
{
SS_PliCommand_MEM_EVICT@-PLICMD-@ arg(pli_socket);
if (pli_socket.pli_ok() && cfg_mem_sync)
{
EvictCmd mem_oper(arg.inv_vec,0,0,arg.pa,arg.time);
mem_sync->handleEvict(mem_oper);
}
break;
}
case SS_PliCommand::PLI_MEM_EVICT_INV:
{
SS_PliCommand_MEM_EVICT_INV@-PLICMD-@ arg(pli_socket);
if (pli_socket.pli_ok() && cfg_mem_sync)
{
EvictInvCmd mem_oper(arg.cid,arg.bid,0,0,arg.time);
mem_sync->handleEvictInv(mem_oper);
}
break;
}
case SS_PliCommand::PLI_MEM_SLAM:
{
SS_PliCommand_MEM_SLAM@-PLICMD-@ arg(pli_socket);
if (pli_socket.pli_ok() && cfg_mem_sync)
{
StoreIssueCmd mem_oper((enum INSTR_TYPE)0,0,0,arg.pa,arg.data,arg.size,arg.time);
mem_sync->handleStoreSlam(mem_oper);
#ifdef TODO
//TODO do we handle reset_gen properly in store_slam?
try {
mem_sync->handleStoreSlam(mem_oper);
}
catch ( ResetGen &e ) {
((@-ARCH-@_RegReader*)regReader_)->handleResetGen(@-ARCH-@_System::RESET_GEN);
}
catch (...) {
throw;
}
#endif
}
break;
}
case SS_PliCommand::PLI_MEM_LD_POP:
{
SS_PliCommand_MEM_LD_POP@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_mem_sync)
mem_sync->handleLoadPop(arg.tid);
break;
}
case SS_PliCommand::PLI_MEM_ST_POP:
{
SS_PliCommand_MEM_ST_POP@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (pli_socket.pli_ok() && cfg_mem_sync)
mem_sync->handleStorePop(arg.tid);
break;
}
case SS_PliCommand::PLI_MEM_CHECK:
{
SS_PliCommand_MEM_CHECK@-PLICMD-@ arg(pli_socket);
if (pli_socket.pli_ok() && cfg_mem_sync)
mem_sync->handleMemoryCheck(arg.pa,arg.data,8);
break;
}
case SS_PliCommand::PLI_MEM_DMA_STORE:
{
SS_PliCommand_MEM_DMA_STORE@-PLICMD-@ arg(pli_socket);
if (pli_socket.pli_ok() && cfg_mem_sync){
DmaStoreCmd memCmd(0, 0, arg.pa, arg.data, arg.size_vec, arg.inv, arg.tsize, arg.time);
mem_sync->handleDmaStore(memCmd);
#ifdef TODO
//TODO do we handle reset_gen properly in dma_store?
try {
mem_sync->handleDmaStore(memCmd);
}
catch ( ResetGen &e ) {
((@-ARCH-@_RegReader*)regReader_)->handleResetGen(@-ARCH-@_System::RESET_GEN);
}
catch (...) {
throw;
}
#endif
}
break;
}
case SS_PliCommand::PLI_MEM_DMA_STORE_START:
{
SS_PliCommand_MEM_DMA_STORE_START@-PLICMD-@ arg(pli_socket);
if (pli_socket.pli_ok() && cfg_mem_sync){
DmaStoreCmd memCmd(0, 0, arg.pa, 0, 0, 0, arg.tsize, arg.time);
mem_sync->handleDmaStoreStart(memCmd);
}
break;
}
case SS_PliCommand::PLI_INTP:
{
SS_PliCommand_INTP@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (!pli_socket.pli_ok()) break;
switch (arg.tt)
{
case SS_Trap::RESERVED: // warm reset
{
for (int s = 0; s < (cpu_cnt()*@-ARCH-@_Model::NO_STRANDS_PER_CPU); s++)
if (tlb_sync[s])
tlb_sync[s]->pli_flush();
mem_sync->flushAll();
intp0_count++;
if (intp0_count > 1)
{
// we are seeing the second or more "INTP 00 00", it is
// considered a wmr
csr->warm_reset();
// the warm_reset() is invoked by "INTP 00 00", do not throw a
// WMR trap here, the following "INTP xx 01" will take care of
// that.
warm_reset(false);
}
irq_sync[arg.tid]->raise(SS_Trap::Type(arg.tt));
break;
}
case SS_Trap::POWER_ON_RESET:
{
// the first encounter of "INTP xx 01" for each strand is
// considered POR, the seond and up are considered WMR
if (first_intp1[arg.tid])
{
first_intp1[arg.tid] = false;
irq_sync[arg.tid]->raise(SS_Trap::Type(arg.tt));
}
else
{
// enter a WMR, clean up other pending interrupts
irq_sync[arg.tid]->clear_list();
irq_sync[arg.tid]->raise(SS_Trap::RESET_GEN_WMR);
}
irq_sync[arg.tid]->check();
break;
}
case SS_Trap::EXTERNALLY_INITIATED_RESET:
// enter a XIR, clean up other pending interrupts
irq_sync[arg.tid]->clear_list();
irq_sync[arg.tid]->raise(SS_Trap::Type(arg.tt));
break;
case SS_Trap::DATA_ACCESS_ERROR:
case SS_Trap::INTERNAL_PROCESSOR_ERROR:
{
mem_sync->flushMsyncCallback(arg.tid);
irq_sync[arg.tid]->raise(SS_Trap::Type(arg.tt));
break;
}
case SS_Trap::INSTRUCTION_ACCESS_MMU_ERROR:
{
int pid = arg.tid / @-ARCH-@_Model::NO_STRANDS_PER_CPU;
int sid = arg.tid % @-ARCH-@_Model::NO_STRANDS_PER_CPU;
SS_Strand* strand = cpu[pid]->strand[sid];
strand->inst_mmu_error = true;
strand->flush_tte_all();
break;
}
case SS_Trap::DATA_ACCESS_MMU_ERROR:
{
int pid = arg.tid / @-ARCH-@_Model::NO_STRANDS_PER_CPU;
int sid = arg.tid % @-ARCH-@_Model::NO_STRANDS_PER_CPU;
SS_Strand* strand = cpu[pid]->strand[sid];
strand->data_mmu_error = true;
strand->flush_tte_all();
break;
}
default:
{
irq_sync[arg.tid]->raise(SS_Trap::Type(arg.tt));
break;
}
}
break;
}
case SS_PliCommand::PLI_ASR_READ:
{
SS_PliCommand_ASR_READ@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (!pli_socket.pli_ok()) break;
val_sync[arg.tid]->ctr_read(asr2index(arg.asr),arg.data);
break;
}
case SS_PliCommand::PLI_ASR_WRITE:
{
SS_PliCommand_ASR_WRITE@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (!pli_socket.pli_ok()) break;
if (arg.asr == 0x46)
{
// HVER. Strands on a physical core share the same hver, but our
// internal implementation gives each strand its own hver, so we
// have to update the hver of all the strands (on the same core)
// together
int core_id = arg.tid / @-ARCH-@_Model::NO_STRANDS_PER_CORE;
for (int i = (core_id*@-ARCH-@_Model::NO_STRANDS_PER_CORE); i < ((core_id+1)*@-ARCH-@_Model::NO_STRANDS_PER_CORE); i++)
val_sync[i]->ctr_write(asr2index(arg.asr),arg.data);
}
else
{
val_sync[arg.tid]->ctr_write(asr2index(arg.asr),arg.data);
}
break;
}
case SS_PliCommand::PLI_ASI_READ:
{
SS_PliCommand_ASI_READ@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (!pli_socket.pli_ok()) break;
val_sync[arg.tid]->asi_read(arg.asi,arg.va,arg.data);
break;
}
case SS_PliCommand::PLI_ASI_WRITE:
{
SS_PliCommand_ASI_WRITE@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (!pli_socket.pli_ok()) break;
val_sync[arg.tid]->asi_write(arg.asi,arg.va,arg.data);
break;
}
case SS_PliCommand::PLI_CMP_WRITE:
{
SS_PliCommand_CMP_WRITE arg(pli_socket);
if (check_strand(0) != 0) break;
if (!pli_socket.pli_ok()) break;
cmp_write(0, arg);
break;
}
case SS_PliCommand::PLI_CSR_READ:
{
SS_PliCommand_CSR_READ@-PLICMD-@ arg(pli_socket);
if (!pli_socket.pli_ok()) break;
csr_sync->pliReadCsrReg(csr,arg.pa,arg.data,arg.le,-1);
break;
}
case SS_PliCommand::PLI_CSR_WRITE:
{
SS_PliCommand_CSR_WRITE@-PLICMD-@ arg(pli_socket);
if (!pli_socket.pli_ok()) break;
csr_sync->pliWriteCsrReg(csr,arg.pa,arg.data,arg.le,-1);
break;
}
case SS_PliCommand::PLI_CMP_WRITE_MN:
{
SS_PliCommand_CMP_WRITE_MN arg(pli_socket);
if (check_strand(arg.nid*@-ARCH-@_Model::NO_STRANDS_PER_CPU) != 0) break;
if (!pli_socket.pli_ok()) break;
cmp_write(arg.nid, SS_PliCommand_CMP_WRITE(arg.va, arg.data));
break;
}
case SS_PliCommand::PLI_CSR_READ_MN:
{
SS_PliCommand_CSR_READ_MN@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.tid) != 0) break;
if (!pli_socket.pli_ok()) break;
csr_sync->pliReadCsrReg(csr,arg.pa,arg.data,arg.le,arg.tid);
break;
}
case SS_PliCommand::PLI_CSR_WRITE_MN:
{
SS_PliCommand_CSR_WRITE_MN@-PLICMD-@ arg(pli_socket);
if (check_strand(arg.nid*@-ARCH-@_Model::NO_STRANDS_PER_CPU) != 0) break;
if (!pli_socket.pli_ok()) break;
csr_sync->pliWriteCsrReg(csr,arg.pa,arg.data,arg.le,(arg.nid*@-ARCH-@_Model::NO_STRANDS_PER_CPU));
break;
}
case SS_PliCommand::PLI_SSTEP_SNIPER:
{
step_count++;
SS_PliCommand_SSTEP_SNIPER@-PLICMD-@ arg(pli_socket, &step_count);
if (check_strand(arg.tid) != 0) break;
if (!pli_socket.pli_ok()) break;
mem_sync->handleSniper(arg.tid, arg.pa, (INSTR_TYPE)arg.itype, arg.data);
break;
}
default:
{
fprintf(stderr,"Received strange PLI command %02x, socket error ?!\n", pli_socket.get8(0));
// read & display a few more bytes and then close down socket properly
pli_socket.debug(99);
pli_socket.read(4);
pli_socket.close();
assert(0);
break;
}
}
fflush(stderr);
fflush(stdout);
}
return 0;
}
/*}}}*/
void @-ARCH-@_Main::cmp_write( int cid, SS_PliCommand_CMP_WRITE& arg )/*{{{*/
{
// CMP_WRITE command does not carry the strand_id info we need to
// prevent all strands from getting parked. So we use strand_id 0
// for this purpose.
switch (arg.va)
{
case 0x10:
// POR: strand_available (0x0) ---> strand_enable_status (0x10)
// ---> strand_enable (0x20)
// ---> xir_steering (0x30)
// WMR: no change: strand_available (0x0) & strand_enable (0x20)
// strand_enable (0x20) ---> strand_enable_status (0x10)
// ---> xir_steering (0x30)
// testbench will send over 'strand_enable_status' (0x10) during POR,
// we should propogate the value to 0x0/0x20/0x30
if (intp0_count <= 1)
{
// during POR
cpu_ptr(cid)->strand_available.set_unmasked(arg.data);
cpu_ptr(cid)->strand_enable_status.set_unmasked(arg.data);
cpu_ptr(cid)->strand_enable = arg.data;
cpu_ptr(cid)->xir_steering = arg.data;
// provide msync strand_enable info for cache invalidation process
if (mem_sync)
mem_sync->setCoreEnable((@-ARCH-@_Model::NO_CORES_PER_CPU*cid/8), arg.data);
}
else
{
// after POR, strand_available should not change, other values must
// be masked by strand_available. strand_enable (0x20) will not change
// during wmr, either.
uint64_t mask_data = arg.data & cpu_ptr(cid)->strand_available();
cpu_ptr(cid)->strand_enable_status.set_unmasked(mask_data);
cpu_ptr(cid)->xir_steering = mask_data;
}
break;
case 0x50:
cpu_ptr(cid)->strand_running = arg.data;
break;
case 0x58:
cpu_ptr(cid)->strand_running_update(0,2,arg.data);
break;
default:
pli_socket.pli_stop();
fprintf(stderr,"PLI: ERROR: CMP_WRITE unexpected va=0x%x\n",arg.va);
break;
}
}
/*}}}*/
void @-ARCH-@_Main::pli_trace( uint_t tid )/*{{{*/
{
if (reg_comp[tid]->is_cmpr(SS_RegCompare::CTR_INSTR))
{
const char* fmt = "%d: [swvp0,th%02d] <v:%016llx> <p:%016llx> [%08x] %s %s\n";
char str[1024];
char str_inst[512];
char str_trap[512];
SS_TrapInfo* info = &SS_Trap::table[trc_strand[tid]->trap_type];
if (info->disrupting)
{
sprintf(str_trap,"(Interrupted %s)",info->name);
}
else if (trc_strand[tid]->get_trap_mode() == SS_Tracer::INST_TRAP)
{
switch (trc_strand[tid]->trap_type)
{
case SS_Trap::INSTRUCTION_ACCESS_MMU_MISS:
case SS_Trap::FAST_INSTRUCTION_ACCESS_MMU_MISS:
sprintf(str_trap,"(I-miss %#x)",trc_strand[tid]->trap_type);
break;
default:
sprintf(str_trap,"(I-mmu trap %#x)",trc_strand[tid]->trap_type);
break;
}
}
else if (trc_strand[tid]->get_trap_mode() == SS_Tracer::DATA_TRAP)
{
switch (trc_strand[tid]->trap_type)
{
case SS_Trap::DATA_ACCESS_MMU_MISS:
case SS_Trap::FAST_DATA_ACCESS_MMU_MISS:
sprintf(str_trap,"(D-miss %#x)",trc_strand[tid]->trap_type);
break;
default:
sprintf(str_trap,"(D-mmu trap %#x)",trc_strand[tid]->trap_type);
break;
}
}
else
{
sprintf(str_trap,"");
}
uint32_t _iw = trc_strand[tid]->iw;
SS_Vaddr _pc = trc_strand[tid]->pc_va;
size_t n = spix_sparc_dis(str_inst,512,spix_sparc_iop(SPIX_SPARC_V9,&_iw),&_iw,_pc);
sprintf(str,fmt,step_count,tid,_pc,trc_strand[tid]->pc_pa,trc_strand[tid]->iw,str_inst,str_trap);
pli_socket.write(str);
}
trc_strand[tid]->clear();
}
/*}}}*/
void @-ARCH-@_Main::pli_trace_0x0( uint_t tid, uint64_t trc_pc )/*{{{*/
{
// this function is used to produce a instruction line with
// "[ 0x00000000 ] illtrap 0", it is mainly used in situation where a
// cosim step is called, but because of a pending interrupt, the interrupt
// is taken instead of the intended instruction, we need the information to
// make cosim log more complete. Because the instruction is not executed,
// the PC_PA is not valid, we use 0x0 in its place.
if (reg_comp[tid]->is_cmpr(SS_RegCompare::CTR_INSTR))
{
const char* fmt = "%d: [swvp0,th%02d] <v:%016llx> <p:%016llx> [%08x] %s %s\n";
char str[1024];
char str_inst[512];
char str_trap[512];
SS_TrapInfo* info = &SS_Trap::table[trc_strand[tid]->trap_type];
if (info->disrupting)
{
sprintf(str_trap,"(Interrupted %s)",info->name);
}
else if (trc_strand[tid]->get_trap_mode() == SS_Tracer::INST_TRAP)
{
switch (trc_strand[tid]->trap_type)
{
case SS_Trap::INSTRUCTION_ACCESS_MMU_MISS:
case SS_Trap::FAST_INSTRUCTION_ACCESS_MMU_MISS:
sprintf(str_trap,"(I-miss)");
break;
default:
sprintf(str_trap,"(ERROR mmutrap %#x)",trc_strand[tid]->trap_type);
break;
}
}
else if (trc_strand[tid]->get_trap_mode() == SS_Tracer::DATA_TRAP)
{
switch (trc_strand[tid]->trap_type)
{
case SS_Trap::DATA_ACCESS_MMU_MISS:
case SS_Trap::FAST_DATA_ACCESS_MMU_MISS:
sprintf(str_trap,"(D-miss)");
break;
default:
sprintf(str_trap,"(ERROR mmutrap %#x)",trc_strand[tid]->trap_type);
break;
}
}
else
{
sprintf(str_trap,"");
}
uint32_t _iw = 0x0;
SS_Vaddr _pc = trc_pc;
size_t n = spix_sparc_dis(str_inst,512,spix_sparc_iop(SPIX_SPARC_V9,&_iw),&_iw,_pc);
sprintf(str,fmt,step_count,tid,_pc,0x0,_iw,str_inst,str_trap);
pli_socket.write(str);
}
trc_strand[tid]->clear();
}
/*}}}*/
SS_Registers::Index @-ARCH-@_Main::asr2index( uint8_t idx )/*{{{*/
{
if (idx < 0x20)
return SS_Registers::Index(SS_Registers::ASR_OFS + (idx & 0x1f));
else if (idx < 0x40)
return SS_Registers::Index(SS_Registers::PR_OFS + (idx & 0x1f));
else if (idx < 0x60)
return SS_Registers::Index(SS_Registers::HPR_OFS + (idx & 0x1f));
else
assert(0);
// Should really never get here, but if we do lets return something that make
// sence as we don't have an invalid index value (should we add that?) ...
// %g0 is the best candidate as it ought to be read only.
return SS_Registers::G0;
}
/*}}}*/
@-ARCH-@_Main* @-arch-@ = 0;
extern "C" static PyObject* @-arch-@_model( PyObject* self, PyObject* args )/*{{{*/
{
if (!PyArg_ParseTuple(args,(char*)""))
return 0;
return Py_BuildValue((char*)"l",@-arch-@);
}
/*}}}*/
extern "C" static PyObject* @-arch-@_init( PyObject* self, PyObject* args )/*{{{*/
{
int record, replay;
if (!PyArg_ParseTuple(args,(char*)"ii",&record,&replay))
return 0;
@-arch-@->init(record,replay);
return Py_BuildValue((char*)"");
}
/*}}}*/
extern "C" static PyObject* @-arch-@_step( PyObject* self, PyObject* args )/*{{{*/
{
uint_t n;
if (!PyArg_ParseTuple(args,(char*)"i",&n))
return 0;
n = @-arch-@->step(n);
return Py_BuildValue((char*)"i",n);
}
/*}}}*/
extern "C" static PyObject* @-arch-@_trace( PyObject* self, PyObject* args )/*{{{*/
{
if (!PyArg_ParseTuple(args,(char*)""))
return 0;
return Py_BuildValue((char*)"i",@-arch-@->set_trace);
}
/*}}}*/
static PyMethodDef @-arch-@_methods[] = /*{{{*/
{
{(char*)"model", @-arch-@_model, METH_VARARGS, (char*)"@-ARCH-@ Model created for cosim."},
{(char*)"init", @-arch-@_init, METH_VARARGS, (char*)"Initialise simulation"},
{(char*)"step", @-arch-@_step, METH_VARARGS, (char*)"Step @-ARCH-@ simulator N steps forward (driven by test bench)."},
{(char*)"trace", @-arch-@_trace, METH_VARARGS, (char*)"0 means trace (i.e., instr & reg delta) is off, otherwise on"},
{0, 0, 0, 0}
};
/*}}}*/
int main( int argc, char* argv[] )
{
@-arch-@ = new @-ARCH-@_Main();
Py_Initialize();
Py_InitModule((char*)"@-arch-@",@-arch-@_methods);
int ok = Py_Main(argc,argv);
Py_Finalize();
return ok;
}