// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: ui_cmds.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 ============================================
SELECT - input multiplexing
DONE - done replies to the sync-server
* Copyright (C) 1996, 2001, 2005 Sun Microsystems, Inc.
#pragma ident "%%1.119 07/01/09 %%"
// handles UI input multiplexing (stdin, sync socket, back door, script file)
// and command parsing, lookup, and calling of registered function for command
// preinit_ui lame excuse for poor programming
// UI_register_cmd add a command string to the lookup list
// UI_invalidate_cmd delete a command string from the lookup list
// init_ui starts up the UI thread
// UI_exec_cmd inserts a command into the back-door queue
// send_diskinfo_to_fakeprom called from scsi_ctrl, fc_ctrl. Yeuch!
/* standard C includes */
#include <sys/resource.h>
// FlexConfig: needs this
#include "blaze_globals.h"
typedef void* TM_OPAQUE_DATA
;
#include "sim_cmd_struct.h"
#include "blaze_globals.h"
#include "ui_cmd_struct.h"
#include "cpu_interface.h"
#include "workerthread.h"
#include "command_opts.h"
#include "readline/readline.h"
#include "readline/history.h"
extern uint32_t boot_ctrl_id
;
extern uint32_t boot_target_id
;
extern uint32_t boot_part_id
;
extern uint32_t boot_disk_id
;
// global cpu_id set by pselect command
extern int eventque_ui_cmds (void*, int argc
, char **argv
);
// ============================================================================
volatile bool_t cpu_enabled
[MAX_MP
]; /* init'd in main.cc */
volatile bool_t cpu_enable_changed
; /* init'd in main.cc */
extern int blaze_debug
; /* lives in main.cc */
extern int blaze_option
; /* lives in main.cc */
// ============================================================================
int exec_cmd (char *s_cmd
);
static int version_ui_cmd (void*, int argc
, char **argv
);
static int conf_ui_cmd (void*, int argc
, char **argv
);
static int mips_ui_cmd (void*, int argc
, char **argv
);
static int file_ui_cmd (void*, int argc
, char **argv
);
static int write_ui_cmd (void*, int argc
, char **argv
);
static int cs_ui_cmd (void*, int argc
, char **argv
);
static int load_ui_cmd (void*, int argc
, char **argv
);
static int setreg_ui_cmd (void*, int argc
, char **argv
);
static int stop_ui_cmd (void*, int argc
, char **argv
);
static int stepim_ui_cmd (void*, int argc
, char **argv
);
static int stept_ui_cmd (void*, int argc
, char **argv
);
static int sync_ui_cmd (void*, int argc
, char **argv
);
static int resume_ui_cmd (void*, int argc
, char **argv
);
static int on_ui_cmd (void*, int argc
, char **argv
);
static int rdt_ui_cmd (void*, int argc
, char **argv
);
static int diskdelay_ui_cmd (void*, int argc
, char **argv
);
static int perf_ui_cmd (void*, int argc
, char **argv
);
static int help_ui_cmd (void*, int argc
, char **argv
);
static int debug_ui_cmd (void*, int argc
, char **argv
);
static int option_ui_cmd (void*, int argc
, char **argv
);
static int alias_ui_cmd (void*, int argc
, char **argv
);
static int unalias_ui_cmd (void*, int argc
, char **argv
);
static int quit_ui_cmd (void*, int argc
, char **argv
);
static int break_ui_cmd (void*, int argc
, char **argv
);
static int list_breakpoints_ui_cmd (void*, int argc
, char **argv
);
static int dbreak_ui_cmd (void*, int argc
, char **argv
);
static int delete_ui_cmd (void*, int argc
, char **argv
);
static int pty_display (void *, int argc
, char **argv
);
static int penable_ui_cmd (void *, int argc
, char **argv
);
static int pdisable_ui_cmd (void *, int argc
, char **argv
);
static int tlbs_ui_cmd (void *, int argc
, char **argv
);
static int vdebug_ui_cmd (void *, int argc
, char **argv
);
static int loglev_ui_cmd (void*, int argc
, char**argv
);
static int devmap_ui_cmd (void*, int argc
, char**argv
);
static int pselect_ui_cmd (void*, int argc
, char**argv
);
static int translate_ui_cmd(void*, int argc
, char **argv
);
static int get_ui_cmd(void*, int argc
, char **argv
);
static int set_ui_cmd(void*, int argc
, char **argv
);
static int disassemble_ui_cmd(void*, int argc
, char **argv
);
static int run_python_file_ui_cmd(void*, int argc
, char **argv
);
static int echo_ui_cmd(void*, int argc
, char **argv
);
static int run_ui_cmd (void*, int argc
, char **argv
);
static int stepi_ui_cmd (void*, int argc
, char **argv
);
static int stepc_ui_cmd (void*, int argc
, char **argv
);
static int read_asi_ui_cmd (void*, int argc
, char **argv
);
static int write_asi_ui_cmd (void*, int argc
, char **argv
);
static void init_sync ();
static Vcpu
* get_vcpu_by_name ( char *name
);
// ======================= GLOBAL VARIABLES ===================================
{"version","\n", 0, version_ui_cmd
, NULL
, NULL
},
{"run", "run <mode>\n", 0, run_ui_cmd
, NULL
, NULL
},
{"file", "file <script file name>\n", 0, file_ui_cmd
, NULL
, NULL
},
{"run-cmd-file", "run-cmd-file <script file name>\n", 0, file_ui_cmd
, NULL
, NULL
},
{"stop", "just stop SAM\n", 0, stop_ui_cmd
, NULL
, NULL
},
{"conf", "conf <name> <value>\n", 0, conf_ui_cmd
, NULL
, NULL
},
{"mips", "mips \n", 0, mips_ui_cmd
, NULL
, NULL
},
{"write", "write <pa> <file> <va> \n", 0, write_ui_cmd
, NULL
, NULL
},
{"load", "load <mode> <addr> <value>\n", 0, load_ui_cmd
, NULL
, NULL
},
{"setreg", "setreg <regname> <value> \n", 0, setreg_ui_cmd
, NULL
, NULL
},
{"console-send", "console-send <string> \n",FUI_STRING
, cs_ui_cmd
, NULL
, NULL
},
{"quit", "quit SAM\n", 0, quit_ui_cmd
, NULL
, NULL
},
{"help", "help <command>", 0, help_ui_cmd
, NULL
, NULL
},
{"debug", "debug [N]", 0, debug_ui_cmd
, NULL
, NULL
},
{"option", "option [N]", 0, option_ui_cmd
, NULL
, NULL
},
{"events", "events", 0, eventque_ui_cmds
, NULL
, NULL
},
{"stepi", "stepi <N>", 0, stepi_ui_cmd
, NULL
, NULL
},
{"stepc", "stepc <N>", 0, stepc_ui_cmd
, NULL
, NULL
},
{"stepim", "stepim <N>", 0, stepim_ui_cmd
, NULL
, NULL
},
{"stept", "stept <usecs>", 0, stept_ui_cmd
, NULL
, NULL
},
{"on", "on STOP <command>", 0, on_ui_cmd
, NULL
, NULL
},
{"rdt", "rdt [<FILE>]", 0, rdt_ui_cmd
, NULL
, NULL
},
{"diskdelay", "diskdelay [ddelay[/wrddelay]] [start_cycle]", 0, diskdelay_ui_cmd
, NULL
, NULL
},
{"perf", "perf # | off", 0, perf_ui_cmd
, NULL
, NULL
},
{"sync", "on|off", 0, sync_ui_cmd
, NULL
, NULL
},
{"resume", "back to prev sync mode", 0, resume_ui_cmd
, NULL
, NULL
},
{"alias", "alias [<old cmd>] [<new cmd>] ",0, alias_ui_cmd
, NULL
, NULL
},
{"unalias", "unalias <alias cmd>" ,0, unalias_ui_cmd
, NULL
, NULL
},
{"penable","penable [-all | <thN>]", 0, penable_ui_cmd
, NULL
, NULL
},
{"pdisable", "pdisable [-all | <thN>]", 0, pdisable_ui_cmd
, NULL
, NULL
},
{"pty", "pty", 0, pty_display
, NULL
, NULL
},
{"break", "set a breakpoint \n", 0, break_ui_cmd
, NULL
, NULL
},
{"list-breakpoints", "list breakpoints \n", 0, list_breakpoints_ui_cmd
, NULL
, NULL
},
{"dbreak", "delete a breakpoint <bp_id>\n", 0, dbreak_ui_cmd
, NULL
, NULL
},
{"delete", "delete breakpoints [all|<bp_id>...]\n", 0, delete_ui_cmd
, NULL
, NULL
},
{"vdebug", "debug tracer on|off\n", 0, vdebug_ui_cmd
, NULL
, NULL
},
{"load_symbols","load symbol table\n", 0, load_sym_ui_cmd
, NULL
, NULL
},
{"unload_symbols","uload symbol table\n", 0, unload_sym_ui_cmd
, NULL
, NULL
},
{"sym", "display symbol table\n", 0, symbols_ui_cmd
, NULL
, NULL
},
{"where", "display call stack\n", 0, where_ui_cmd
, NULL
, NULL
},
{"tlbs", "display tlb entries\n", 0, tlbs_ui_cmd
, NULL
, NULL
},
{"loglev", "loglev [1|2|3]\n", 0, loglev_ui_cmd
, NULL
, NULL
},
{"devmap", "show internal device id map\n", 0, devmap_ui_cmd
, NULL
, NULL
},
{"pselect", "pselect cpu_id\n", 0, pselect_ui_cmd
, NULL
, NULL
},
{"translate", "translate address\n", 0, translate_ui_cmd
, NULL
, NULL
},
{"get", "get memory\n", 0, get_ui_cmd
, NULL
, NULL
},
{"set", "set memory\n", 0, set_ui_cmd
, NULL
, NULL
},
{"disassemble", "disassemble memory\n", 0, disassemble_ui_cmd
, NULL
, NULL
},
{"echo", "echo [(\"string\"|integer|float)]\n", 0, echo_ui_cmd
, NULL
, NULL
},
{"run-python-file", "py execfile\n", 0, run_python_file_ui_cmd
, NULL
, NULL
},
{"read-asi", "read non-translating asi\n", 0, read_asi_ui_cmd
, NULL
, NULL
},
{"write-asi", "write non-translating asi\n",0, write_asi_ui_cmd
, NULL
, NULL
}
static Ui_cmd
* plast
= NULL
;
// ------------ ui-misc globals ------------
static Ui_misc the_misc
= {0};
static Ui_misc
*pui_misc
= &the_misc
;
static uint32_t diskdelay
, wrdiskdelay
;
static uint64_t ddelay_start_cycle
= 0;
int& CpuSet::max_cpu_ndx
= g_vcpu_id_max
;
// ------------- UI-thread globals -------------
static volatile int sync_fd
= -1;
static volatile int sync_on
= 0;
static thread_t ui_sync_tid
;
// ============================ end globals ===================================
// --------------------------- some forward decls --------------------------
int arbitrary_ui_cmd (char * s
);
// these are in "main.cc"
typedef int (*ui_cmd_fn
) (char *);
extern void fe_register_ui_action (ui_cmd_fn foo
) ;
extern char* fe_get_sofile ();
extern void* fe_get_sohandle ();
extern char *pty_dev_a
, *pty_dev_b
;
extern char *pty_dev_c
, *pty_dev_d
;
// the pointers are set to point to real impl. if the py module is loaded to
// add/delete the dynamically created SAM UI commands
typedef void (*Py_Intf_fn
)(const char *);
/////////////////////////////////////////////////
void linkup (Ui_cmd
* pc
)
for (i
= 0; i
< (sizeof(ui_cmd_list
) / sizeof(Ui_cmd
)) - 1; i
++) {
ui_cmd_list
[i
].next
= &ui_cmd_list
[i
+1];
/////////////////////////////////////////////////
for (i
= 0; i
< (sizeof(ui_cmd_list
) / sizeof(Ui_cmd
)) - 1; i
++) {
ui_cmd_list
[i
].next
= &ui_cmd_list
[i
+1];
///////////////////////////////////////////////
// These functions below register new UI commands
void UI_register_cmd_1 (char * name
, char *help
,
ui_cmd_exe_handler efn
, ui_cmd_help_handler hfn
)
Ui_cmd
*pcmd
= (Ui_cmd
*) calloc (1, sizeof(Ui_cmd
));
ui
->error("UI_register can not malloc\n");
pcmd
->name
= (char*) strdup(name
);
pcmd
->help
= (char*) strdup(help
);
pcmd
->cmd_exe_func
= efn
;
pcmd
->cmd_help_func
= hfn
;
pcmd
->flags
= FUI_STRING
; /* _1 */
if(addPycmd
) (*addPycmd
)(name
);
void UI_register_cmd_2 (char * name
, char *help
,
ui_cmd_exe_handler efn
, ui_cmd_help_handler hfn
)
Ui_cmd
*pcmd
= (Ui_cmd
*) calloc (1, sizeof(Ui_cmd
));
ui
->error("UI_register can not malloc\n");
pcmd
->name
= (char*) strdup(name
);
pcmd
->help
= (char*) strdup(help
);
pcmd
->cmd_exe_func
= efn
;
pcmd
->cmd_help_func
= hfn
;
pcmd
->flags
= 0; /* _2 */
if(addPycmd
) (*addPycmd
)(name
);
void UI_register_cmd_3 (char * name
, char *help
,
ui_cmd_exe_handler efn
, ui_cmd_help_handler hfn
, uint32_t flags
)
Ui_cmd
*pcmd
= (Ui_cmd
*) calloc (1, sizeof(Ui_cmd
));
ui
->error("UI_register can not malloc\n");
pcmd
->name
= (char*) strdup(name
);
pcmd
->help
= (char*) strdup(help
);
pcmd
->cmd_exe_func
= efn
;
pcmd
->cmd_help_func
= hfn
;
pcmd
->flags
= flags
; /* _3 */
if(addPycmd
) (*addPycmd
)(name
);
///////////////////////////////////////////////
// this command un-registers a UI command
void UI_invalidate_cmd (char *name
)
for (pcmd
= &ui_cmd_list
[0]; pcmd
;pcmd
= pcmd
->next
) {
if (strcmp(pcmd
->name
, name
) == NULL
) {
pcmd
->flags
|= FUI_INVALID
;
ui
->error("unable to find <%s> command", name
);
// delete the command with the PY UI if present
if(delPycmd
) (*delPycmd
)(name
);
///////////////////////////////////////////////
static const int max_cmd_length
= 2048;
static int fdgets (char * sss
, int fd
)
if (read (fd
, sss
, 1) != 1)
return 0; // convention for closed socket
if (n
>= max_cmd_length
) {
ui
->error("UI command too long (limit %d characters)\n", max_cmd_length
);
sint64_t perf_ui_interval
= 0, // all in "hrtime" units of nanosecs
last_perf_globaltick
= 0;
// ============================ UI SYNC THREAD ================================
// the purpose of this thread is to enable concurrent input from
// sync_fd (is the global-time-sync socket) and to deal with the
extern "C" void * ui_sync_thread (void *arg
)
char sss
[max_cmd_length
];
struct timeval timeout
, *tvp
;
// Open a fake input so that select below works ok
// when there is no sync_fd.
int fake_fd
= open("/dev/null",O_RDONLY
,0);
FD_SET (fake_fd
,&read_set
);
if (IN_SYNC_STATE(blaze_run_state
))
FD_SET (sync_fd
, &read_set
);
if (perf_ui_interval
!= 0) {
sint64_t tmp
= (next_perf_ui_time
- gethrtime());
timeout
.tv_sec
= tmp
/ 1000000000;
timeout
.tv_usec
= (tmp
- 1000000000 * timeout
.tv_sec
) / 1000;
timeout
.tv_sec
= timeout
.tv_usec
= 0;
selrc
= select (FD_SETSIZE
, &read_set
, 0, 0, tvp
); /* SELECT */
if (perf_ui_interval
!= 0
&& (perf_now
= gethrtime()) > next_perf_ui_time
) {
perf_tmp
= SYSTEM_get_ticks ();
ui
->output(" %6.1f %6.3f MIPS \n",
(double)(perf_now
- perf_ui_start
) / 1000000000.0,
(double)(perf_tmp
- last_perf_globaltick
)
/ (perf_ui_interval
/ 1000.0));
next_perf_ui_time
+= perf_ui_interval
;
last_perf_globaltick
= perf_tmp
;
/* @@@ what about EINTR (for keyboard ctrl-C ?) */
ui
->perror ("ui select: ");
if (sync_fd
>= 0 && FD_ISSET (sync_fd
, &read_set
)) { /*SYNC*/
if (fdgets(sss
, sync_fd
)) {
if (strncmp (sss
, "stept ", 6) == 0) {
ui
->error("###sync cmd \"%s\", ignored.\n", sss
);
write (sync_fd
, "done\n", 5); /*quick DONE*/
} else { // the socket closed ...
UI_exec_cmd ("sync off\n");
UI_exec_cmd ("sync disconnect\n");
if (IN_SYNC_STATE(blaze_run_state
)) {
////////////////////////////////////////////////////////
// read user command input
char *line
, *help
; // read line buffer
const char* prompt
= "sam: ";
case e_BLAZE_STOP
: prompt
= "stop: "; break;
case e_BLAZE_STEP
: prompt
= "step: "; break;
case e_BLAZE_RUN
: prompt
= "run: "; break;
case e_BLAZE_GTSTEP
: prompt
= "gtstep:"; break;
case e_BLAZE_GTWAIT
: prompt
= "gtwait:"; break;
default: prompt
= "???"; break;
// Read a line from input. An EOF results in a NULL
// pointer. We simply exit on EOF.
// Only add non blank lines to the history.
for (help
= line
; *help
&& isspace(*help
); ++help
)
if (IN_RUN_STATE (blaze_run_state
))
// ============================ UI THREAD INIT ================================
void init_ui (char *rc
, bool_t notused
)
pui_misc
->rcfile
= (rc
) ? (char*) strdup(rc
) : NULL
;
pui_misc
->redirect_fd
= (-1);
init_sync (); // connect to global-time-sync if server specified
thr_create (NULL
, NULL
, ui_sync_thread
, (void*)0, THR_BOUND
, &ui_sync_tid
);
// ================================ EXEC_CMD ==================================
static void clear_invalid_aliases()
for (Ui_cmd
* pcmd
= &ui_cmd_list
[0]; pcmd
; pcmd
= pcmd
->next
)
if ((pcmd
->flags
& (FUI_ALIAS
|FUI_INVALID
)) ==
pcmd
->flags
&= ~FUI_INVALID
;
int exec_cmd (char *s_cmd
)
static char lastCommand
[max_cmd_length
] = "";
char * ps
= NULL
, *ps1
= NULL
, *ps2
= NULL
, **argv
= NULL
;
if ((*ps
== '\0') || (*ps
== '#'))
//check if the cmd is well double-quoted.
if (ps1
= strchr(ps
, '"')) {
//only when '"' is not escaped by '\', it will be regarded as a valid double-quoted sign.
if (((*ps1
== '"') && ((*(ps1
-1) != '\\')) || (ps1
== ps
))) {
//when the number of valid double-quoted sign is even, the cmd is well quoted.
if ((!(count
%2))&&appear
) {
//when the cmd is not well double-quoted, '#' is regarded as a comment. Or, keep the '#' when it is put into a
//well double-quoted cmd.
if (ps2
= strchr(ps
, '#')) {
if ( strcmp(ps
, "!!") == NULL
)
strcpy(s_cmd
, lastCommand
);
strcpy(lastCommand
, s_cmd
); // save last command
if (*ps
== '%') // register read
return cpu_read_register_name (ps
+1);
argv
= ui_argv_argc_parse (ps
, &argc
);
ui
->error("cmd format error <%s>", ps
);
for (pcmd
= &ui_cmd_list
[0]; pcmd
;pcmd
= pcmd
->next
) {
if (pcmd
->flags
& FUI_INVALID
)
if (strcmp(argv
[0], pcmd
->name
) == NULL
) {
if (pcmd
->flags
& FUI_ALIAS
) {
int new_argc
= argc
+ pcmd
->alias_argc
- 1;
argv
= (char**) realloc(argv
,
sizeof(const char*) * new_argc
);
memmove(argv
+ pcmd
->alias_argc
, argv
+ 1,
sizeof(char**) * (argc
- 1));
memmove(argv
, pcmd
->alias_argv
, sizeof(char**) * pcmd
->alias_argc
);
for (int ndx
= 0; ndx
< pcmd
->alias_argc
; ++ndx
)
ui
->error("cannot strdup <%s>", p
);
pcmd
->flags
|= FUI_INVALID
;
if (pcmd
->flags
& FUI_STRING
) {
char *str
= ui_parsew(s_cmd
, &pw0
);
argv
[1] = (char*) strdup (str
);
if (pcmd
->cmd_exe_func
) { /*******/
int rv
= (pcmd
->cmd_exe_func (NULL
, argc
, argv
)); /*DO IT*/
ui_argv_free(argc
, argv
);
ui_argv_free(argc
, argv
);
ui
->error("unknown command <%s>\n", ps
);
//==============================================================================
// ====================== locally implemented ui functions ====================
/////////////////////////////////////////////
static int run_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");
ui
->output("usage: run\nUse stepi <instruction count> to single step\n");
SYSTEM_run_UI (); /* kicks off async running of cpu-sim threads */
///////////////////////////////////////////////
static int stop_ui_cmd (void*, int argc
, char **argv
)
// we intentionally leave sync_on alone for now...
// that way "resume" can decide which way to go...
////////////////////////////////////////////
// Step for n instructions all cpu's,
// optionally show trace for vcpu: cpuid
// stepi [<nsteps>] [-t [<cpuid>]]
static int stepi_ui_cmd (void*, int argc
, char **argv
)
if (SYSTEM_in_execution_driven_mode()) {
ui
->error("cannot do stepi in exec-driven mode\n");
if (!IN_STOP_STATE (blaze_run_state
)) {
ui
->error("not in stop state\n");
if ((argc
> 1) && isdigit(argv
[1][0]))
sscanf(argv
[1], "%lli", &ni
);
ni
= strtoll(argv
[1], NULL
, 0);
for (int i
=1; i
<argc
; i
++)
if ((strcmp(argv
[i
], "-t")==0) || (strcmp(argv
[i
], "-o")==0))
ui
->error("to enable debug tracer use vdebug command\n");
else if(strcmp(argv
[i
], "?")==0)
ui
->output("usage: stepi [<ninstr>]\n");
static int stepc_ui_cmd(void *, int argc
, char **argv
)
if (!SYSTEM_in_execution_driven_mode()) {
ui
->error("stepc only supported in exec-driven mode\n");
if (!IN_STOP_STATE(blaze_run_state
))
ui
->error("not in stop state, use stop command first\n");
ui
->output("usage: stepc [<ncycles>]\n");
nc
= strtoll(argv
[i
], NULL
, 0);
ui
->error("invalid argument %s\n", argv
[i
]);
///////////////////////////////////////////////
int stepim_ui_cmd (void*, int argc
, char **argv
)
if (argc
> 1) sscanf(argv
[1], "%lli", &ni
);
struct timeval btime
, etime
;
gettimeofday ((struct timeval
*)&btime
, NULL
);
stepi_ui_cmd (NULL
, argc
, argv
);
gettimeofday ((struct timeval
*)&etime
, NULL
);
uint64_t elapsed_usecs
= etime
.tv_sec
* 1000000 + etime
.tv_usec
-
(btime
.tv_sec
* 1000000 + btime
.tv_usec
);
uint64_t icount
= ni
* the_arch
.numcpus
;
double instr_per_sec
= (double)(icount
) /
((double)elapsed_usecs
/ 1000000.0);
ui
->output("ic = %lld, usecs = %lld : %.4f \n",
icount
, elapsed_usecs
, instr_per_sec
);
///////////////////////////////////////////////////
// STEPT <usecs> <seqnum>
static volatile int64_t stept_usecs
= 1;
static volatile int64_t stept_seqnum
= -1; /* most recent request */
static volatile int64_t done_seqnum
= -1; /* most recent reply */
static void stept_done_callback (void * x
)
char buf
[max_cmd_length
];
if (sync_fd
!= -1 && sync_on
) {
if (stept_seqnum
!= -1) {
sprintf (buf
, "done %lld\n", stept_seqnum
);
res
= write (sync_fd
, buf
, strlen(buf
)); /*DONE*/
if (res
!= strlen(buf
)) {
ui
->perror ("sync-done writemsg error:");
done_seqnum
= stept_seqnum
;
static int SYNCDEBUG
= 0;
int stept_ui_cmd (void*, int argc
, char **argv
)
if (!IN_GTWAIT_STATE(blaze_run_state
)) {
ui
->error("not in sync-mode\n");
if (argc
> 1) sscanf(argv
[1], "%lli", &stept_usecs
);
if (argc
> 2) sscanf(argv
[2], "%lli", &stept_seqnum
);
ui
->output("sync[%lld]: for %lld-usecs, now=%lld\n",
stept_seqnum
, stept_usecs
, SYSTEM_get_time());
SYSTEM_stept_UI (stept_usecs
, stept_seqnum
, stept_done_callback
);
/////////////////////////////////////////////
static int resume_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");
///////////////////////////////////////////////
static int quit_ui_cmd (void*, int argc
, char **argv
)
if (IN_RUN_STATE (blaze_run_state
))
stop_ui_cmd (NULL
, 0, NULL
);
///////////////////////////////////////////////
// LOAD <pa> <filename> <va> // was totally simplified by Tycho
extern void load_elf64 (char *filename
, uint64_t base_pa
, uint64_t base_va
);
extern void schizo_ext_init (uint64_t , uint64_t);
static int load_ui_cmd (void*, int argc
, char **argv
)
uint64_t base_pa
, addr
, size
, seg_size
;
int ret
, zero_pad
= 0, create_lbl
= 0;
bool_t load_image
= FALSE
;
ui
->error("RAM object is not ready yet!\n");
if (BLAZE_restore_from_checkpoint())
// don't load the image again, it should be in mem dump already
ui
->error("<%s> image should be already in memory \n", argv
[2]);
if ((argc
== 3) && (strcmp(argv
[1], "image") == NULL
))
if (mm1
->load(argv
[2]) !=0 )
ui
->error("Error in <%s> memory image\n ", argv
[2]);
// Format will be 'load bin file_name start_addr'
if ((argc
== 4) && (strcmp(argv
[1], "bin") == NULL
))
ret
= sscanf (argv
[3], "%llx", &addr
);
if (mm1
->load_bin(argv
[2], addr
) !=0 )
ui
->error("Error in <%s> bin image\n ", argv
[2]);
ui
->error("check LOAD command format\n");
ret
= sscanf (argv
[1], "%lli", &base_pa
);
ui
->error("check PA arg <%s>\n", argv
[1]);
ret
= sscanf (argv
[3], "%lli", &base_va
);
ui
->error("check VA arg <%s>\n", argv
[3]);
filename
= (char*)malloc (strlen(argv
[2]) + 16);
sscanf (argv
[2], "%s", filename
);
load_elf64(filename
, base_pa
, base_va
);
///////////////////////////////////////////////
static int file_ui_cmd (void*, int argc
, char **argv
)
ui
->error("UI (file): format error");
FILE* fp
= fopen(argv
[1],"r");
ui
->error("Can't open <%s>", argv
[1]);
char line
[max_cmd_length
];
while (fgets(line
,max_cmd_length
,fp
))
///////////////////////////////////////////////
extern void complete_cfg ();
extern uint8_t get_platform_index (char *s
);
static void print_new_cpi ()
for (int i
=0; i
<=g_vcpu_id_max
; i
++)
Vcpu
*vcpu
= get_vcpu(i
);
vcpu
->config
.cpi
= ((double)(vcpu
->config
.stickincr
)) * (vcpu
->config
.cpufreq
)
/ (vcpu
->config
.loopticks
) / (vcpu
->config
.stickfreq
);
ui
->output("%s new cpi (=stinc*cpufq/ltick/sysfq) = %6.3f\n",
vcpu
->config
.name
, vcpu
->config
.cpi
);
static int conf_ui_cmd (void*, int argc
, char **argv
)
char *default_s
= (char*)"sun4u";
static bool numcores_initialized
= FALSE
;
static bool numcpus_initialized
= FALSE
;
ui
->output("CMP mode: %s\n", the_arch
.cmp_mode
?"true":"false");
ui
->output("Number of cores: %d\n", the_arch
.numcores
);
ui
->output("CPUs per core: %d\n", the_arch
.cpus_per_core
);
#if defined (CHPLUS_OBP) || defined(CHPLUS) || defined(CHEETAH_OBP) || defined(CHEETAH)
ui
->output("mmutype: %s\n", the_arch
.mmutype
);
ui
->output("flags: 0x%x \n", the_arch
.arch_flags
);
ui
->output("numcpu: %d \n", the_arch
.numcpus
);
ui
->output("ramsize: 0x%llx bytes (%lld MB) \n",
the_arch
.ramsize
, the_arch
.ramsize
>> 20);
ui
->output("cpu per thread: %d\n", the_arch
.cpus_per_thread
);
if (the_arch
.umips
== the_arch
.mips
&& the_arch
.kmips
== the_arch
.mips
)
ui
->output("mips: %lld\n\n", the_arch
.mips
);
ui
->output("umips: %lld\n"
"kmips: %lld\n\n", the_arch
.umips
, the_arch
.kmips
);
ui
->output("cpufreq: %llu\n", the_arch
.cpu_freq
);
ui
->output("stickfreq: %llu\n", the_arch
.stick_freq
);
ui
->output("conf numthreads = %d\n", the_arch
.numthreads
);
ui
->output("conf roundrobin = %d\n", the_arch
.roundrobin
);
else if (strcmp (argv
[1], "ramsize") == NULL
)
ui
->output ("ramsize: 0x%llx bytes (%lld MB) \n",
the_arch
.ramsize
, the_arch
.ramsize
>> 20);
uint64_t lval
= strtoll (argv
[2], &p
, 0);
the_arch
.ramsizeS
= (char*)strdup(argv
[2]);
if ((argc
> 3) && !BLAZE_restore_from_checkpoint())
// mem object is global for entire system
ui
->error("RAM object is already created !!");
mm1
= new SMemory (the_arch
.ramsize
);
if ( !mm1
|| !mm1
->init(mfile_name
) )
ui
->error("cannot allocate mem object size of %llx\n",the_arch
.ramsize
);
if (!BLAZE_restore_from_checkpoint())
memwrite64s_nl(mm1
, pa
, the_arch
.ramsize
);
the_arch
.arch_flags
|= FA_RAMSIZE
;
// TO DO: why do we need these flags?
the_arch
.arch_flags
|= FA_STICKINCR
|FA_TLBSIZE
|FA_PLATFORM
;
else if (strcmp (argv
[1], "memseg") == NULL
)
assert(argc
>= 5 && argc
<= 6);
const char * name
= argv
[2];
uint64_t base
= strtoll(argv
[3],0,0);
size
= strtoll (argv
[4], &p
, 0);
the_arch
.ramsize
+= size
;
the_arch
.ramsizeS
= strdup(ulltostr(the_arch
.ramsize
,q
));
if ((argc
> 5) && !BLAZE_restore_from_checkpoint())
if (!mm1
->addMem(name
,base
,size
,mfile_name
) )
ui
->error("memseg: cannot allocate mem object size of %llx\n",size
);
if (!BLAZE_restore_from_checkpoint())
memwrite64s_nl(mm1
, pa
, the_arch
.ramsize
);
the_arch
.arch_flags
|= FA_RAMSIZE
;
// TO DO: why do we need these flags?
the_arch
.arch_flags
|= FA_STICKINCR
|FA_TLBSIZE
|FA_PLATFORM
;
else if (strcmp(argv
[1], "mips") == 0)
sscanf (argv
[2], "%lld", &the_arch
.mips
);
the_arch
.kmips
= the_arch
.mips
;
the_arch
.umips
= the_arch
.mips
;
if (the_arch
.umips
== the_arch
.kmips
)
ui
->output("mips: %lld\n\n", the_arch
.umips
);
ui
->output("kmips: %lld, umips: %lld\n\n",
the_arch
.kmips
, the_arch
.umips
);
else if (strcmp(argv
[1], "kmips") == 0)
sscanf (argv
[2], "%lld", &the_arch
.kmips
);
ui
->output("conf kmips = %lld\n", the_arch
.kmips
);
else if (strcmp(argv
[1], "umips") == 0)
sscanf (argv
[2], "%lld", &the_arch
.umips
);
ui
->output("conf umips = %lld\n", the_arch
.umips
);
else if (strcmp(argv
[1], "cmips") == 0)
sscanf (argv
[2], "%lld", &the_arch_cmips
);
sscanf (argv
[3], "%d", &the_arch_ccntx
);
ui
->output("conf cmips = %lld for context %d\n",
the_arch_cmips
, the_arch_ccntx
);
ui
->output("conf cmips is ineffective when context is zero\n");
else if (strcmp (argv
[1], "cpu_per_thread") == 0)
sscanf (argv
[2], "%d", &the_arch
.cpus_per_thread
);
cpu_enable_changed
= true;
the_arch
.numthreads
= g_nvcpu
/ the_arch
.cpus_per_thread
;
ui
->output ("conf cpu_per_thread = %d (numthreads = %d)\n",
the_arch
.cpus_per_thread
, the_arch
.numthreads
);
ui
->output ("conf cpu_per_thread = %d\n", the_arch
.cpus_per_thread
);
else if (strcmp (argv
[1], "numthreads") == 0)
sscanf (argv
[2], "%d", &the_arch
.numthreads
);
cpu_enable_changed
= true;
the_arch
.cpus_per_thread
= g_nvcpu
/ the_arch
.numthreads
;
ui
->output ("conf numthreads = %d (cpu_per_thread = %d)\n",
the_arch
.numthreads
, the_arch
.cpus_per_thread
);
ui
->output ("conf numthreads = %d\n", the_arch
.numthreads
);
else if (strcmp (argv
[1], "roundrobin") == 0)
sscanf (argv
[2], "%d", &the_arch
.roundrobin
);
ui
->output ("conf roundrobin = %d\n", the_arch
.roundrobin
);
#if defined (CHPLUS_OBP) || defined(CHPLUS) || defined(CHEETAH_OBP) || defined(CHEETAH)
if (strcmp (argv
[1], "loopticks") == NULL
)
ui
->warning("loopticks has been dpecrecated. Use conf mips\n");
Vcpu
*vcpu
= get_vcpu_by_name ( argv
[3] );
sscanf (argv
[2], "%i", &temp
);
if (temp
>= vcpu
->config
.stickincr
)
vcpu
->config
.loopticks
= temp
;
ui
->error("Ignored: loopticks >= stickincr, limitation\n");
ui
->error("Ignored: unknow cpu instance. \n");
else if (strcmp (argv
[1], "stickincr") == NULL
)
ui
->warning("stickincr has been dpecrecated. Use conf mips\n");
Vcpu
*vcpu
= get_vcpu_by_name ( argv
[3] );
sscanf (argv
[2], "%i", &temp
);
vcpu
->config
.stickincr
= temp
;
ui
->error("Ignored: unknow cpu instance. \n");
else if (strcmp(argv
[1], "cpi") == NULL
)
ui
->error("SAM-GTSync doesn't support cpi feature \n");
ui
->error("conf cpi: move this line to be after cpu is created.\n");
ret
= sscanf (argv
[2], "%i", &id
);
ui
->error("wrong cpu id argument <%s>\n", argv
[2]);
Vcpu
* vcpu
= get_vcpu(id
);
ui
->error("wrong cpu id argument <%s>\n", argv
[2]);
ret
= sscanf (argv
[3], "%f", &ffv
);
ui
->error("wrong cpi argument <%s>\n", argv
[3]);
ui
->output("cpu%d cpi=%f \n", id
, fv
);
ui
->error("Ignored: wrong parameter\n");
// TO DO: why do we need these flags?
the_arch
.arch_flags
|= FA_STICKINCR
|FA_TLBSIZE
|FA_PLATFORM
;
// TODO : some of these arguments should be written into thw memory after
// Not necessarily. All these arguments should be put into 0 page
// so it can be done right in instant way
if (strcmp (argv
[1], "numcores") == NULL
)
int rv
= sscanf(argv
[2], "%i", &the_arch
.numcores
);
if (rv
!= 1 || !the_arch
.numcores
)
ui
->error("conf command: invalid arg %s\n", argv
[2]);
the_arch
.cmp_mode
= true;
the_arch
.cpus_per_core
= the_arch
.numcpus
/the_arch
.numcores
;
if (the_arch
.numcpus
% the_arch
.numcores
)
ui
->error("numcpus %d not divisible by numcores %d\n", the_arch
.numcpus
, the_arch
.numcores
);
numcores_initialized
= TRUE
;
else if (strcmp (argv
[1], "numcpu") == NULL
)
sscanf (argv
[2], "%i", &the_arch
.numcpus
);
memwrite32u_nl(mm1
, pa
, the_arch
.numcpus
);
the_arch
.arch_flags
|= FA_NCPU
;
if (numcores_initialized
)
the_arch
.cpus_per_core
= the_arch
.numcpus
/the_arch
.numcores
;
if (the_arch
.numcpus
% the_arch
.numcores
)
ui
->error("numcpus %d not divisible by numcores %d\n", the_arch
.numcpus
, the_arch
.numcores
);
numcpus_initialized
= TRUE
;
else if (strcmp (argv
[1], "nwins") == NULL
)
sscanf (argv
[2], "%i", &the_arch
.nwins
);
the_arch
.arch_flags
|= FA_NWINS
;
else if (strcmp (argv
[1], "mmutype") == NULL
)
sscanf (argv
[2], "%s", s
);
the_arch
.mmutype
= (char*)strdup(s
);
the_arch
.arch_flags
|= FA_MMUTYPE
;
else if (strcmp (argv
[1], "cputype") == NULL
)
sscanf (argv
[2], "%s", s
);
the_arch
.mmutype
= (char*)strdup(s
);
the_arch
.arch_flags
|= FA_MMUTYPE
;
else if (strcmp (argv
[1], "tlbsize") == NULL
)
sscanf (argv
[2], "%i", &the_arch
.tlbsize
);
the_arch
.arch_flags
|= FA_TLBSIZE
;
#if defined (CHPLUS_OBP) || defined(CHPLUS) || defined(CHEETAH_OBP) || defined(CHEETAH)
else if (strcmp (argv
[1], "loopticks") == NULL
)
ui
->warning("loopticks has been dpecrecated in favor of mips\n");
sscanf (argv
[2], "%i", &temp
);
// set loopticks for all vcpu's
if (temp
>= the_arch
.stickincr
)
for (int i
=0; i
<=g_vcpu_id_max
; i
++)
Vcpu
*vcpu
= get_vcpu(i
);
vcpu
->config
.loopticks
= temp
;
the_arch
.loopticks
= temp
;
the_arch
.loopticks_cp
= the_arch
.loopticks
;
ui
->error("Ignored: loopticks >= stickincr, limitation\n");
else if (strcmp (argv
[1], "stickincr") == NULL
)
ui
->warning("stickincr has been dpecrecated in favor of mips\n");
sscanf (argv
[2], "%i", &temp
);
// set stickincr for all vcpu's
for (int i
=0; i
<=g_vcpu_id_max
; i
++)
Vcpu
*vcpu
= get_vcpu(i
);
vcpu
->config
.stickincr
= temp
;
the_arch
.stickincr
= temp
;
else if (strcmp (argv
[1], "cpufreq") == NULL
)
if ((the_arch
.arch_flags
& FA_FREQ
) == 0)
sscanf (argv
[2], "%llu", &the_arch
.cpu_freq
);
memwrite64s_nl(mm1
, pa
, the_arch
.cpu_freq
);
the_arch
.arch_flags
|= FA_FREQ
;
ui
->error("cannot change cpufreq \n");
else if (strcmp (argv
[1], "stickfreq") == NULL
)
if ((the_arch
.arch_flags
& FA_SFREQ
) == 0)
sscanf (argv
[2], "%llu", &the_arch
.stick_freq
);
memwrite64s_nl(mm1
, pa
, the_arch
.stick_freq
);
the_arch
.arch_flags
|= FA_SFREQ
;
// allow end user to change the stick freq. The reason
// this may be useful is when we want to reach a particular
// simulation state fast. Higher stick frequency(than what is
// known to Solaris) would result in time moving faster from
// Solaris's perspective, making timeouts faster. Another
// sideeffect would be that CPI would change by a factor
// of sam_stick/solaris_stick.
ui
->warning("changing stickfreq \n"
"stick freq in simulated Solaris(prtconf -pv), should be same as in SAM\n"
"cpi observed from Solaris will change to old_cpi*sam_stickfreq/sol_stickfreq\n");
sscanf (argv
[2], "%llu", &the_arch
.stick_freq
);
for(int i
= 0; i
<= g_vcpu_id_max
; i
++)
Vcpu
*vcpu
= get_vcpu(i
);
vcpu
->config
.stickfreq
= the_arch
.stick_freq
;
else if (strcmp (argv
[1], "skipmp") == NULL
)
ui
->warning("skipmp has been dpecrecated. Value will be ignored \n");
sscanf (argv
[2], "%i", &the_arch
.skip_mp
);
else if (strcmp (argv
[1], "blockmp") == NULL
)
ui
->warning("blockmp has been dpecrecated. Value will be ignored \n");
sscanf (argv
[2], "%i", &the_arch
.block_mp
);
else if (strcmp (argv
[1], "platform") == NULL
)
sscanf (argv
[2], "%s", s
);
the_arch
.platform
= (char *) strdup(s
);
// convert platform to index to pass down to fakeprom
idx_to_plist
= get_platform_index(the_arch
.platform
);
memwrite8u_nl(mm1
, pa
, idx_to_plist
);
the_arch
.arch_flags
|= FA_PLATFORM
;
else if (strcmp (argv
[1], "bootpath") == NULL
)
strcpy (bootpath
, argv
[2]);
int boot_aid
,boot_dev
,boot_bus
;
boot_disk_id
= 0; //lun of scsi disk. always 0.
// boot_ctrl_id set from parse_arg on sysconf scsi line
// fakeprom doesn;t need it.
// boot path is of this form - /pci@aid,[6|7]00000/scsi@dev/disk@targ,lun:slice
int result
= sscanf(argv
[2], "/pci@%x,%d/scsi@%d/disk@%x,0:%s",
&boot_aid
,&boot_bus
, &boot_dev
, &boot_target_id
, boot_part
);
ui
->error("unknown parameter <%s> for boot path", argv
[2]);
boot_bus
= (boot_bus
== 7000000) ? 1:0;
boot_part_id
= boot_part
[0] - 'a';
// the pa used below comes from struct fkparam in fakeprom.h
memwrite8u_nl(mm1
, pa
, (uint8_t)boot_dev
);//pci device number of scsi hba on sysconf line
memwrite8u_nl(mm1
, pa
, (uint8_t)boot_target_id
);//scsi disk target id, specified from scsidisk.init
memwrite8u_nl(mm1
, pa
, (uint8_t)boot_part_id
);//parition id of scsi disk, from scsidisk.init
memwrite8u_nl(mm1
, pa
, (uint8_t)boot_disk_id
);//lun of scsi disk. always 0 for our supported disks, redundant info currently
memwrite8u_nl(mm1
, pa
, (uint8_t)boot_aid
);//aid of schizo, to which scsi hba connects to
memwrite8u_nl(mm1
, pa
, (uint8_t)boot_bus
);//busA=0 busB=1. to help fakeprom decide whether boot path prefix is
// pci@<aid>,600000 or pci@<aid>,700000
else if (strcmp (argv
[1], "DC") == NULL
)
sscanf (argv
[2], "%i", &the_arch
.numDCs
);
ui
->output("%d DC on board \n", the_arch
.numDCs
);
else if (strcmp (argv
[1], "NIC") == NULL
)
sscanf (argv
[2], "%i", &the_arch
.numNICs
);
memwrite8u_nl(mm1
, pa
, the_arch
.numNICs
);
else if (strcmp (argv
[2], "done") == NULL
)
if (strcmp (argv
[1], "cpu") == NULL
) {
ui
->error("unknown parameter <%s> ", argv
[1]);
ui
->error("unknown parameter <%s> ", argv
[1]);
if (the_arch
.platform
== NULL
)
// set the_arch.platform to sun4u as default
the_arch
.platform
= strdup(default_s
);
* instrumentation to see if simulator U/K sync-intervals ratio matches
* the actual U/K instructions ratio.
* also calculates the simulated mips using simulated time (stick-interrupts).
static int mips_ui_cmd (void*, int argc
, char **argv
)
int ncpus
= SYSTEM_get_ncpu(), n
= 0;
int64_t instrs
, Uinstrs
, Kinstrs
;
int64_t intervals
, Uintervals
, Kintervals
;
// total instructions simulated, all cpus
Uinstrs
= atomic_and_64 (& WorkerThread::u_instrs
, 0);
Kinstrs
= atomic_and_64 (& WorkerThread::k_instrs
, 0);
instrs
= Uinstrs
+ Kinstrs
;
ui
->output("instructions: %12d\n", 0);
"instructions: %12lld, %12lld-Usr, %12lld-Ker; (%d/%d)\n",
(Uinstrs
+Kinstrs
)/ncpus
, Uinstrs
/ncpus
, Kinstrs
/ncpus
,
(int)((Uinstrs
*100+50)/instrs
),
(int)((Kinstrs
*100+50)/instrs
));
// total 1-usec time sync intervals, all cpus
Uintervals
= atomic_and_64 (& WorkerThread::u_intervals
, 0);
Kintervals
= atomic_and_64 (& WorkerThread::k_intervals
, 0);
intervals
= Uintervals
+ Kintervals
;
ui
->output("sync-intervals: %12d\n", 0);
"sync-intervals: %12lld, %12lld-Usr, %12lld-Ker; (%d/%d)\n",
intervals
/ncpus
, Uintervals
/ncpus
, Kintervals
/ncpus
,
(int)((Uintervals
*100+50)/intervals
),
(int)((Kintervals
*100+50)/intervals
));
// average per-cpu mips, in simulated time not wall clock time
ui
->output("effective-mips: %12d\n", 0);
ui
->output("effective-mips: %12lld\n",
// this function is called by:
uint8_t send_diskinfo_to_fakeprom()
memwrite8u_nl(mm1
, pa
, (uint8_t)SYSTEM_get_scsi_disk_enable_flag()
| (uint8_t)SYSTEM_get_fc_disk_enable_flag() <<1);
memwrite8u_nl(mm1
, pa
, (uint8_t)SYSTEM_get_scsi_boot_enable_flag()
| (uint8_t)SYSTEM_get_fc_boot_enable_flag() <<1);
memwrite8u_nl(mm1
, pa
, (uint8_t)SYSTEM_get_ce_enable_flag());
// added for platform support, to pass down to fakeprom
const char *os_platform_lists
[] = { // fakeprom must have the same table
"sun4u", // default settting
"SUNW,Ultra-Enterprise-10000",
"SUNW,UltraSPARCengine_CP-20",
"SUNW,UltraSPARCengine_CP-40",
"SUNW,UltraSPARCengine_CP-60",
uint8_t get_platform_index(char *s
)
while (strcmp (s
, os_platform_lists
[retval
]) != NULL
) {
if (strcmp (os_platform_lists
[retval
], "nomore") == NULL
)
return 0; // if not found, set to default "sun4u"
///////////////////////////////////////////////
static int write_ui_cmd (void*, int argc
, char **argv
)
ui
->error("Check command format");
ret
= sscanf (argv
[2], "%lli", &paddr
);
ui
->error("wrong address");
ret
= sscanf (argv
[3], "%lli", &value
);
ui
->error("wrong value");
ui
->error("RAM object is not ready yet!");
if (strcmp(argv
[1], "word") == 0) {
memwrite32u_nl(mm1
, paddr
, value
);
} else if (strcmp(argv
[1], "lword") == 0) {
memwrite64s_nl(mm1
, paddr
, value
);
} else if (strcmp(argv
[1], "hword") == 0) {
memwrite16u_nl(mm1
, paddr
, value
);
} else if (strcmp(argv
[1], "byte") == 0) {
memwrite8u_nl(mm1
, paddr
, value
);
ui
->error("wrong format (size)");
///////////////////////////////////////////////
//typedef void (*serial_send)(void *, char *);
extern serialInterface
* systemConsole
;
int static cs_ui_cmd (void*, int argc
, char **argv
)
ui
->error("command format error!\n");
ui
->error("system console not yet initialized\n");
str
= extract_string(argv
[1]);
systemConsole
->chars_send(str
,systemConsole
->portH
);
///////////////////////////////////////////////
// RDT <filename> # redirect stdout
/*static?*/ int rdt_ui_cmd (void*, int argc
, char **argv
)
// redirect back (FILE->stdout)
FILE * fp
= fopen (argv
[1], "w");
if (redirect_stdout (fileno(fp
))) {
ui
->output("STDOUT redirected to <%s>\n", argv
[1]);
ui
->error("wrong RDT command format\n");
///////////////////////////////////////////////
/*static?*/ int on_ui_cmd (void*, int argc
, char **argv
)
ui
->error("wrong format ON command\n");
if (strcmp(argv
[1], "stop") == NULL
) {
for (ii
= 2; ii
< argc
; ii
++) {
len
+= (int)strlen(argv
[ii
]);
len
+= argc
+ 4; // just in case :-)
str
= (char*) malloc (len
);
for (ii
= 3; ii
< argc
; ii
++) {
if (strcmp(argv
[2], "discard") == NULL
) {
Ui_blcmd
*pcmd
= pui_misc
->stop_list
, *next
;
pui_misc
->stop_list
= pcmd
= next
;
///////////////////////////////////////////////
int static setreg_ui_cmd (void*, int argc
, char **argv
)
ui
->error("wrong number of arguments : %d\n", argc
);
ui
->error("Move this line to be after CPU is created ...\n");
ret
= sscanf (argv
[2], "%lli", &value
);
ui
->error("wrong VALUE argument <%s>\n", argv
[2]);
if (strcmp(argv
[1], "pc") == NULL
) {
for (uint32_t id
= 0; id
<= g_vcpu_id_max
; id
++) {
Vcpu
*vcpu
= get_vcpu(id
);
g_vcpu
[id
]->set_reg(VCPU_ASR_PC
, value
);
else if (strcmp(argv
[1], "npc") == NULL
) {
for (uint32_t id
= 0; id
<= g_vcpu_id_max
; id
++) {
Vcpu
*vcpu
= get_vcpu(id
);
g_vcpu
[id
]->set_reg(VCPU_ASR_NPC
, value
);
ui
->error("unsupported register <%s>\n", argv
[1]);
ret
= sscanf (argv
[1], "%i", &id
);
ui
->error("wrong cpu id argument <%s>\n", argv
[2]);
ui
->error("wrong cpu id argument <%s>\n", argv
[2]);
ret
= sscanf (argv
[3], "%lli", &value
);
ui
->error("wrong value argument <%s>\n", argv
[3]);
if (strcmp(argv
[2], "pc") == NULL
) {
vcpu
->set_reg(VCPU_ASR_PC
, value
);
else if (strcmp(argv
[2], "npc") == NULL
) {
vcpu
->set_reg(VCPU_ASR_NPC
, value
);
ui
->error("unknown reg NAME <%s>\n", argv
[2]);
///////////////////////////////////////////////
int static alias_ui_cmd (void*, int argc
, char **argv
)
for (pcmd
= &ui_cmd_list
[0]; pcmd
;pcmd
= pcmd
->next
) {
if (pcmd
->flags
& FUI_ALIAS
) {
ui
->output("<%s> --> ", pcmd
->name
);
for (int32_t ndx
= 0; ndx
< pcmd
->alias_argc
; ++ndx
)
ui
->output("%s ", pcmd
->alias_argv
[ndx
]);
for (pcmd
= &ui_cmd_list
[0]; pcmd
;pcmd
= pcmd
->next
) {
if (strcmp(argv
[1], pcmd
->name
) == NULL
)
ui
->error("command <%s> not found \n", argv
[1]);
if (!(pcmd
->flags
& FUI_ALIAS
)) {
ui
->error("command <%s> is not an alias \n", argv
[1]);
ui
->output("<%s> --> ", pcmd
->name
);
for (int32_t ndx
= 0; ndx
< pcmd
->alias_argc
; ++ndx
)
ui
->output("%s ", pcmd
->alias_argv
[ndx
]);
// handle "alias new old ..."
// limit aliases to C-style identifiers i.e. alphanumeric and '_';
char* const alias_name
= argv
[1];
for (int ndx
= 0; alias_name
[ndx
] != '\0'; ++ndx
) {
if (!isalpha(alias_name
[ndx
]) && alias_name
[ndx
] != '_') {
if (ndx
== 0 || !isdigit(alias_name
[ndx
])) {
ui
->error("illegal alias name <%s>\n", alias_name
);
for (pcmd
= &ui_cmd_list
[0];
prev_cmd
= pcmd
, pcmd
= pcmd
->next
) {
if (strcmp(alias_name
, pcmd
->name
) == NULL
) {
if ((pcmd
->flags
& FUI_ALIAS
) == 0)
ui
->error("command <%s> cannot be aliased\n", alias_name
);
free((void*)pcmd
->alias_argv
[pcmd
->alias_argc
--]);
free((void*)pcmd
->alias_argv
);
prev_cmd
->next
= pcmd
->next
;
pcmd
= (Ui_cmd
*) calloc (1, sizeof(Ui_cmd
));
ui
->error("register: cant malloc\n");
pcmd
->name
= (char*) strdup(alias_name
);
sprintf(buf
, "alias for %s", pcmd
->name
);
pcmd
->help
= (char*) strdup(buf
);
pcmd
->cmd_exe_func
= NULL
;
pcmd
->cmd_help_func
= NULL
;
pcmd
->alias_argc
= argc
- 2;
(const char**)malloc((argc
-2) * sizeof(const char*));
if (pcmd
->alias_argv
== NULL
) {
ui
->error("register: cant malloc\n");
for (int ndx
= 0; ndx
< argc
- 2; ++ndx
)
pcmd
->alias_argv
[ndx
] = strdup(argv
[ndx
+ 2]);
if (pcmd
->alias_argv
[ndx
] == NULL
) {
ui
->error("register: cant strdup %x\n", argv
[ndx
+ 2]);
Ui_cmd
* pc
= &ui_cmd_list
[0];
for ( ;pc
->next
; pc
= pc
->next
)
///////////////////////////////////////////////
int static unalias_ui_cmd (void*, int argc
, char **argv
)
for (pcmd
= &ui_cmd_list
[0];
prev_cmd
= pcmd
, pcmd
= pcmd
->next
) {
if (strcmp(argv
[1], pcmd
->name
) == NULL
) {
if ((pcmd
->flags
& FUI_ALIAS
) == 0)
ui
->error("command <%s> cannot be aliased\n", argv
[1]);
free((void*)pcmd
->alias_argv
[pcmd
->alias_argc
--]);
free((void*)pcmd
->alias_argv
);
prev_cmd
->next
= pcmd
->next
;
ui
->error("cannot find alias <%s>\n",
ui
->error("usage: unalias <alias cmd>\n");
///////////////////////////////////////////////
// MIPS [#|off] # compute blaze MIPS
perf_ui_cmd (void*, int argc
, char**argv
)
if ((argc
== 2 && strcmp (argv
[1], "off") == 0) || argc
== 1) {
if (argc
== 2 && sscanf (argv
[1], "%f", &tmp
) == 1) {
perf_ui_interval
= tmp
* 1000000000; /* cvt to nano-secs for hr time*/
perf_ui_start
= gethrtime();
next_perf_ui_time
= perf_ui_start
+ perf_ui_interval
;
last_perf_globaltick
= SYSTEM_get_ticks ();
ui
->error("usage : perf # | off \n");
///////////////////////////////////////////////
// DEBUG, and OPTION settings
int static debug_ui_cmd (void*, int argc
, char **argv
)
blaze_debug
= strtoul((const char*)argv
[1], (char**)NULL
, 0);
ui
->output("blaze_debug = %d \n", blaze_debug
);
int static option_ui_cmd (void*, int argc
, char **argv
)
blaze_option
= strtoul((const char*)argv
[1], (char**)NULL
, 0);
ui
->output("blaze_option = %d \n", blaze_option
);
///////////////////////////////////////////////
int static version_ui_cmd (void*, int argc
, char **argv
)
ui
->output("SAM VERSION %s\n", BLAZEVERSION_STRING
);
ui
->output("BUILT ON %s, AT %s, IN %s\n", __DATE__
,__TIME__
,__CWD__
);
///////////////////////////////////////////////
int static help_ui_cmd (void*, int argc
, char **argv
)
ui
->output("SAM now supports UI commands: \n\n");
for (pcmd
= &ui_cmd_list
[0]; pcmd
; pcmd
= pcmd
->next
) {
if (pcmd
->flags
& FUI_INVALID
)
ui
->output("%s\n", pcmd
->name
);
if (strcmp(argv
[1], "all") == NULL
) {
for (pcmd
= &ui_cmd_list
[0]; pcmd
; pcmd
= pcmd
->next
) {
if (pcmd
->flags
& FUI_INVALID
)
ui
->output ("%s : %s\n", pcmd
->name
, pcmd
->help
);
for (pcmd
= &ui_cmd_list
[0]; pcmd
; pcmd
= pcmd
->next
) {
if (pcmd
->flags
& FUI_INVALID
)
if (strcmp(pcmd
->name
, argv
[1]) == NULL
) {
ui
->output("%s\n", pcmd
->help
);
///////////////////////////////////////////////
// The interface for UI commands
void UI_exec_cmd (char *cmd
)
///////////////////////////////////////////////
void store_stdout_fd (int fd
)
pui_misc
->redirect_fd
= fd
;
///////////////////////////////////////////////
return pui_misc
->redirect_fd
;
///////////////////////////////////////////////
void add_to_stop_list (char * cmd_str
)
Ui_blcmd
*pcmd
= (Ui_blcmd
*) calloc (1, sizeof(Ui_blcmd
));
ui
->error("unable to deffer <%s> command \n", cmd_str
);
if (pui_misc
->stop_list
== NULL
) {
pui_misc
->stop_list
= pcmd
;
Ui_blcmd
*prev_cmd
= pui_misc
->stop_list
;
while (prev_cmd
->next
!= NULL
) {
prev_cmd
= prev_cmd
->next
;
///////////////////////////////////////////////
get_disk_ddelay_start_cycle(void)
return ddelay_start_cycle
;
static int diskdelay_ui_cmd (void*, int argc
, char **argv
)
diskdelay
= atoi((const char*)argv
[1]);
if (strchr(argv
[1], '/') != NULL
) {
if (sscanf(argv
[1], "%d/%d", &diskdelay
, &wrdiskdelay
) != 2) {
ui
->error("diskdelay format error !\n");
ddelay_start_cycle
= strtoul((const char*)argv
[2], (char**)NULL
, 0);
ddelay_start_cycle
= SYSTEM_get_ticks ();
ui
->output("DISK : ddelay = %d, wrddelay = %d, start_cycle = %lld\n",
diskdelay
, wrdiskdelay
, ddelay_start_cycle
);
ui
->output("DISK : ddelay = %d, wrddelay = %d, start_cycle = %lld\n",
diskdelay
, wrdiskdelay
, ddelay_start_cycle
);
// ================================== SYNC-UI =================================
// volatile int sync_fd = -1; moved up above to ui-thread,
// volatile int sync_on = 0; ditto,
// along with stept_usecs, stept_seqnum, done_seqnum.
typedef volatile struct sync_s
{
static syncT sync_obj
= {0};
static volatile syncT
* sync1
= &sync_obj
;
static int sync_ui_cmd (void*, int argc
, char **argv
);
static void sync_ui_usage ();
static void sync_connect (syncT
* msp
, const char * switchname
);
static void sync_disconnect (syncT
* msp
);
// attempt an initial connection if a server name is specified
const char * name
= SYSTEM_get_hostconfig ("sync.host");
if (!name
) name
= SYSTEM_get_hostconfig ("switch.host");
sprintf (buf
, "sync:%s", name
);
sync1
->switchname
= strdup (buf
);
sync_fd
= netsim_connect (sync1
->switchname
);
static int sync_ui_cmd (void*, int argc
, char * argv
[])
if (argc
== 2 && strcmp (argv
[1], "on") == 0) { // "sync on" <--
ui
->error("already in time-sync mode\n");
else if (!IN_STOP_STATE (blaze_run_state
)) {
ui
->error("not in stop state, use stop command first\n");
ui
->error("time-sync not connected\n");
write (sync_fd
, "conn\n", 5); // Inform Sync-Master !!
SYSTEM_syncon_UI (); // transition !!!
if (argc
== 2 && strcmp (argv
[1], "off") == 0) { // "sync off" <-
ui
->error("not in time-sync mode\n");
ui
->error("time-sync not connected\n");
write (sync_fd
, "disconn\n", 8); // Inform Sync-Master !!!
SYSTEM_syncoff_UI (); // transition !!!
// ------------------ remote connection state ----------------------
|| (argc
== 2 && strcmp (argv
[1], "print") == 0)) { // "print"
ui
->output("\tsync1: %s", msp
->switchname
);
if (stept_seqnum
!= -1) {
if (IN_GTSTEP_STATE(blaze_run_state
))
ui
->output("\t %s, %lld *\n",
else if (IN_GTWAIT_STATE(blaze_run_state
))
ui
->output("\t %s, %lld \n",
ui
->output("\t %s, %lld \n",
(sync_on
? "on" : "off"), done_seqnum
);
ui
->output("\t %s \n", (sync_on
? "on" : "off"));
ui
->output("\tsync1: disconnected\n");
if (argc
== 2 && strcmp (argv
[1], "disconnect") == 0) { // "disconnect"
if (argc
== 2 && strcmp (argv
[1], "connect") == 0) { // "connect"
sync_connect (msp
, msp
->switchname
);
if (argc
== 3 && strcmp (argv
[1], "connect") == 0) { // "connect host"
sync_connect (msp
, argv
[2]);
// --------------------------- stuff ----------------------------
if (argc
>= 2 && strcmp (argv
[1], "debug") == 0) { // "debug"
ui
->output("sync debug level is %d\n", SYNCDEBUG
);
SYNCDEBUG
= atoi (argv
[2]);
sync_ui_usage (); /* if we haven't already returned... */
// see also sync_thread_main for handling of disconnect by other end of socket
static void sync_disconnect (syncT
* msp
)
ui
->error("sync already disconnected\n");
sync_fd
= -1; /* <--- ui-thread will see this <--- */
static void sync_connect (syncT
* msp
, const char * switchname
)
ui
->error("sync already connected\n");
} else if (switchname
== NULL
) {
ui
->error("sync no switchname\n");
ui
->output("sync reconnecting\n");
sprintf(buf
,"sync:%s", switchname
);
if ((fd
= netsim_connect (buf
)) >= 0) {
msp
->switchname
= strdup (switchname
);
ui
->error("connection failed\n");
static void sync_ui_usage ()
ui
->output(" sync on|off\n");
ui
->output(" sync connect [hostname[/portnum]]\n");
ui
->output(" sync disconnect\n");
ui
->output(" sync print|stats|reset|debug\n");
////////////////////////////////////////////////////////////////
class PenableDisableOptions
: public CommandOptions
PenableDisableOptions(const std::string
& cmd_
)
cpu_opt(CpuSet().clear_all(), CpuOption::MULTITUDE
)
virtual ~PenableDisableOptions() {}
std::string
get_cmd() const { return cmd
; }
"" + cmd
+ " command usage:\n"
"\t" + cmd
+ " -cpu <cpu set>\n"
"\t" + cmd
+ " <cpu mask>\n";
static int penable_disable_ui_cmd (void *, int argc
, char **argv
,
bool new_state
, PenableDisableOptions
& options
)
for (i
= 0; i
< the_arch
.numcpus
; i
++)
int sid
= get_vcpu(i
)->id();
ui
->output("cpuid %d %s\n", sid
, cpu_enabled
[sid
] ? "enabled" : "disabled");
std::vector
<std::string
> pos_args
;
bool result
= options
.parse(argc
-1, (const char**)&argv
[1], pos_args
);
if (options
.cpu_opt
.is_on()) {
cpu_set
= options
.cpu_opt
.get_value();
if (pos_args
.size() != 1) {
if (!UnsignedOption::parse_number(pos_args
[0], cpu_mask
, error_msg
)) {
std::string fmt
= "UI " + options
.get_cmd() + ": Bad cpu mask: %s\n";
ui
->error(fmt
.c_str(), pos_args
[0].c_str());
bool out_of_bounds
= false;
cpu_set
.insert_mask(cpu_mask
, &out_of_bounds
);
ui
->warning("cpu mask (%s) out of range\n",
for (CpuSet::iterator iter
= cpu_set
.begin();
cpu_enabled
[i
] = new_state
;
cpu_enable_changed
= true;
std::string fmt
= "UI " + options
.get_cmd() + ": Syntax error\n\t%s\n";
ui
->error(fmt
.c_str(),options
.get_error_msg().c_str());
static int penable_ui_cmd (void *, int argc
, char **argv
)
PenableDisableOptions
options("penable");
return penable_disable_ui_cmd(NULL
, argc
, argv
, true, options
);
static int pdisable_ui_cmd (void *, int argc
, char **argv
)
PenableDisableOptions
options("pdisable");
return penable_disable_ui_cmd(NULL
, argc
, argv
, false, options
);
//////////////////////////////////////////////////////////////
int static pty_display (void *, int argc
, char **argv
)
ui
->output("SAM: Serial port A (pty device) for TIP connection is %s\n", pty_dev_a
);
ui
->output("SAM: Serial port B (pty device) for TIP connection is %s\n", pty_dev_b
);
ui
->output("SAM: Serial port C (pty device) for TIP connection is %s\n", pty_dev_c
);
ui
->output("SAM: Serial port D (pty device) for TIP connection is %s\n", pty_dev_d
);
//////////////////////////////////////////////////////////////
// break [?|cpu=[<cpu_id>|all]]
// [iaddr=<value>|opcode=<value>|data_read_addr=<value>|data_write_addr=<value>]
int bp_action ( int bp_id
, int vcpu_id
)
ui
->output("cpu %i hit breakpoint %i, stop... \n", vcpu_id
, bp_id
);
// request simulation stop
BLAZE_STOP(blaze_stop_request
);
//sinal stop to remote debug client if any
class BreakOptions
: public CommandOptions
cpu_opt(CpuSet().insert_all(), CpuOption::MULTITUDE
),
// -trap qutiand -red are mutual exclusive
excl_opts
.add(trap_opt
).add(red_opt
);
virtual ~BreakOptions() {}
ui
->output("set breakpoint command usage:\n");
ui
->output("\tbreak pc_va\n");
ui
->output("\tbreak pc_va cpu_id\n");
ui
->output("\tbreak -cpu [cpu_id|all] pc_va\n");
ui
->output("\tbreak -cpu [cpu_id|all] -trap trap_type\n");
ui
->output("\tbreak -cpu [cpu_id|all] -red\n");
ExclusiveOptions excl_opts
;
int break_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");
std::vector
<std::string
> pos_args
;
bool result
= options
.parse(argc
-1, (const char**)&argv
[1], pos_args
);
CpuSet cpu_set
= options
.cpu_opt
.get_value();
// printout all existing breakpoints
for (int i
=0; i
<=g_vcpu_id_max
; i
++)
g_vcpu
[i
]->print_breakpoints(ui
->get_output_file());
g_vcpu
[i
]->print_breakpoints(ui
->get_log_file());
// break -cpu [cpu_id|all] -trap trap_type
if (options
.trap_opt
.is_on())
if (pos_args
.size() == 0)
bp_value
= options
.trap_opt
.get_value();
ui
->error("break on trap does not take any arguments\n");
// break -cpu [cpu_id|all] -red
else if (options
.red_opt
.is_on())
if (pos_args
.size() == 0)
ui
->error("break on red does not take arguments\n");
else if (options
.cpu_opt
.is_on())
// break -cpu [cpu_id|all] pc_va
bp_type
= VCPU_BP_INSTR_ADDR
;
if (!UnsignedOption::parse_number(pos_args
[0], bp_value
, error_msg
))
ui
->error("%s\n", error_msg
.c_str());
ui
->error("break on PC requires a PC value\n");
bp_type
= VCPU_BP_INSTR_ADDR
;
if (pos_args
.size() >= 1)
if (!UnsignedOption::parse_number(pos_args
[0], bp_value
, error_msg
))
ui
->error("%s\n", error_msg
.c_str());
if (pos_args
.size() == 2)
// set on the specified cpu
if (!UnsignedOption::parse_number(pos_args
[1], cpu_id
, error_msg
))
ui
->error("%s\n", error_msg
.c_str());
bool out_of_bounds
= false;
cpu_set
.insert(cpu_id
, &out_of_bounds
);
ui
->error("Cpu number %d is out of range\n", cpu_id
);
// set breakpoints on all valid cpus
for (CpuSet::iterator iter
= cpu_set
.begin();
ui
->fatal("internal error: break_ui_cmd: cpu 0x%lx out of range\n",i
);
g_vcpu
[i
]->set_breakpoint(&bp_id
, bp_type
, bp_value
,
bp_action
, bp_mask
)== 0)
ui
->output("set breakpoint %i, for cpu %i \n", bp_id
, g_vcpu
[i
]->id());
ui
->error("break command parsing failed: %s\n",
options
.get_error_msg().c_str());
int break_ui_cmd_OLD (void*, int argc
, char **argv
)
if (!IN_STOP_STATE (blaze_run_state
))
ui
->error("not in stop state, use stop command first\n");
if ((argc
< 2) || (argc
> 4))
return BreakOptions::usage();
if (strcmp(argv
[1], "?")==0) // print info for all
// printout all existing breakpoints
for (int i
=0; i
<=g_vcpu_id_max
; i
++)
g_vcpu
[i
]->print_breakpoints(ui
->get_output_file());
g_vcpu
[i
]->print_breakpoints(ui
->get_log_file());
// read second argument as cpu=id
name
= strtok ( argv
[1], " =" );
param
= strtok ( NULL
, "\0" );
if( !name
|| !param
|| (strcmp(name
, "cpu") != 0) )
ui
->error("missing cpu id \n");
return BreakOptions::usage();
if ( strcmp(param
, "all") == 0)
cpu_id
= (int)strtol(param
, NULL
, 0);
if ((cpu_id
<0) || ( ( vcpu
= get_vcpu(cpu_id
) ) == 0) )
ui
->error("bad cpu id[%d] \n", cpu_id
);
return BreakOptions::usage();
ui
->error("incomplete list of breakpoint parameters \n");
return BreakOptions::usage();
// read third argument as <type=value>
name
= strtok ( argv
[2], " =" );
param
= strtok ( NULL
, "\0" );
ui
->error("missing breakpoint type \n");
return BreakOptions::usage();
bp_value
= strtoull(param
, NULL
, 0);
bp_type
= VCPU_BP_INSTR_ADDR
;
if (strcmp(name
, "pc" ) == 0 ) bp_type
= VCPU_BP_INSTR_ADDR
;
else if (strcmp(name
, "opcode") == 0 ) bp_type
= VCPU_BP_OPCODE
;
else if (strcmp(name
, "dread" ) == 0 ) bp_type
= VCPU_BP_DATA_READ_ADDR
;
else if (strcmp(name
, "dwrite") == 0 ) bp_type
= VCPU_BP_DATA_WRITE_ADDR
;
ui
->error("breakpoint type should be: iaddr | opcode | data_read | data_write \n");
return BreakOptions::usage();
name
= strtok ( argv
[3], " =" );
param
= strtok ( NULL
, "\0" );
ui
->error("missing breakpoint mask \n");
return BreakOptions::usage();
bp_mask
= strtoull(param
, NULL
, 0);
ui
->error("incorrect breakpoint mask\n");
return BreakOptions::usage();
for (int i
=0; i
<=g_vcpu_id_max
; i
++)
g_vcpu
[i
]->set_breakpoint(&bp_id
, bp_type
, bp_value
,
bp_action
, bp_mask
)== 0)
ui
->output("set breakpoint %i for cpu %i \n", bp_id
, g_vcpu
[i
]->id());
vcpu
->set_breakpoint(&bp_id
, bp_type
, bp_value
,
ui
->output("set breakpoint %i for cpu %i \n", bp_id
, cpu_id
);
return BreakOptions::usage();
////////////////////////////////////////////////////
// command: dbreak cpu=[<cpu_id>|all] bp_id
static int print_dbreak_usage()
ui
->output("delete breakpoint command usage:\n dbreak cpu=[<cpu_id>|all]"
int dbreak_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 print_dbreak_usage();
// read second argument as cpu=id
name
= strtok ( argv
[1], " =" );
param
= strtok ( NULL
, "\0" );
if( !name
|| !param
|| (strcmp(name
, "cpu") != 0) )
ui
->error("break: missing cpu id \n");
return print_dbreak_usage();
if ( strcmp(param
, "all") == 0)
cpu_id
= (int)strtol(param
, NULL
, 0);
if ((cpu_id
<0) || ( ( vcpu
= get_vcpu(cpu_id
) ) == 0) )
ui
->error("bad cpu id[%d] \n", cpu_id
);
return print_dbreak_usage();
name
= strtok ( argv
[2], " =" );
param
= strtok ( NULL
, "\0" );
if (!name
|| !param
|| (strcmp(name
, "bp_id") != 0))
ui
->error("missing breakpoint id \n");
return print_dbreak_usage();
bp_id
= strtol(param
, NULL
, 0);
for (int i
=0; i
<=g_vcpu_id_max
; i
++)
g_vcpu
[i
]->delete_breakpoint(-1)== 0)
ui
->output("delete breakpoint %i for cpu %i \n", bp_id
, g_vcpu
[i
]->id());
vcpu
->delete_breakpoint(bp_id
)==0)
ui
->output("delete breakpoint %i for cpu %i \n", bp_id
, cpu_id
);
////////////////////////////////////////////////////
// command: delete [-all] [<bp_id> ... ]
class DeleteOptions
: public CommandOptions
virtual ~DeleteOptions() {}
ui
->output("usage: delete [-all] [<bp_id> ... ]\n");
int delete_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");
std::vector
<std::string
> pos_args
;
bool result
= options
.parse(argc
-1, (const char**)&argv
[1], pos_args
);
// remove all breakpoints
if (options
.all_opt
.is_on())
ui
->output("deleting all breakpoints\n");
for (int i
=0; i
<=g_vcpu_id_max
; i
++)
g_vcpu
[i
]->delete_breakpoint(-1);
for (std::vector
<std::string
>::iterator iter
= pos_args
.begin();
if (!UnsignedOption::parse_number(*iter
, bp_id
, err_msg
))
err_msg
+= "breakpoint id\n";
ui
->error(err_msg
.c_str());
for (i
=0; i
<=g_vcpu_id_max
; i
++)
if (g_vcpu
[i
] && g_vcpu
[i
]->delete_breakpoint(bp_id
) == 0) {
ui
->output("deleting breakpoint %d\n", bp_id
);
ui
->error("Unknown breakpoint %d\n", bp_id
);
///////////////////////////////////////////////////////
// set debug tracer on/off
static int print_vdebug_usage()
ui
->output("debug tracer usage:\n vdebug [-cpu <cpu_set>][-o <file_name>] on|off\n");
static int vdebug_ui_cmd (void*, int argc
, char **argv
)
if (ANY_RUNNING_STATE (blaze_run_state
))
ui
->error(" not in stop state, use stop command first\n");
if ( argc
== 1) // show status
return tracer_cmd (STRACER_STATUS
);
return print_vdebug_usage();
CpuOption
cpu_option(pselect_cpu_id
,CpuOption::MULTITUDE
);
StringOption
out_option("o");
std::vector
<std::string
> args
;
if (!option
.parse(argc
-1,(const char**)&argv
[1],args
))
fprintf(stderr
, "ERROR: %s command parsing failed: %s\n",cmd
,option
.get_error_msg().c_str());
fprintf(stderr
, "ERROR: %s requires 1 positional argument - on|off.\n",cmd
);
else // parse on/off flag
return print_vdebug_usage();
bool separate_files
= false;
int sid
[NCPU_MAX
]; // cpu id's that need to be traced
for (int i
=0; i
<NCPU_MAX
; i
++) sid
[i
] = 0;
// check which vcpus need debug tracing
CpuSet
& cpu_set
= cpu_option
.get_value();
for (CpuSet::iterator i
=cpu_set
.begin(); i
!= cpu_set
.end(); ++i
)
Vcpu
* vcpu
= g_vcpu
[cpu_id
];
ui
->error("cpu[%d] is not available\n", cpu_id
);
return print_vdebug_usage();
if (SYSTEM_get_ncpu() > SYSTEM_get_cpus_per_thread())
// check if specified cpu's belong to the same worker thread
int vid
= 0; // get a "sequential id"
for ( ;vid
< g_nvcpu
; vid
++)
if (get_vcpu(vid
) == vcpu
)
// check worker thread id
int tid
= vid
/ SYSTEM_get_cpus_per_thread();
if (tprev
< 0 ) tprev
= tid
;
else if ( tprev
!= tid
) separate_files
= true;
// set a flag to enable tracer for this cpu id
const char *file_name
= out_option
.is_on() ? out_option
.get_value().c_str() : NULL
;
return tracer_cmd ( trace_cmd_t(on
), sid
, file_name
, separate_files
);
///////////////////////////////////////////////////////
static int tlbs_ui_cmd (void*, int argc
, char **argv
)
if (ANY_RUNNING_STATE (blaze_run_state
))
ui
->error("not in stop state, use stop command first\n");
if (argc
< 2 || argc
> 3)
ui
->error("print all valid TTEs, usage: tlbs <cpuid> [<outfile>]\n");
int cpu_id
= strtol(argv
[1], NULL
, 0);
Vcpu
* vcpu
= get_vcpu(cpu_id
);
ui
->error("SAM: There is no vcpu %i instance \n", cpu_id
);
FILE* stream
= fopen (fname
, "w");
ui
->output("print tlb entries to %s\n", fname
);
vcpu
->print_tlbs(stream
);
vcpu
->print_tlbs(ui
->get_output_file());
vcpu
->print_tlbs(ui
->get_log_file());
///////////////////////////////////////////////////////
loglev_ui_cmd (void*, int argc
, char**argv
)
else if (argc
== 2 && sscanf (argv
[1], "%d", &tmp
) == 1 &&
ui
->error("usage: loglev [1|2|3] \n");
devmap_ui_cmd (void*, int argc
, char**argv
)
ui
->error("no arguments are allowed\n");
extern devRegistry
* samDevs
;
samDevs
->dump(ui
->get_log_file());
// find a vcpu pointer by cpu instance name
static Vcpu
* get_vcpu_by_name ( char *name
)
for (int i
=0; i
<g_nvcpu
; i
++)
if ( strcmp ( name
, g_vcpu
[i
]->config
.name
) == 0 )
vcpu
= g_vcpu
[i
]; // found a matching name
///////////////////////////////////////////////////
// run-python-file command
int (*py_source
)( int argc
, char** argv
);
static int run_python_file_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");
ui
->error("usage: run-python-file <file_name> \n");
// check if py module was loaded already
exec_cmd("mod load py py.so\n");
sam_py_argv
[0] = "$SAM/pfe/sam.py";
(py_source
)(1,sam_py_argv
);
ui
->fatal("internal error with python module.\n");
return (py_source
)(argc
- 1,argv
+ 1);
static int print_pselect_usage()
ui
->output("select cpu command usage:\n");
ui
->output("\tpselect\n");
ui
->output("\tpselect cpu_id\n");
int pselect_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");
CommandOptions cmd_options
;
std::vector
<std::string
> pos_args
;
bool result
= cmd_options
.parse(argc
-1, (const char**)&argv
[1], pos_args
);
ui
->error("cpu %d is currently selected\n", pselect_cpu_id
);
if (!UnsignedOption::parse_number(pos_args
[0], cpu_id
, error_msg
))
error_msg
+= "cpu number";
ui
->error("%s\n", error_msg
.c_str());
if (cpu_id
<=g_vcpu_id_max
&& g_vcpu
[cpu_id
])
ui
->error("No cpu matching cpu number: %lld\n", cpu_id
);
ui
->error("pselect command parsing failed: %s\n", cmd_options
.get_error_msg().c_str());
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
class TranslateOptions
: public CommandOptions
TranslateOptions( int cpu_id
)
cpu(cpu_id
,CpuOption::MULTITUDE
),
addressing(AddressingOptions::VA
)
AddressingOptions addressing
;
// We need to get this from the Options class
// CommandOptions::usage('translate');
int translate_ui_cmd( void*, int argc
, char** argv
)
static const char* cmd
= "translate";
if (!IN_STOP_STATE (blaze_run_state
))
ui
->error("not in stop state, use stop command first\n");
TranslateOptions
options(pselect_cpu_id
);
std::vector
<std::string
> args
;
if (!options
.parse(argc
-1,(const char**)&argv
[1],args
))
ui
->error("%s command parsing failed: %s\n",cmd
,options
.get_error_msg().c_str());
ui
->error("%s requires 1 positional argument; the address to translate.\n",cmd
);
Vcpu::TranslateMode mode
= options
.addressing
.translate_mode();
uint64_t ctx
= options
.addressing
.context_id
.get_value();
uint64_t pid
= options
.addressing
.partition_id
.get_value();
uint64_t ea
= strtoull(args
[0].c_str(), NULL
, 0);
CpuSet
& cpu_set
= options
.cpu
.get_value();
for (CpuSet::iterator i
=cpu_set
.begin(); i
!= cpu_set
.end(); ++i
)
ui
->output("%d: ",cpu_id
);
Vcpu
* vcpu
= g_vcpu
[cpu_id
];
ui
->output("not available\n");
else if (vcpu
->translate(mode
,ea
,ctx
,pid
,&pa
) != Vcpu::TRANSLATE_OK
)
ui
->output("no mapping available\n");
ui
->output("pa = 0x%llx\n",pa
);
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
class GetOptions
: public CommandOptions
addressing(AddressingOptions::PA
),
AddressingOptions addressing
;
// We need to get this from the Options class
// CommandOptions::usage('get');
int get_ui_cmd( void*, int argc
, char** argv
)
static const char* cmd
= "get";
if (!IN_STOP_STATE (blaze_run_state
))
ui
->error("not in stop state, use stop command first\n");
GetOptions
options(pselect_cpu_id
);
std::vector
<std::string
> args
;
if (!options
.parse(argc
-1,(const char**)&argv
[1],args
))
ui
->error("%s command parsing failed: %s\n",cmd
,options
.get_error_msg().c_str());
if (options
.size
.is_on())
ui
->error("%s used with confusing arguments: both positional "
"size argument and -size option given: use -size and -count.\n",cmd
);
if (options
.count
.is_on())
ui
->error("%s used with confusing arguments: both positional "
"size argument and -count option given: use -size and -count.\n",cmd
);
ui
->warning("%s use -size and -count options as [size] positional "
"argument is deprecated.\n",cmd
);
size
= strtoull(args
[1].c_str(),NULL
,0);
count
= (size
> 8) ? ((size
+ 7) / 8) : 1;
size
= options
.size
.get_value();
count
= options
.count
.get_value();
ui
->error("%s requires address positional argument.\n",cmd
);
if ((size
== 0) || ((size
!= 1) && (size
!= 2) && (size
!= 4) && (size
!= 8)))
if (options
.size
.is_on() || (size
< 8))
ui
->error("%s requires size to be 1, 2, 4, or 8.\n",cmd
);
ui
->warning("%s rounded size up to nearest multiple of 8.\n",cmd
);
Vcpu::TranslateMode mode
= options
.addressing
.translate_mode();
uint64_t ctx
= options
.addressing
.context_id
.get_value();
uint64_t pid
= options
.addressing
.partition_id
.get_value();
uint64_t ea
= strtoull(args
[0].c_str(),NULL
,0);
uint32_t cpu_id
= *options
.cpu
.get_value().find(0);
Vcpu
* vcpu
= g_vcpu
[cpu_id
];
ui
->error("cpu %d not available\n",cpu_id
);
else if (vcpu
->translate(mode
,ea
,ctx
,pid
,&pa
) != Vcpu::TRANSLATE_OK
)
ui
->warning("cpu %d has no mapping available for 0x%llx\n",cpu_id
,ea
);
for (n
= 0; count
--; ++n
, ea
+= size
, pa
+= size
)
if (((ea
& 0x1fff) == 0) // At the begin of every 8KByte page
&& vcpu
->translate(mode
,ea
,ctx
,pid
,&pa
) != Vcpu::TRANSLATE_OK
)
ui
->warning("cpu %d has no mapping available for 0x%llx\n",cpu_id
,ea
);
if ((n
% (32 / size
)) == 0)
ui
->output("0x%016llx: ",pa
);
mmi_memread(pa
,(uint8_t*)&data8
,1);
ui
->output("0x%02llx ",data8
);
mmi_memread(pa
,(uint8_t*)&data16
,2);
ui
->output("0x%04llx ",data16
);
mmi_memread(pa
,(uint8_t*)&data32
,4);
ui
->output("0x%08llx ",data32
);
mmi_memread(pa
,(uint8_t*)&data64
,8);
ui
->output("0x%016llx ",data64
);
if (((n
+ 1) % (32 / size
)) == 0)
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
class SetOptions
: public CommandOptions
addressing(AddressingOptions::PA
),
AddressingOptions addressing
;
// We need to get this from the Options class
// CommandOptions::usage('set');
int set_ui_cmd( void*, int argc
, char** argv
)
static const char* cmd
= "set";
if (!IN_STOP_STATE (blaze_run_state
))
ui
->error("not in stop state, use stop command first\n");
SetOptions
options(pselect_cpu_id
);
std::vector
<std::string
> args
;
if (!options
.parse(argc
-1,(const char**)&argv
[1],args
))
ui
->error("%s command parsing failed: %s\n",cmd
,options
.get_error_msg().c_str());
if (options
.size
.is_on())
ui
->error("%s used with confusing arguments: both positional "
"size argument and -size option given: use -size and -count.\n",cmd
);
if (options
.count
.is_on())
ui
->error("%s used with confusing arguments: both positional "
"size argument and -count option given: use -size and -count.\n",cmd
);
ui
->warning("%s use -size and -count options as [size] positional "
"argument is deprecated.\n",cmd
);
size
= strtoull(args
[2].c_str(),NULL
,0);
count
= (size
> 8) ? ((size
+ 7) / 8) : 1;
size
= options
.size
.get_value();
count
= options
.count
.get_value();
ui
->error("%s requires address [size] positional arguments.\n",cmd
);
if ((size
== 0) || ((size
!= 1) && (size
!= 2) && (size
!= 4) && (size
!= 8)))
if (options
.size
.is_on() || (size
< 8))
ui
->error("%s requires size to be 1, 2, 4, or 8.\n",cmd
);
ui
->warning("%s rounded size up to nearest multiple of 8.\n",cmd
);
Vcpu::TranslateMode mode
= options
.addressing
.translate_mode();
uint64_t ctx
= options
.addressing
.context_id
.get_value();
uint64_t pid
= options
.addressing
.partition_id
.get_value();
uint64_t ea
= strtoull(args
[0].c_str(),NULL
,0);
uint32_t cpu_id
= *options
.cpu
.get_value().find(0);
Vcpu
* vcpu
= g_vcpu
[cpu_id
];
ui
->error("cpu %d not available\n",cpu_id
);
else if (vcpu
->translate(mode
,ea
,ctx
,pid
,&pa
) != Vcpu::TRANSLATE_OK
)
ui
->output("cpu %d has no mapping available for 0x%llx\n",cpu_id
,ea
);
uint64_t data64
= strtoull(args
[1].c_str(),NULL
,0);
uint32_t data32
= data64
;
uint16_t data16
= data64
;
for (uint_t n
= 0; count
--; ++n
, ea
+= size
, pa
+= size
)
if (((ea
& 0x1fff) == 0) // At the begin of every 8KByte page
&& vcpu
->translate(mode
,ea
,ctx
,pid
,&pa
) != Vcpu::TRANSLATE_OK
)
ui
->output("cpu %d has no mapping available for 0x%llx\n",cpu_id
,ea
);
case 1: mmi_memwrite(pa
,(uint8_t*)&data8
, 1); break;
case 2: mmi_memwrite(pa
,(uint8_t*)&data16
,2); break;
case 4: mmi_memwrite(pa
,(uint8_t*)&data32
,4); break;
case 8: mmi_memwrite(pa
,(uint8_t*)&data64
,8); break;
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
class DisassembleOptions
: public CommandOptions
DisassembleOptions( int cpu_id
)
addressing(AddressingOptions::VA
),
AddressingOptions addressing
;
// We need to get this from the Options class
// CommandOptions::usage('disassemble');
int disassemble_ui_cmd( void*, int argc
, char** argv
)
static const char* cmd
= "disassemble";
if (!IN_STOP_STATE (blaze_run_state
))
ui
->error("not in stop state, use stop command first\n");
DisassembleOptions
options(pselect_cpu_id
);
std::vector
<std::string
> args
;
if (!options
.parse(argc
-1,(const char**)&argv
[1],args
))
ui
->error("%s command parsing failed: %s\n",cmd
,options
.get_error_msg().c_str());
uint32_t cpu_id
= *options
.cpu
.get_value().begin();
Vcpu
* vcpu
= g_vcpu
[cpu_id
];
ui
->error("cpu %d not available\n",cpu_id
);
if (options
.count
.is_on())
ui
->error("%s used with confusing arguments: both positional "
"count argument and -count option given: use -count.\n",cmd
);
ui
->warning("%s use -count option as [count] positional "
"argument is deprecated.\n",cmd
);
ea
= strtoull(args
[0].c_str(),NULL
,0);
count
= strtoull(args
[1].c_str(),NULL
,0);
ea
= strtoull(args
[0].c_str(),NULL
,0);
count
= options
.count
.get_value();
vcpu
->get_reg(VCPU_ASR_PC
,&ea
);
count
= options
.count
.get_value();
ui
->error("%s requires address positional arguments.\n",cmd
);
Vcpu::TranslateMode mode
= options
.addressing
.translate_mode();
uint64_t ctx
= options
.addressing
.context_id
.get_value();
uint64_t pid
= options
.addressing
.partition_id
.get_value();
ui
->warning("%s likes the address argument to be 4 byte aligned\n",cmd
);
if (vcpu
->translate(mode
,ea
,ctx
,pid
,&pa
) != Vcpu::TRANSLATE_OK
)
ui
->error("cpu %d has no mapping available for 0x%llx\n",cpu_id
,ea
);
for (; count
--; ea
+= 4, pa
+= 4)
if (((ea
& 0x1fff) == 0) // At the begin of every 8KByte page
&& vcpu
->translate(mode
,ea
,ctx
,pid
,&pa
) != Vcpu::TRANSLATE_OK
)
ui
->output("cpu %d has no mapping available for 0x%llx\n",cpu_id
,ea
);
mmi_memread(pa
,(uint8_t*)&data
,4);
spix_sparc_dis(inst
,256,spix_sparc_iop(SPIX_SPARC_V9
,&data
),&data
,ea
);
ui
->output("%d: %llx %llx [%08x] %s\n",cpu_id
,ea
,pa
,data
,inst
);
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
class ReadAsiOptions
: public CommandOptions
ReadAsiOptions( int cpu_id
)
// We need to get this from the Options class
// CommandOptions::usage('disassemble');
int read_asi_ui_cmd( void*, int argc
, char** argv
)
static const char* cmd
= "read-asi";
if (!IN_STOP_STATE (blaze_run_state
))
ui
->error("not in stop state, use stop command first\n");
ReadAsiOptions
options(pselect_cpu_id
);
std::vector
<std::string
> args
;
if (!options
.parse(argc
-1,(const char**)&argv
[1],args
))
ui
->error("%s command parsing failed: %s\n",cmd
,options
.get_error_msg().c_str());
ui
->error("%s requires <asi> <address> positional arguments.\n",cmd
);
uint64_t asi
= strtoull(args
[0].c_str(),NULL
,0);
int64_t va
= strtoll(args
[1].c_str(),NULL
,0); // va is signed
uint32_t cpu_id
= *options
.cpu
.get_value().begin();
ui
->error("valid non-translating asi values range from 0 to 0xff\n",cmd
);
ui
->warning("%s requires the address argument to be 8 byte aligned\n",cmd
);
Vcpu
* vcpu
= g_vcpu
[cpu_id
];
ui
->error("cpu %d not available\n",cpu_id
);
int fail
= vcpu
->get_asi(asi
,va
,data
);
ui
->error("0x%02llx:0x%llx is not a valid non-translating asi:va pair\n",asi
,va
);
ui
->output("0x%02llx:0x%llx = 0x%llx\n",asi
,va
,data
);
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
class WriteAsiOptions
: public CommandOptions
WriteAsiOptions( int cpu_id
)
// We need to get this from the Options class
// CommandOptions::usage('disassemble');
int write_asi_ui_cmd( void*, int argc
, char** argv
)
static const char* cmd
= "write-asi";
if (!IN_STOP_STATE (blaze_run_state
))
ui
->error("not in stop state, use stop command first\n");
WriteAsiOptions
options(pselect_cpu_id
);
std::vector
<std::string
> args
;
if (!options
.parse(argc
-1,(const char**)&argv
[1],args
))
ui
->error("%s command parsing failed: %s\n",cmd
,options
.get_error_msg().c_str());
ui
->error("%s requires <asi> <address> <value> positional arguments.\n",cmd
);
uint64_t asi
= strtoull(args
[0].c_str(),NULL
,0);
int64_t va
= strtoll(args
[1].c_str(),NULL
,0); // va is signed
uint64_t data
= strtoull(args
[2].c_str(),NULL
,0);
uint32_t cpu_id
= *options
.cpu
.get_value().begin();
ui
->error("valid non-translating asi values range from 0 to 0xff\n",cmd
);
ui
->warning("%s requires the address argument to be 8 byte aligned\n",cmd
);
Vcpu
* vcpu
= g_vcpu
[cpu_id
];
ui
->error("cpu %d not available\n",cpu_id
);
int fail
= vcpu
->set_asi(asi
,va
,data
);
ui
->error("0x%02llx:0x%llx is not a valid non-translating asi:va pair\n",asi
,va
);
///////////////////////////////////////////////
int static echo_ui_cmd (void*, int argc
, char **argv
)
for (int i
= 1; i
< argc
; ++i
)
const char* arg
= argv
[i
];
if (len
> 2 && arg
[len
-1] == '"')
ui
->output("%.*s ", len
-2, &arg
[1]);
///////////////////////////////////////////////
int static list_breakpoints_ui_cmd (void*, int argc
, char **argv
)
// printout all existing breakpoints
for (int i
=0; i
<=g_vcpu_id_max
; i
++)
g_vcpu
[i
]->print_breakpoints(ui
->get_output_file());
g_vcpu
[i
]->print_breakpoints(ui
->get_log_file());