Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / cpu_interface.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: cpu_interface.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 ============================================
////////////////////////////////////////////////////////////
//
// File: cpu_interface.cc
//
// Copyright (C) 2005 Sun Microsystems, Inc.
// All rights reserved.
//
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "types.h"
#include "blaze_globals.h"
#include "cpu_interface.h"
#include "spix_sparc.h"
#include "system.h"
#include "ui.h"
#include "command_opts.h"
// This file implements C++ interface for the
// cpu shared library
void *cpu_lib_handle = NULL;
char cpu_lib_name[160] = "lib.unknown.cpu.type";
// global vcpu table
Vcpu *g_vcpu[NCPU_MAX];
int g_nvcpu = 0; // total number of vcpu's
int g_vcpu_id_max = 0; // max id of the vcpu
VCPU_ExInterface g_cpu_ex_intf;
extern int pselect_cpu_id;
// parameter names
#define INST_NAME "name"
#define CPU_TYPE "cpu-type"
#define MMU_TYPE "mmu-type"
#define DTLB_SIZE "dtlb-entries"
#define ITLB_SIZE "itlb-entries"
#define CLOCK "clock-frequency"
#define SCLOCK "system-frequency"
#define LOOPTICKS "cpu-loopticks"
#define STICKINCR "cpu-stickincr"
#define NWINS "cpu-nwins"
#define TLMAX "cpu-tlmax"
#define CPU_ID "id"
// cpu ui commands
static int pregs_ui_cmd (void *, int argc, char **argv);
static int fpregs_ui_cmd (void *, int argc, char **argv);
static int cmpregs_ui_cmd (void *, int argc, char **argv);
static int read_reg_ui_cmd (void *, int argc, char **argv);
static int set_pc_ui_cmd (void *, int argc, char **argv);
static int write_reg_ui_cmd (void *, int argc, char **argv);
static int regs_ui_cmd (void *, int argc, char **argv);
static int pc_ui_cmd (void *, int argc, char **argv);
static int cpuregs_ui_cmd (void *, int argc, char **argv);
static int pregs_cmd_usage ();
static int fpregs_cmd_usage ();
static int cmpregs_cmd_usage ();
static int read_reg_cmd_usage ();
static int set_pc_cmd_usage ();
static int write_reg_cmd_usage();
static int print_reg_cmd_usage();
static int cpuregs_cmd_usage ();
//////////////////////////////////////////////////////////////
//
// set configuration parameter
//
// Configuration informaion is encoded in
// name=<value> pairs
//
int set_param
(
char * name_value, // parameter name=value string
VCPU_Config *config // set value in this sructure
)
{
// get param name
char *name = strtok ( name_value, " =" );
if (name == NULL)
{
ui->error("cannot read cpu param name %s\n", name_value);
return 1;
}
// get param value
char *param = strtok ( NULL, "\0" );
if (param == NULL)
{
ui->error("cannot read cpu param value %s\n", name_value);
return 1;
}
if (strcmp ( name, CPU_TYPE) == 0 )
{
config->type = strdup ( param ) ;
}
else if (strcmp ( name, INST_NAME) == 0 )
{
config->name = strdup ( param ) ;
}
else if (strcmp ( name, MMU_TYPE) == 0 )
{
config->mmu_type = strdup ( param ) ;
}
else if (strcmp ( name, NWINS) == 0 )
{
config->reg_wins = (int)strtol(param, NULL, 0);
}
else if (strcmp ( name, TLMAX ) == 0 )
{
config->tl_max = (int)strtol(param, NULL, 0);
}
else if (strcmp ( name, DTLB_SIZE ) == 0 )
{
config->dtlb_size = (int)strtol(param, NULL, 0);
}
else if (strcmp ( name, ITLB_SIZE ) == 0 )
{
config->itlb_size = (int)strtol(param, NULL, 0);
}
else if (strcmp ( name, CLOCK ) == 0 )
{
config->cpufreq = (unsigned long long)strtoull(param, NULL, 0);
}
else if (strcmp ( name, SCLOCK ) == 0 )
{
ui->warning("param %s %s is not supported \n", name, param);
}
else if (strcmp ( name, STICKINCR ) == 0 )
{
config->stickincr = (int)strtol(param, NULL, 0);
}
else if (strcmp ( name, LOOPTICKS ) == 0 )
{
config->loopticks = (int)strtol(param, NULL, 0);
}
else if(strcmp(name ,CPU_ID) == 0)
{
config->id = (int)strtol(param,NULL,0);
if (config->id >= NCPU_MAX)
{
ui->error("cpu id %d cannot exceed %d\n", config->id, NCPU_MAX );
return 1;
}
}
else
{
ui->error("unknown cpu param: %s\n", name);
return 1;
}
return 0;
}
///////////////////////////////////////////////////////////
//
// get cpu config parameter string based on param name
//
static char *get_param ( char *name, VCPU_Config *config )
{
static char param_value[40];
sprintf ( param_value, "unknown parameter" );
if (strcmp ( name, CPU_TYPE ) == 0 )
{
sprintf ( param_value, "%s", config->type );
}
else if (strcmp ( name, INST_NAME) == 0 )
{
sprintf ( param_value, "%s", config->name );
}
else if (strcmp ( name, MMU_TYPE) == 0 )
{
sprintf ( param_value, "%s", config->mmu_type );
}
else if (strcmp ( name, NWINS) == 0 )
{
sprintf ( param_value, "%i", config->reg_wins );
}
else if (strcmp ( name, TLMAX ) == 0 )
{
sprintf ( param_value, "%i", config->tl_max );
}
else if (strcmp ( name, DTLB_SIZE ) == 0 )
{
sprintf ( param_value, "%i", config->dtlb_size );
}
else if (strcmp ( name, ITLB_SIZE ) == 0 )
{
sprintf ( param_value, "%i", config->itlb_size );
}
else if (strcmp ( name, SCLOCK ) == 0 )
{
sprintf ( param_value, "%i", config->stickfreq );
}
else if (strcmp ( name, CLOCK ) == 0 )
{
sprintf ( param_value, "%llu", config->cpufreq );
}
else if (strcmp ( name, STICKINCR ) == 0 )
{
sprintf ( param_value, "%i", config->stickincr );
}
else if (strcmp ( name, LOOPTICKS ) == 0 )
{
sprintf ( param_value, "%i", config->loopticks );
}
else if(strcmp(name ,CPU_ID) == 0)
{
sprintf ( param_value, "%i", config->id );
}
return param_value;
}
void set_default ( VCPU_Config &config )
{
// set defaullt values
config.name = NULL;
config.type = NULL; //strdup("SUNW,UltraSPARC-II");
config.mmu_type = NULL;
config.cpu_type = VCPU_IMPL_VER_NONE; // encoded cpu impl version
config.reg_wins = 8; // number of reg windows
config.tl_max = 7; // trap level max
config.itlb_size = 64; // number of tlb entries
config.dtlb_size = 64;
config.stickincr= 1; // the amount stick has to be incremented
// a person doing simulation ought to know these values
// have to be initialized in the rc file ... Sreenivas
///* not to break the regression without changes available in rc file
config.loopticks= 25; // number of instruction per one update of stick
config.cpufreq = 1000000; // cpu clock
config.stickfreq= 10000; // system clock
//*/
config.cpi = 1; // cycles per instruction
config.delay = 0; // delay this number of instructions
config.mode = 1; // all cpu's on separate threads
config.trace_on = 0; // tracing is off
config.id = -1;
config.execution_driven = 0;
}
//////////////////////////////////////////////////////////////
//
// parse config string
//
static int process_config_cmd
(
char *config_cmd, // config string: name=value pairs
VCPU_Config *config // return config structure
)
{
char param_delimiter[] = " \0";
// make a copy because strtok() will write the termination chars
char *cmd = strdup ( config_cmd );
int n_param = 0; // param counter
int status = 0;
for (
char *name_value = strtok ( cmd, param_delimiter );
name_value != NULL;
name_value = strtok ( NULL, param_delimiter )
)
{
if ( set_param ( name_value, config ) != 0 )
{
ui->error("cannot set cpu param %s\n", name_value);
status++;
break;
}
n_param++;
}
free (cmd);
if (n_param ==0)
{
ui->error("there are no cpu config params\n");
return 1;
}
return status;
}
int deprecated_read_cmd (void *, int argc, char **argv)
{
ui->error("This command is deprecated, use read-reg command instead.\n");
return 0;
}
int deprecated_write_cmd (void *, int argc, char **argv)
{
ui->error("This command is deprecated, use write-reg command instead.\n");
return 0;
}
//////////////////////////////////////////////////////////////
//
// Create a new cpu instance
//
Vcpu* create_cpu
(
char *path, // library path
char *pconfig, // config line with name=value pairs
VCPU_ImpIntf *intf, // cpu imported interface
int version // cpu lib version number
)
{
VCPU_Config config_info;
// process cpu config command
// fill out config_info structure
if ( process_config_cmd (pconfig, &config_info) != 0 )
{
ui->error("Invalid Cpu config information \n");
exit (1);
}
return create_cpu ( path, config_info, intf, version );
}
//////////////////
Vcpu* create_cpu
(
char *path, // library path
VCPU_Config &config_info, // cpu config params
VCPU_ImpIntf *intf, // cpu imported interface
int version // cpu lib version number
)
{
static bool id_from_sysconf = true; // expect id from sysconf
if ( config_info.type == NULL )
{
ui->error("missing cpu type information \n");
exit (1);
}
// either id is present on all lines, or its not present on any
// sysconf line. no intermixing is allowed
if(config_info.id == -1){
// sid is not provided on sysconf line. assign sid = vid
config_info.id = g_nvcpu;
if(g_nvcpu == 0) // first vcpu
id_from_sysconf = false;
if(id_from_sysconf){
ui->error("cpu id is being assigned implicitly. sysconf file error\n");
exit(1);
}
}else{
if(!id_from_sysconf){
ui->error("cpu id missing. sysconf file error\n");
exit(1);
}
}
if (!cpu_lib_handle) // first cpu
{
// register cpu related ui commands
UI_register_cmd_2 ("cpuregs", "print cpu register names", cpuregs_ui_cmd, cpuregs_cmd_usage );
UI_register_cmd_2 ("pregs", "print cpu architecture registers", pregs_ui_cmd, pregs_cmd_usage);
UI_register_cmd_2 ("fpregs", "print floating-point registers", fpregs_ui_cmd, fpregs_cmd_usage);
UI_register_cmd_2 ("cmpregs", "print cmp registers", cmpregs_ui_cmd, cmpregs_cmd_usage);
UI_register_cmd_2 ("read-reg", "read a register by name", read_reg_ui_cmd, read_reg_cmd_usage);
UI_register_cmd_2 ("write-reg","write value to a register", write_reg_ui_cmd, write_reg_cmd_usage);
UI_register_cmd_2 ("set-pc", "set pc for current cpu", set_pc_ui_cmd, set_pc_cmd_usage);
UI_register_cmd_2 ("pc", "print current pc for all cpus", pc_ui_cmd, NULL);
UI_register_cmd_2 ("r", "print cpu regs", regs_ui_cmd, print_reg_cmd_usage);
UI_register_cmd_2 ("read-fp-reg-i", "print floating point single register as integer", deprecated_read_cmd, NULL);
UI_register_cmd_2 ("read-fp-reg-x", "print floating point double register as integer", deprecated_read_cmd, NULL);
UI_register_cmd_2 ("read-th-ctl-reg", "print a control register value of a strand" , deprecated_read_cmd, NULL);
UI_register_cmd_2 ("read-th-fp-reg-i", "print a single fp register value of a strand" , deprecated_read_cmd, NULL);
UI_register_cmd_2 ("read-th-fp-reg-x", "print a double fp register value of a strand" , deprecated_read_cmd, NULL);
UI_register_cmd_2 ("read-th-reg", "print an integer register value of a strand" , deprecated_read_cmd, NULL);
UI_register_cmd_2 ("write-fp-reg-i", "write floating point single register as integer", deprecated_write_cmd, NULL);
UI_register_cmd_2 ("write-fp-reg-x", "write floating point double register as integer", deprecated_write_cmd, NULL);
UI_register_cmd_2 ("write-th-ctl-reg", "write a control register value of a strand" , deprecated_write_cmd, NULL);
UI_register_cmd_2 ("write-th-fp-reg-i","write floating point single register as integer", deprecated_write_cmd, NULL);
UI_register_cmd_2 ("write-th-fp-reg-x","write double fp register value of a strand" , deprecated_write_cmd, NULL);
UI_register_cmd_2 ("write-th-reg", "write integer register value of a strand" , deprecated_write_cmd, NULL);
}
// generate cpu library name from the config info
char lib_name[160];
sprintf(lib_name,"lib%s.so", config_info.type );
if (strcmp(lib_name, cpu_lib_name)!=0) // library was not loaded yet
{
// open shared library;
extern void * mod_dlopen (char * pathp, char * name, int flags);
cpu_lib_handle = mod_dlopen (path, lib_name, RTLD_LAZY|RTLD_GLOBAL|RTLD_PARENT);
// remember last opened cpu library
strlcpy ( cpu_lib_name, lib_name, 160 );
}
if ( cpu_lib_handle == NULL )
{
ui->error("Cannot find cpu library %s \n", lib_name );
exit (1);
}
// extract lib exported interface
VCPU_GetIntfFn get_interface = (VCPU_GetIntfFn)dlsym ( cpu_lib_handle, "get_ex_interface" );
if (get_interface == NULL)
{
ui->error("Cannot find cpu exported interface \n");
exit (1);
}
// obtain cpu interface
get_interface ( &g_cpu_ex_intf);
// create cpu instance
Vcpu * vcpu = (Vcpu*)g_cpu_ex_intf.create( &config_info, intf );
if ( vcpu == NULL )
{
ui->error("Cannot create Cpu %s \n", config_info.name);
exit (1);
}
int sid = vcpu->config.id;
g_vcpu[sid] = vcpu;
// total number of vcpu's
g_nvcpu ++;
// max id of the vcpu
if (g_vcpu_id_max < sid)
g_vcpu_id_max = sid;
return vcpu;
}
// cofiguration parameters
int set_param ( int cpu_id, char *param_name )
{
Vcpu *vcpu = get_vcpu(cpu_id);
if (!vcpu)
return 0;
return set_param (param_name, &(vcpu->config));
}
char *get_param ( int cpu_id, char *param_name )
{
Vcpu *vcpu = get_vcpu(cpu_id);
if (!vcpu)
return 0;
return get_param (param_name, &(vcpu->config));
}
// set a breakpoint from a remote debugger
int cpu_set_breakpoint ( int cpu_id, VCPU_BpType type, uint64_t addr )
{
int bp_id;
extern int bp_action ( int bp_id, int vcpu_id );
Vcpu * vcpu = get_vcpu(cpu_id);
if(!vcpu)
return 0;
return vcpu->set_breakpoint( &bp_id,type, addr, bp_action );
}
// remove a breakpoint
int cpu_remove_breakpoint ( int cpu_id, VCPU_BpType type, uint64_t addr )
{
Vcpu * vcpu = get_vcpu(cpu_id);
if(!vcpu)
return 0;
return vcpu->delete_breakpoint();
}
/////////////////////////////////////////////////////////
//
// Disassemble instruction
//
int disassemble (uint32_t iw, uint64_t pc, char *buf, int size )
{
if (
! spix_sparc_dis( buf, size,
spix_sparc_iop(SPIX_SPARC_V9, &iw),
&iw, pc )
)
{
sprintf ( buf, "unknown" );
return 0;
}
return 1;
}
///////////////////////////////////////////////////////
//
// Read vcpu regs from the ui
//
int print_reg_cmd_usage()
{
ui->output("usage: r [-cpu <id>] [-w [<wp>]|-g [<gwp>]|-f|df|-pr|-asr|-hpr|-tr <tr_level>|-asi <asi> <va>]\n");
return 0;
}
int regs_ui_cmd (void *, int argc, char **argv)
{
if (!IN_STOP_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
int cpuid = 0;
int greg = 0;
int wreg = 0;
int gl = -1;
int wp = -1;
int freg = 0;
int dfreg = 0;
int pr = 0;
int asr = 0;
int hpr = 0;
int tr = 0;
int tl = 1;
int asi = 0;
uint8_t asi_i = 0;
uint64_t asi_va = 0;
Vcpu *cpu = 0;
for(int i=1; i<argc; i++)
{
// check reg type
if (strcmp(argv[i], "-w")==0)
{
wreg = 1;
if (((i+1)<argc) && isdigit(argv[i+1][0]))
wp = int(strtol(argv[++i], NULL, 0));
continue;
}
else if (strcmp(argv[i], "-g")==0)
{
greg = 1;
if ( ((i+1)<argc) && isdigit(argv[i+1][0]) )
gl = int(strtol(argv[++i], NULL, 0));
continue;
}
else if (strcmp(argv[i], "-f")==0) freg = 1;
else if (strcmp(argv[i], "-df")==0) dfreg = 1;
else if (strcmp(argv[i], "-pr")==0) pr = 1;
else if (strcmp(argv[i], "-asr")==0) asr = 1;
else if (strcmp(argv[i], "-hpr")==0) hpr = 1;
else if ((strcmp(argv[i], "-asi")==0) && ((i+2)<argc))
{
asi_i = uint8_t(strtol(argv[++i], NULL, 0));
asi_va = strtoll(argv[++i], NULL, 0);
asi = 1;
continue;
}
else if ((strcmp(argv[i], "-tr")==0) && ((i+1)<argc))
{
tr = 1;
tl = int(strtol(argv[++i], NULL, 0));
if (tl < 1) tl = 1;
continue;
}
else if ((strcmp(argv[i], "-cpu")==0) && ((i+1)<argc))
{
cpuid = int(strtol(argv[++i], NULL, 0));
if(cpuid<0) cpuid = 0;
cpu = get_vcpu(cpuid);
if(!cpu)
ui->error("cpu[%d] is not available\n",cpuid);
continue;
}
else if (strcmp(argv[i], "?")==0)
{
print_reg_cmd_usage();
return 0;
}
}
if (!( greg||wreg||freg||dfreg||pr||asr||hpr||tr|asi) )
return print_reg_cmd_usage();
if(!cpu) // no cpu id was selected
{
cpu = get_vcpu(pselect_cpu_id);
if(!cpu)
{
ui->error("cpu[%d] is not available\n",cpuid);
return 0;
}
cpuid = pselect_cpu_id;
}
ui->output ( "cpu[%i]:",cpuid);
if (asi)
{
uint64_t value = 0;
ui->output ("asi 0x%x, va=0x%llx, ", asi_i, asi_va);
if (cpu->get_asi(asi_i, asi_va, value) == 0)
ui->output ("value = 0x%llx \n", value);
else
ui->error ("unknown \n");
}
if (wreg)
{
uint64_t max_wp;
uint64_t cur_wp;
cpu->get_reg(VCPU_SIM_MAX_WP,&max_wp);
cpu->get_reg(VCPU_PR_CWP,&cur_wp);
ui->output ( "\nwindowed R registers,");
if (wp < 0) {
wp = cur_wp;
ui->output (" wp=%d (current)\n",wp);
} else {
if (wp > max_wp)
wp = max_wp;
ui->output (" wp=%d\n", wp);
}
cpu->set_reg(VCPU_PR_CWP,wp);
for (int i=0; i<8; i++)
{
uint64_t value = 0;
cpu->get_reg(VCPU_IRF_0 + i + 8, &value); // o regs
ui->output ("%s=0x%016llx ", cpu->get_reg_name(VCPU_IRF_0 + i + 8), value);
cpu->get_reg(VCPU_IRF_0 + i + 16, &value); // l regs
ui->output ("%s=0x%016llx ", cpu->get_reg_name(VCPU_IRF_0 + i + 16), value);
cpu->get_reg(VCPU_IRF_0 + i + 24, &value); // i regs
ui->output ("%s=0x%016llx\n", cpu->get_reg_name(VCPU_IRF_0 + i + 24), value);
}
cpu->set_reg(VCPU_PR_CWP,cur_wp);
}
if (greg)
{
uint64_t max_gl;
uint64_t cur_gl;
cpu->get_reg(VCPU_SIM_MAX_GL,&max_gl);
cpu->get_reg(VCPU_PR_GL,&cur_gl);
ui->output ( "\nglobal R registers,");
if (gl < 0) {
gl = cur_gl;
ui->output (" gl=%d (current)\n",gl);
} else {
if (gl > max_gl)
gl = max_gl;
ui->output (" gl=%d\n", gl);
}
cpu->set_reg(VCPU_PR_GL,gl);
for (int i=0; i<8; i++)
{
uint64_t value = 0;
cpu->get_reg(VCPU_IRF_0 + i, &value);
ui->output ("%s=0x%016llx\n", cpu->get_reg_name(VCPU_IRF_0 + i), value);
}
cpu->set_reg(VCPU_PR_GL,cur_gl);
}
if (freg)
{
ui->output ( "\nfloating point registers\n");
for (int i=0; i<32; i++)
{
uint64_t value = 0;
cpu->get_reg(VCPU_FRF_0 + i, &value);
uint32_t val32 = uint32(value);
ui->output ( "f%-2i = %e\n", i, val32);
}
}
if (dfreg)
{
ui->output ( "\ndouble floating point registers\n");
for (int i=0; i<63; i+=2)
{
uint64_t value = 0;
if (cpu->get_reg(VCPU_DRF_0 + i/2, &value) == 0)
ui->output ( "d%-2i = %e\n", i, value);
}
}
if (pr)
{
ui->output ( "\nPR registers\n");
for (int i=0; i<32; i++)
{
uint64_t value = 0;
if (cpu->get_reg(VCPU_PR_0 + i, &value) == Vcpu::REG_OK)
{
ui->output ( "pr%-2d %16s = 0x%llx\n", i, cpu->get_reg_name(VCPU_PR_0 + i), value);
}
}
}
if (asr)
{
ui->output ( "\nASR registers\n");
for (int i=0; i<32; i++)
{
uint64_t value = 0;
if (cpu->get_reg(VCPU_ASR_0 + i, &value) == Vcpu::REG_OK)
{
ui->output ( "asr%-2d %16s = 0x%llx\n", i, cpu->get_reg_name(VCPU_ASR_0 + i), value);
}
}
}
if (hpr)
{
ui->output ( "\nHPR registers\n");
for (int i=0; i<32; i++)
{
uint64_t value = 0;
if (cpu->get_reg(VCPU_HPR_0 + i, &value) == Vcpu::REG_OK)
ui->output ( "hpr%-2d %16s = 0x%llx\n", i, cpu->get_reg_name(VCPU_HPR_0 + i), value);
}
}
if (tr)
{
uint64_t max_tl;
uint64_t cur_tl;
cpu->get_reg(VCPU_SIM_MAX_TL,&max_tl);
cpu->get_reg(VCPU_PR_TL,&cur_tl);
ui->output ( "\ntrap registers, tl=%i\n", tl);
if (tl < 0) {
tl = cur_tl;
ui->output (" tl=%d (current)\n",tl);
} else {
if (tl > max_tl)
tl = max_tl;
ui->output (" tl=%d\n", tl);
}
cpu->set_reg(VCPU_PR_TL,tl);
uint64_t value = 0;
cpu->get_reg(VCPU_PR_TPC,&value);
ui->output ( "tpc = 0x%llx\n", value);
cpu->get_reg(VCPU_PR_TNPC,&value);
ui->output ( "tnpc = 0x%llx\n", value);
cpu->get_reg(VCPU_PR_TSTATE,&value);
ui->output ( "tstate = 0x%llx\n", value);
cpu->get_reg(VCPU_PR_TT,&value);
ui->output ( "tt = 0x%llx\n", value);
if (cpu->get_reg(VCPU_HPR_HTSTATE,&value) == Vcpu::REG_OK)
ui->output ( "htstate = 0x%llx\n", value);
cpu->set_reg(VCPU_PR_TL,cur_tl);
}
ui->output("\n");
return 0;
}
///////////////////////////////////////////////////////
//
// single step one vcpu only
//
int sstep_cmd (int cpu_id)
{
if (!IN_STOP_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
Vcpu *vcpu = get_vcpu(cpu_id);
if (!vcpu)
return 0;
vcpu->stepi(1);
return 1;
}
/////////////////////////////////////////////////////////////////////
//
int pc_ui_cmd (void *, int argc, char **argv)
{
for (int i=0; i<=g_vcpu_id_max; i++)
{
Vcpu *vcpu = get_vcpu(i);
if (!vcpu)
continue;
uint64_t pc = 0xdead;
vcpu->get_reg(VCPU_ASR_PC, &pc);
ui->output ("cpu[%i]: pc=0x%llx \n", i, pc);
}
return 1;
}
////////////////////////////////////////////////////////////////////////
//
// SAM FE command
//
// read register by name
int cpu_read_register_name ( char *cmd )
{
if (!IN_STOP_STATE(blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
Vcpu* vcpu = g_vcpu[pselect_cpu_id];
if (vcpu == 0)
{
ui->error("cpu[%d] is not available\n", pselect_cpu_id);
return 0;
}
else
{
int index;
uint64_t value;
const int max_reg_name = 128;
char reg_name[max_reg_name];
strlcpy(reg_name, cmd, max_reg_name);
char *name = strtok ( reg_name, " \n\0" );
char *parm = strtok ( NULL, " \n\0" );
if (!name || parm)
{
ui->error("\nusage: %%reg_name , to list register names use 'cpuregs' command\n");
return 0;
}
if ( (vcpu->get_reg_index( reg_name, &index )==Vcpu::REG_OK) &&
(vcpu->get_reg( index, &value )==Vcpu::REG_OK))
{
ui->output("0x%llx\n", value);
}
else
{
ui->error("cpu[%d] register %s is not available\n", pselect_cpu_id, reg_name);
return 0;
}
}
return 1;
}
////////////////////////////////////////////////////////////
//
// pregs command
//
int pregs_cmd_usage()
{
ui->output("\nusage : pregs [-cpu cpu_set]]\n");
return 0;
}
int pregs_ui_cmd(void *, int argc, char **argv)
{
if (!IN_STOP_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
char *cmd = "pregs";
CommandOptions option;
CpuOption cpu_option(pselect_cpu_id,CpuOption::MULTITUDE);
option.add(cpu_option);
std::vector<std::string> args;
if (!option.parse(argc-1,(const char**)&argv[1],args))
{
ui->error("%s command parsing failed: %s\n",cmd,option.get_error_msg().c_str());
return 0;
}
if (args.size() != 0)
return pregs_cmd_usage();
CpuSet& cpu_set = cpu_option.get_value();
for (CpuSet::iterator i=cpu_set.begin(); i != cpu_set.end(); ++i)
{
uint32_t cpu_id = *i;
ui->output("cpu[%d]: \n",cpu_id);
Vcpu* vcpu = g_vcpu[cpu_id];
if (vcpu == 0)
{
ui->error("cpu[%d] is not available\n", cpu_id);
continue;
}
// pr
for (int i=0; i<32; i++)
{
uint64_t value = 0;
if (vcpu->get_reg(VCPU_PR_0 + i, &value) == Vcpu::REG_OK)
{
ui->output ( "pr%3d %16s = 0x%llx\n", i, vcpu->get_reg_name(VCPU_PR_0 + i), value);
}
}
// asr
for (int i=0; i<32; i++)
{
uint64_t value = 0;
if (vcpu->get_reg(VCPU_ASR_0 + i, &value) == Vcpu::REG_OK)
{
ui->output ( "asr%2d %16s = 0x%llx\n", i, vcpu->get_reg_name(VCPU_ASR_0 + i), value);
}
}
// hpr
for (int i=0; i<32; i++)
{
uint64_t value = 0;
if (vcpu->get_reg(VCPU_HPR_0 + i, &value) == Vcpu::REG_OK)
ui->output ( "hpr%2d %16s = 0x%llx\n", i, vcpu->get_reg_name(VCPU_HPR_0 + i), value);
}
}
return 1;
}
/////////////////////////////////////////////////////////////
//
// fpregs command
//
int fpregs_cmd_usage()
{
ui->error("\nusage : fpregs [-cpu cpu_set]]\n");
return 0;
}
int fpregs_ui_cmd(void *, int argc, char **argv)
{
if (!IN_STOP_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
char *cmd = "fpregs";
CommandOptions option;
CpuOption cpu_option(pselect_cpu_id,CpuOption::MULTITUDE);
option.add(cpu_option);
std::vector<std::string> args;
if (!option.parse(argc-1,(const char**)&argv[1],args))
{
ui->error("%s command parsing failed: %s\n",cmd,option.get_error_msg().c_str());
return 0;
}
if (args.size() != 0)
return fpregs_cmd_usage();
CpuSet& cpu_set = cpu_option.get_value();
for (CpuSet::iterator i=cpu_set.begin(); i != cpu_set.end(); ++i)
{
uint32_t cpu_id = *i;
Vcpu* vcpu = g_vcpu[cpu_id];
if (vcpu == 0)
{
ui->error("cpu[%d] is not available\n", cpu_id);
continue;
}
ui->output("cpu[%d]: ",cpu_id);
int index;
uint64_t value = 0;
const char *fsr = "fsr";
if ( (vcpu->get_reg_index( fsr, &index )==Vcpu::REG_OK) &&
(vcpu->get_reg( index, &value )==Vcpu::REG_OK))
ui->output("%s=0x%llx\n",fsr, value);
for (int i=0; i<63; i+=2)
{
uint64_t value = 0;
if (vcpu->get_reg(VCPU_DRF_0 + i/2, &value) == 0)
ui->output ( "d%-2i=0x%016llx ", i, value);
if (i < 32)
ui->output ( "f%-2i=0x%08llx f%-2i=0x%08llx\n", i, uint32(value), i+1, uint32(value>>32));
else
ui->output("\n");
}
}
return 1;
}
/////////////////////////////////////////////////////////////
//
// cmpregs command
//
int cmpregs_cmd_usage()
{
ui->error("\nusage : cmpregs [-cpu cpu_set]]\n");
return 0;
}
int cmpregs_ui_cmd(void *, int argc, char **argv)
{
if (!IN_STOP_STATE(blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
char *cmd = "cmpregs";
CommandOptions option;
CpuOption cpu_option(pselect_cpu_id,CpuOption::MULTITUDE);
option.add(cpu_option);
std::vector<std::string> args;
if (!option.parse(argc-1,(const char**)&argv[1],args))
{
ui->error("%s command: %s\n",cmd,option.get_error_msg().c_str());
return 0;
}
if (args.size() != 0)
return cmpregs_cmd_usage();
CpuSet& cpu_set = cpu_option.get_value();
for (CpuSet::iterator i=cpu_set.begin(); i != cpu_set.end(); ++i)
{
uint32_t cpu_id = *i;
ui->output("cpu[%d]: \n",cpu_id);
Vcpu* vcpu = g_vcpu[cpu_id];
if (vcpu == 0)
{
ui->error("cpu %d is not available\n", cpu_id);
continue;
}
uint64_t value = 0;
if (vcpu->get_asi(0x41, 0x0 , value) == 0) ui->output ("STRAND_AVAILABLE 0x%016llx \n", value);
if (vcpu->get_asi(0x41, 0x10, value) == 0) ui->output ("STRAND_ENABLE_STATUS 0x%016llx \n", value);
if (vcpu->get_asi(0x41, 0x20, value) == 0) ui->output ("STRAND_ENABLE 0x%016llx \n", value);
if (vcpu->get_asi(0x41, 0x30, value) == 0) ui->output ("XIR_STEERING 0x%016llx \n", value);
if (vcpu->get_asi(0x41, 0x38, value) == 0) ui->output ("CMT_TICK_ENABLE 0x%016llx \n", value);
if (vcpu->get_asi(0x41, 0x50, value) == 0) ui->output ("STRAND_RUNNING 0x%016llx \n", value);
if (vcpu->get_asi(0x41, 0x58, value) == 0) ui->output ("STRAND_RUNNING_STATUS 0x%016llx \n", value);
ui->output ("\n");
}
return 1;
}
//////////////////////////////////////////////////
//
// cpuregs command
//
int cpuregs_cmd_usage()
{
ui->error("\nusage : cpuregs \n");
return 0;
}
int cpuregs_ui_cmd(void *, int argc, char **argv)
{
if (!IN_STOP_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
Vcpu* vcpu = g_vcpu[pselect_cpu_id];
if (!vcpu)
{
ui->error("cpu %d is not available\n", pselect_cpu_id);
return 0;
}
for (int i=0; i<=VCPU_MAX_INDEX;i++)
{
const char *reg_name = vcpu->get_reg_name(i);
if (reg_name)
{
ui->output("%3d) %s\n", i, reg_name);
}
}
return 1;
}
//////////////////////////////////////////////////
//
// read-reg command
//
int read_reg_cmd_usage()
{
ui->error("\nusage : read-reg [-cpu cpu_set] reg-name\n");
return 0;
}
int read_reg_ui_cmd(void *, int argc, char **argv)
{
if (!IN_STOP_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
char *cmd = "read-reg";
CommandOptions option;
CpuOption cpu_option(pselect_cpu_id,CpuOption::MULTITUDE);
option.add(cpu_option);
std::vector<std::string> args;
if (!option.parse(argc-1,(const char**)&argv[1],args))
{
ui->error("%s command parsing failed: %s\n",cmd,option.get_error_msg().c_str());
return 0;
}
if (args.size() != 1)
{
ui->error("%s requires 1 positional argument - register name.\n",cmd);
return 0;
}
CpuSet& cpu_set = cpu_option.get_value();
for (CpuSet::iterator i=cpu_set.begin(); i != cpu_set.end(); ++i)
{
uint32_t cpu_id = *i;
Vcpu* vcpu = g_vcpu[cpu_id];
if (vcpu == 0)
{
ui->error("cpu[%d] is not available\n", cpu_id);
continue;
}
int index;
uint64_t value;
const char *reg_name = args[0].c_str();
if ( (vcpu->get_reg_index( reg_name, &index )==Vcpu::REG_OK) &&
(vcpu->get_reg( index, &value )==Vcpu::REG_OK))
{
ui->output("cpu[%d]: %s=0x%llx\n",cpu_id, reg_name, value);
}
else
{
ui->error("cpu[%d] - register %s is not available\n", cpu_id, reg_name);
return 0;
}
}
return 1;
}
//////////////////////////////////////////////////
//
// set-pc command
//
int set_pc_cmd_usage()
{
ui->error("\nusage : set-pc address\n");
return 0;
}
int set_pc_ui_cmd(void *, int argc, char **argv)
{
if (!IN_STOP_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
char *cmd = "set_pc";
CommandOptions option;
CpuOption cpu_option(pselect_cpu_id);
option.add(cpu_option);
std::vector<std::string> args;
if (!option.parse(argc-1,(const char**)&argv[1],args))
{
ui->error("%s command parsing failed: %s\n",cmd,option.get_error_msg().c_str());
return 0;
}
if (args.size() != 1)
{
ui->error("%s requires 1 positional argument - pc value.\n",cmd);
return 0;
}
uint32_t cpu_id = *(cpu_option.get_value().begin());
Vcpu* vcpu = g_vcpu[cpu_id];
if (vcpu == 0)
{
ui->error("cpu[%d] is not available\n", cpu_id);
return 0;
}
uint64_t value = strtoull(args[0].c_str(), NULL, 0);
if ( vcpu->set_reg( VCPU_ASR_PC, value )!=Vcpu::REG_OK)
{
ui->error(" cannot set pc value 0x%llx for cpu[%d]\n",value,cpu_id);
return 0;
}
return 1;
}
//////////////////////////////////////////////////
//
// write-reg command
//
int write_reg_cmd_usage()
{
ui->output("\nusage : write-reg [-cpu cpu_set] reg-name value\n");
return 0;
}
int write_reg_ui_cmd(void *, int argc, char **argv)
{
if (!IN_STOP_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
char *cmd = "write-reg";
CommandOptions option;
CpuOption cpu_option(pselect_cpu_id);
option.add(cpu_option);
std::vector<std::string> args;
if (!option.parse(argc-1,(const char**)&argv[1],args))
{
ui->error("%s command parsing failed: %s\n",cmd,option.get_error_msg().c_str());
return 0;
}
if (args.size() != 2)
{
ui->error("%s requires 2 positional argument - reg name and value.\n",cmd);
return 0;
}
uint32_t cpu_id = *(cpu_option.get_value().begin());
Vcpu* vcpu = g_vcpu[cpu_id];
if (vcpu == 0)
{
ui->error("cpu[%d] is not available\n", cpu_id);
return 0;
}
int index;
uint64_t value = strtoull(args[1].c_str(), NULL, 0);
const char *reg_name = args[0].c_str();
if ( (vcpu->get_reg_index( reg_name, &index )!=Vcpu::REG_OK) ||
(vcpu->set_reg( index, value ) !=Vcpu::REG_OK) )
{
ui->error("cannot set reg %s=0x%llx for cpu[%d]\n",reg_name,value,cpu_id);
return 0;
}
return 1;
}