// ========== 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 "SS_PliCommand.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];
class @
-ARCH
-@_Main
: public @
-ARCH
-@_Model
/*{{{*/
void init( int record
, int replay
);
SS_TrcStrand
* trc_strand
[@
-ARCH
-@
_Model::NO_STRANDS
];
@
-ARCH
-@_RegCompare
* reg_comp
[@
-ARCH
-@
_Model::NO_STRANDS
];
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
];
@
-ARCH
-@_CsrReadWrite
* csr_sync
;
std::string cfg_replay_fn
;
std::string cfg_record_fn
;
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_standalone
; // Nonzero means there is no RTL or replay
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
);
// 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.
// the first INTP 'xx 01' for each strand is considered POW, after that
bool first_intp1
[@
-ARCH
-@
_Model::NO_STRANDS
];
@
-ARCH
-@
_Main::@
-ARCH
-@
_Main()/*{{{*/
csr_sync
= new @
-ARCH
-@
_CsrReadWrite();
csr
= new @
-ARCH
-@
_Csr();
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
if (!trc_strand
[strand_id
])
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
);
// 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 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.
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
++)
int pid
= c
/ @
-ARCH
-@
_Model::NO_CORES_PER_CPU
;
int cid
= c
% @
-ARCH
-@
_Model::NO_CORES_PER_CPU
;
@
-ARCH
-VF
-@_Core
* core
= cpu_ptr(pid
)->core
[cid
];
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
++)
int pid
= s
/ @
-ARCH
-@
_Model::NO_STRANDS_PER_CPU
;
int gcid
= s
/ @
-ARCH
-@
_Model::NO_STRANDS_PER_CORE
;
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]
cpu
[pid
]->strand
[sid
]->asi_map
.set_asi_va_follow_me_mask(0x40,0x20,0x1f);
cpu
[pid
]->strand
[sid
]->asi_map
.set_asi_va_follow_me_mask(0x40,0x20,0x1b);
cpu
[pid
]->strand
[sid
]->asi_map
.set_asi_va_follow_me_mask(0x40,0x30,0x1f);
cpu
[pid
]->strand
[sid
]->asi_map
.set_asi_va_follow_me_mask(0x40,0x30,0x1b);
// 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
++)
void @
-ARCH
-@
_Main::init( int record
, int replay
)/*{{{*/
// 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
// process CPU option, if specified
SS_ConfigValue
* val_num_cpu
= config
.value("swvmem0","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 no CPU is specified, then process THREAD_MASKs.
for (int i
= 0; i
< @
-ARCH
-@
_Model::NO_CPUS
; i
++)
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
->is_str())
create_cpu_extra(i
+1, no_core
);
cmp_init(i
, val_thd_mask0
->str()->value
);
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
else if (val_pli_log
->is_num())
cfg_record
= val_pli_log
->num()->value
> 0;
else if (val_pli_log
->is_var())
cfg_record_fn
= val_pli_log
->var()->value
;
else if (val_pli_log
->is_str())
cfg_record_fn
= val_pli_log
->str()->value
;
// If the frontend say we should record we should record !!!
// If replay_log is given and none zero then replay
else if (val_replay_log
->is_num())
cfg_replay
= val_replay_log
->num()->value
> 0;
else if (val_replay_log
->is_var())
cfg_replay_fn
= val_replay_log
->var()->value
;
else if (val_replay_log
->is_str())
cfg_replay_fn
= val_replay_log
->str()->value
;
// If the frontend says we should replay we should replay
// 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
pli_socket
.open_replay(cfg_replay_fn
);
pli_socket
.open_record(cfg_record_fn
);
pli_socket
.open_cosim(cfg_socket
);
pli_socket
.open_record(cfg_record_fn
);
for (int s
=0;s
<(cpu_cnt()*@
-ARCH
-@
_Model::NO_STRANDS_PER_CPU
);s
++)
reg_comp
[s
]->debug_output(stderr
);
// there will be no RTL or replay log to provide execution commands,
// just step through all strands in round robin.
gbt
.read_good_bad_trap(cpu
[0]->strand
[0]->va_bits());
pli_socket
.debug(cfg_pli_debug
, cfg_reg_comp
);
for (s
= 0; s
< (cpu_cnt()*@
-ARCH
-@
_Model::NO_STRANDS_PER_CPU
); 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
++)
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
for (int i
= 0; i
< cpu_cnt(); i
++)
cpu
[i
]->ras_enable(NULL
);
for (int p
= 0; p
< cpu_cnt(); p
++)
SS_Strand
* strand
= cpu
[p
]->strand
[0];
strand
->asi_map
.wr64(strand
, 0x45, 0x18, 0x1);
// register comparison 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
if (cfg_cmpr_list
[0] == '-')
// 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
++)
// process the cmpr_list string
int end_pos
= cfg_cmpr_list
.find('/', start_pos
);
sub
= cfg_cmpr_list
.substr(start_pos
, (end_pos
- start_pos
));
sub
= cfg_cmpr_list
.substr(start_pos
);
set_cmpr_list(sub
, exclude
);
void @
-ARCH
-@
_Main::set_cmpr_list(string sub
, bool exclude
)/*{{{*/
int ii
= reg_comp
[0]->name_2_index(sub
);
for (int i
= 0; i
< @
-ARCH
-@
_Model::NO_STRANDS
; i
++)
reg_comp
[i
]->cmpr_off(ii
);
for (int i
= 0; i
< @
-ARCH
-@
_Model::NO_STRANDS
; 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.
return (var2
.size()/2 + 1);
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.
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
);
// with 'x', the core is not available
available
|= (0x00) << (8*core
);
enabled
|= (0x00) << (8*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( )/*{{{*/
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).
for (int s
= 0; s
< (cpu_cnt()*@
-ARCH
-@
_Model::NO_STRANDS_PER_CPU
); s
++)
reg_comp
[s
]->initialise();
// in standalone mode, just step through all strands in round robin
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
reg_comp
[ss
+s
]->compare(trc_strand
[ss
+s
]->iw
);
if (gbt
.hit_good_bad_trap(strand
->pc()) != 0)
// 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)
switch (pli_socket
.get8(0))
case SS_PliCommand::PLI_QUIT
:
SS_PliCommand_QUIT
arg(pli_socket
);
case SS_PliCommand::PLI_SSTEP
:
SS_PliCommand_SSTEP@
-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();
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());
// a pending interrupt is taken, we need to generate an instruciton
pli_trace_0x0(arg
.tid
, trc_pc
);
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
);
case SS_PliCommand::PLI_SSTEP_N
:
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
++)
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());
// a pending interrupt is taken, we need to generate an instruciton
pli_trace_0x0(arg
.tid
, trc_pc
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
//TODO do we handle reset_gen properly in store_slam?
mem_sync
->handleStoreSlam(mem_oper
);
((@
-ARCH
-@_RegReader
*)regReader_
)->handleResetGen(@
-ARCH
-@
_System::RESET_GEN
);
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
);
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
);
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);
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
);
//TODO do we handle reset_gen properly in dma_store?
mem_sync
->handleDmaStore(memCmd
);
((@
-ARCH
-@_RegReader
*)regReader_
)->handleResetGen(@
-ARCH
-@
_System::RESET_GEN
);
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
);
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;
case SS_Trap::RESERVED
: // warm reset
for (int s
= 0; s
< (cpu_cnt()*@
-ARCH
-@
_Model::NO_STRANDS_PER_CPU
); s
++)
tlb_sync
[s
]->pli_flush();
// we are seeing the second or more "INTP 00 00", it is
// 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
irq_sync
[arg
.tid
]->raise(SS_Trap::Type(arg
.tt
));
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
));
// 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();
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
));
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
));
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;
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;
irq_sync
[arg
.tid
]->raise(SS_Trap::Type(arg
.tt
));
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
);
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;
// 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)
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
);
val_sync
[arg
.tid
]->ctr_write(asr2index(arg
.asr
),arg
.data
);
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
);
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
);
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;
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);
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);
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
));
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
);
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
));
case SS_PliCommand::PLI_SSTEP_SNIPER
:
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
);
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
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
// 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
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
mem_sync
->setCoreEnable((@
-ARCH
-@
_Model::NO_CORES_PER_CPU
*cid
/8), arg
.data
);
// after POR, strand_available should not change, other values must
// be masked by strand_available. strand_enable (0x20) will not change
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
;
cpu_ptr(cid
)->strand_running
= arg
.data
;
cpu_ptr(cid
)->strand_running_update(0,2,arg
.data
);
fprintf(stderr
,"PLI: ERROR: CMP_WRITE unexpected va=0x%x\n",arg
.va
);
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";
SS_TrapInfo
* info
= &SS_Trap::table
[trc_strand
[tid
]->trap_type
];
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
);
sprintf(str_trap
,"(I-mmu trap %#x)",trc_strand
[tid
]->trap_type
);
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
);
sprintf(str_trap
,"(D-mmu trap %#x)",trc_strand
[tid
]->trap_type
);
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
);
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";
SS_TrapInfo
* info
= &SS_Trap::table
[trc_strand
[tid
]->trap_type
];
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)");
sprintf(str_trap
,"(ERROR mmutrap %#x)",trc_strand
[tid
]->trap_type
);
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)");
sprintf(str_trap
,"(ERROR mmutrap %#x)",trc_strand
[tid
]->trap_type
);
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
);
trc_strand
[tid
]->clear();
SS_Registers::Index @
-ARCH
-@
_Main::asr2index( uint8_t idx
)/*{{{*/
return SS_Registers::Index(SS_Registers::ASR_OFS
+ (idx
& 0x1f));
return SS_Registers::Index(SS_Registers::PR_OFS
+ (idx
& 0x1f));
return SS_Registers::Index(SS_Registers::HPR_OFS
+ (idx
& 0x1f));
// 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.
@
-ARCH
-@_Main
* @
-arch
-@
= 0;
extern "C" static PyObject
* @
-arch
-@
_model( PyObject
* self
, PyObject
* args
)/*{{{*/
if (!PyArg_ParseTuple(args
,(char*)""))
return Py_BuildValue((char*)"l",@
-arch
-@
);
extern "C" static PyObject
* @
-arch
-@
_init( PyObject
* self
, PyObject
* args
)/*{{{*/
if (!PyArg_ParseTuple(args
,(char*)"ii",&record
,&replay
))
@
-arch
-@
->init(record
,replay
);
return Py_BuildValue((char*)"");
extern "C" static PyObject
* @
-arch
-@
_step( PyObject
* self
, PyObject
* args
)/*{{{*/
if (!PyArg_ParseTuple(args
,(char*)"i",&n
))
return Py_BuildValue((char*)"i",n
);
extern "C" static PyObject
* @
-arch
-@
_trace( PyObject
* self
, PyObject
* args
)/*{{{*/
if (!PyArg_ParseTuple(args
,(char*)""))
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"},
int main( int argc
, char* argv
[] )
@
-arch
-@
= new @
-ARCH
-@
_Main();
Py_InitModule((char*)"@-arch-@",@
-arch
-@_methods
);
int ok
= Py_Main(argc
,argv
);