Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / ui_cmds.cc
// ========== 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 ============================================
/* icq
SELECT - input multiplexing
DONE - done replies to the sync-server
*/
/*
* Copyright (C) 1996, 2001, 2005 Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%%1.119 07/01/09 %%"
// "ui_cmds.cc"
//
// handles UI input multiplexing (stdin, sync socket, back door, script file)
// and command parsing, lookup, and calling of registered function for command
//
//
// public functions:
//
// 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
//
//
// public variables:
// -- none !!! --
//
// extraneous junk:
//
// send_diskinfo_to_fakeprom called from scsi_ctrl, fc_ctrl. Yeuch!
//
/* standard C includes */
#include <stdio.h>
#include <thread.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
/* solaris includes */
#include <signal.h>
#include <sys/types.h>
#include <sys/exec.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/procfs.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <stropts.h>
#include <dlfcn.h>
/* project includes */
#include "mmi.h"
// FlexConfig: needs this
#include "serial_mod.h"
#include "ui.h"
#include "types.h"
#include "blaze_globals.h"
#include "system.h"
#include "mem.h"
typedef void* TM_OPAQUE_DATA;
#include "tracemod.h"
#include "ui_utils.h"
#include "sim_cmd_struct.h"
#include "ui_cmds.h"
#include "blaze_globals.h"
#include "ui_cmd_struct.h"
#include "ui_cmds.h"
#include "ui_elfsym.h"
#include "blz_runtime.h"
#include "macrolib.h"
#include "netsim.h"
#include "cpu_interface.h"
#include "stracer.h"
#include "workerthread.h"
#include "command_opts.h"
#include "spix_sparc.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;
char bootpath[256];
// global cpu_id set by pselect command
int pselect_cpu_id = 0;
extern int eventque_ui_cmds (void*, int argc, char **argv);
// ============================================================================
//
// public data
//
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 */
// ============================================================================
//
// private functions
//
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 ===================================
Ui_cmd ui_cmd_list [] =
{
{"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},
#ifdef V5_FAKEPROM
{"console-send", "console-send <string> \n",FUI_STRING, cs_ui_cmd, NULL, NULL},
#endif
{"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 *);
Py_Intf_fn addPycmd = 0;
Py_Intf_fn delPycmd = 0;
bool python_UI = false;
/////////////////////////////////////////////////
//
//
//
void linkup (Ui_cmd * pc)
{
int i;
if (!plast) {
for (i = 0; i < (sizeof(ui_cmd_list) / sizeof(Ui_cmd)) - 1; i++) {
ui_cmd_list[i].next = &ui_cmd_list[i+1];
}
plast = &ui_cmd_list[i];
}
plast->next = pc;
plast = pc;
}
/////////////////////////////////////////////////
void preinit_ui ()
{
int i;
if (!plast) {
for (i = 0; i < (sizeof(ui_cmd_list) / sizeof(Ui_cmd)) - 1; i++) {
ui_cmd_list[i].next = &ui_cmd_list[i+1];
}
plast = &ui_cmd_list[i];
}
}
///////////////////////////////////////////////
//
// 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));
if (pcmd == NULL) {
ui->error("UI_register can not malloc\n");
return;
}
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 */
pcmd->alias_argc = 1;
linkup (pcmd);
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));
if (pcmd == NULL) {
ui->error("UI_register can not malloc\n");
return;
}
pcmd->name = (char*) strdup(name);
pcmd->help = (char*) strdup(help);
pcmd->cmd_exe_func = efn;
pcmd->cmd_help_func = hfn;
pcmd->flags = 0; /* _2 */
pcmd->alias_argc = 1;
linkup (pcmd);
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));
if (pcmd == NULL) {
ui->error("UI_register can not malloc\n");
return;
}
pcmd->name = (char*) strdup(name);
pcmd->help = (char*) strdup(help);
pcmd->cmd_exe_func = efn;
pcmd->cmd_help_func = hfn;
pcmd->flags = flags; /* _3 */
pcmd->alias_argc = 1;
linkup (pcmd);
if(addPycmd) (*addPycmd)(name);
}
///////////////////////////////////////////////
//
// this command un-registers a UI command
//
void UI_invalidate_cmd (char *name)
{
Ui_cmd *pcmd;
bool_t done = FALSE;
for (pcmd = &ui_cmd_list[0]; pcmd;pcmd = pcmd->next) {
if (strcmp(pcmd->name, name) == NULL) {
pcmd->flags |= FUI_INVALID;
done = TRUE;
}
}
if (done == FALSE)
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)
{
char * s = sss;
int n = 0;
while (1) {
if (read (fd, sss, 1) != 1)
return 0; // convention for closed socket
++n;
if (*sss == '\n') {
*++sss = '\0';
return n;
}
if (*sss == '\0')
return n;
++sss;
if (n>= max_cmd_length) {
ui->error("UI command too long (limit %d characters)\n", max_cmd_length);
*s = 0;
return 0;
}
}
}
sint64_t perf_ui_interval = 0, // all in "hrtime" units of nanosecs
perf_ui_start = 0,
next_perf_ui_time = 0,
perf_now = 0,
perf_tmp = 0,
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
// perf command
extern "C" void * ui_sync_thread (void *arg)
{
char sss[max_cmd_length];
fd_set read_set;
int selrc;
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);
for (;;) {
FD_ZERO (&read_set);
FD_SET (fake_fd,&read_set);
if (sync_fd >= 0) {
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());
if (tmp > 0) {
timeout.tv_sec = tmp / 1000000000;
timeout.tv_usec = (tmp - 1000000000 * timeout.tv_sec) / 1000;
} else {
timeout.tv_sec = timeout.tv_usec = 0;
}
tvp = &timeout;
} else
tvp = NULL;
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;
}
if (selrc < 0) {
/* @@@ what about EINTR (for keyboard ctrl-C ?) */
ui->perror ("ui select: ");
}
if (sync_fd >= 0 && FD_ISSET (sync_fd, &read_set)) { /*SYNC*/
sss[0] = '\0';
if (fdgets(sss, sync_fd)) {
if (sync_on) {
if (strncmp (sss, "stept ", 6) == 0) {
UI_exec_cmd (sss);
} else {
ui->error("###sync cmd \"%s\", ignored.\n", sss);
}
} else {
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)) {
UI_exec_cmd ("stop\n");
}
}
}
}
return NULL;
}
////////////////////////////////////////////////////////
//
// read user command input
//
void ui_readline ()
{
while(1)
{
char *line, *help; // read line buffer
const char* prompt = "sam: ";
switch (blaze_run_state)
{
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.
ui->input(prompt);
ui->flush();
line = readline(prompt);
if (line)
{
ui->input(line);
ui->input("\n");
UI_exec_cmd(line);
// Only add non blank lines to the history.
for (help = line; *help && isspace(*help); ++help)
;
if (*help)
add_history(line);
free(line);
}
else
break; // eof hit, exit
}
if (IN_RUN_STATE (blaze_run_state))
UI_exec_cmd("stop\n");
SYSTEM_quit_UI ();
}
// ============================ 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)) ==
(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;
int argc = 16;
bool quoted = false;
Ui_cmd *pcmd = NULL;
AGAIN:
ps = s_cmd;
while (isspace(*ps)) {
++ps;
}
if ((*ps == '\0') || (*ps == '#'))
return 0;
//check if the cmd is well double-quoted.
if (ps1 = strchr(ps, '"')) {
int count = 0;
bool appear = false;
while ( *ps1 != '\0' ) {
//only when '"' is not escaped by '\', it will be regarded as a valid double-quoted sign.
if (((*ps1 == '"') && ((*(ps1-1) != '\\')) || (ps1 == ps))) {
count++;
}
if (*ps1 == '#') {
appear = true;
}
ps1++;
}
//when the number of valid double-quoted sign is even, the cmd is well quoted.
if ((!(count%2))&&appear) {
quoted = true;
}
}
//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 (!quoted) {
if (ps2 = strchr(ps, '#')) {
*ps2 = '\0';
}
}
if ( strcmp(ps, "!!") == NULL )
{
strcpy(s_cmd, lastCommand);
goto AGAIN;
}
else
{
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);
if (argv == NULL) {
ui->error("cmd format error <%s>", ps);
return 1;
}
bool saw_alias = false;
retry:
for (pcmd = &ui_cmd_list[0]; pcmd;pcmd = pcmd->next) {
if (pcmd->flags & FUI_INVALID)
continue;
if (strcmp(argv[0], pcmd->name) == NULL) {
if (pcmd->flags & FUI_ALIAS) {
int new_argc = argc + pcmd->alias_argc - 1;
free(argv[0]);
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)
{
char *p = argv[ndx];
argv[ndx] = strdup(p);
if (argv[ndx] == NULL) {
ui->error("cannot strdup <%s>", p);
return 1;
}
}
argc = new_argc;
pcmd->flags |= FUI_INVALID;
saw_alias = true;
goto retry;
}
if (pcmd->flags & FUI_STRING) {
char *pw0;
char *str = ui_parsew(s_cmd, &pw0);
argc = 2;
argv[1] = (char*) strdup (str);
}
if (pcmd->cmd_exe_func) { /*******/
if (saw_alias)
clear_invalid_aliases();
int rv = (pcmd->cmd_exe_func (NULL, argc, argv)); /*DO IT*/
ui_argv_free(argc, argv);
return rv;
} /*******/
}
}
if (saw_alias)
clear_invalid_aliases();
ui_argv_free(argc, argv);
ui->error("unknown command <%s>\n", ps);
return 1;
}
//==============================================================================
// ====================== locally implemented ui functions ====================
/////////////////////////////////////////////
//
// RUN
//
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");
return 1;
}
if (argc != 1) {
ui->output("usage: run\nUse stepi <instruction count> to single step\n");
return 1;
}
SYSTEM_run_UI (); /* kicks off async running of cpu-sim threads */
return 1;
}
///////////////////////////////////////////////
//
// STOP
//
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...
SYSTEM_stop_UI ();
return 1;
}
////////////////////////////////////////////
//
// STEPI <ninstrs>
//
// 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)
{
int64_t ni = 1;
if (SYSTEM_in_execution_driven_mode()) {
ui->error("cannot do stepi in exec-driven mode\n");
return 1;
}
if (!IN_STOP_STATE (blaze_run_state)) {
ui->error("not in stop state\n");
return 1;
}
if ((argc > 1) && isdigit(argv[1][0]))
{
sscanf(argv[1], "%lli", &ni);
ni = strtoll(argv[1], NULL, 0);
if (ni == 0 ) ni = 1;
}
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");
return 1;
}
else if(strcmp(argv[i], "?")==0)
{
ui->output("usage: stepi [<ninstr>]\n");
return 1;
}
}
SYSTEM_stepi_UI (ni);
return 0;
}
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");
return 1;
}
if (!IN_STOP_STATE(blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 1;
}
int64_t nc=1;
int i = 1;
while(i<argc) {
if (argv[i][0] == '?') {
ui->output("usage: stepc [<ncycles>]\n");
return 1;
} else {
errno = 0;
nc = strtoll(argv[i], NULL, 0);
if (errno) {
ui->error("invalid argument %s\n", argv[i]);
return 1;
}
i++;
if (!nc) nc = 1;
}
}
SYSTEM_stepc_UI(nc);
return 0;
}
///////////////////////////////////////////////
//
// STEPIM <ninstrs>
//
int stepim_ui_cmd (void*, int argc, char **argv)
{
int64_t ni = 1;
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);
}
return 0;
}
///////////////////////////////////////////////////
//
// 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 */
extern "C" {
static void stept_done_callback (void * x)
{
int res;
char buf[max_cmd_length];
if (sync_fd != -1 && sync_on) {
if (stept_seqnum != -1) {
sprintf (buf, "done %lld\n", stept_seqnum);
} else {
sprintf (buf, "done\n");
}
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");
return 1;
}
if (argc > 1) sscanf(argv[1], "%lli", &stept_usecs);
if (argc > 2) sscanf(argv[2], "%lli", &stept_seqnum);
else stept_seqnum = -1;
if (SYNCDEBUG)
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);
return 0;
}
/////////////////////////////////////////////
//
// RESUME
//
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");
return 1;
}
if (sync_on) {
SYSTEM_syncon_UI ();
} else {
SYSTEM_run_UI ();
}
return 0;
}
///////////////////////////////////////////////
//
// QUIT
//
static int quit_ui_cmd (void*, int argc, char **argv)
{
if (IN_RUN_STATE (blaze_run_state))
stop_ui_cmd (NULL, 0, NULL);
SYSTEM_quit_UI ();
return 0;
}
///////////////////////////////////////////////
//
// 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)
{
char *filename;
uint64_t base_pa, addr, size, seg_size;
uint64_t base_va;
int ret, zero_pad = 0, create_lbl = 0;
bool_t load_image = FALSE;
if (mm1 == NULL)
{
ui->error("RAM object is not ready yet!\n");
return 1;
}
if (BLAZE_restore_from_checkpoint())
{
// don't load the image again, it should be in mem dump already
if (argc>=2)
ui->error("<%s> image should be already in memory \n", argv[2]);
return 1;
}
if ((argc == 3) && (strcmp(argv[1], "image") == NULL))
{
load_image = TRUE;
if (mm1->load(argv[2]) !=0 )
{
ui->error("Error in <%s> memory image\n ", argv[2]);
return 1;
}
else
{
return 1;
}
}
// 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]);
return 1;
}
return 1;
}
if (argc < 4) {
ui->error("check LOAD command format\n");
return 1;
}
ret = sscanf (argv[1], "%lli", &base_pa);
if (ret != 1) {
ui->error("check PA arg <%s>\n", argv[1]);
return 1;
}
ret = sscanf (argv[3], "%lli", &base_va);
if (ret != 1) {
ui->error("check VA arg <%s>\n", argv[3]);
return 1;
}
filename = (char*)malloc (strlen(argv[2]) + 16);
sscanf (argv[2], "%s", filename);
load_elf64(filename, base_pa, base_va);
return 1;
}
///////////////////////////////////////////////
//
// FILE <filename>
//
static int file_ui_cmd (void*, int argc, char **argv)
{
if (argc != 2) {
ui->error("UI (file): format error");
return 1;
}
FILE* fp = fopen(argv[1],"r");
if (!fp) {
ui->error("Can't open <%s>", argv[1]);
return 1;
}
char line[max_cmd_length];
while (fgets(line,max_cmd_length,fp))
exec_cmd(line);
fclose(fp);
return 0;
}
///////////////////////////////////////////////
//
// CONF <name> <value>
//
//
extern void complete_cfg ();
extern uint8_t get_platform_index (char *s);
static void print_new_cpi ()
{
if (g_vcpu[0] != NULL)
{
for (int i=0; i<=g_vcpu_id_max; i++)
{
Vcpu *vcpu = get_vcpu(i);
if (!vcpu)
continue;
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)
{
uint8_t idx_to_plist;
char s[max_cmd_length];
uint64_t pa;
char *default_s = (char*)"sun4u";
static bool numcores_initialized = FALSE;
static bool numcpus_initialized = FALSE;
if (argc == 1)
{
if (the_arch.cmp_mode) {
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);
#endif
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);
else
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)
{
if (argc == 2)
{
ui->output ("ramsize: 0x%llx bytes (%lld MB) \n",
the_arch.ramsize, the_arch.ramsize >> 20);
return 1;
}
char *mfile_name = NULL;
if (argc > 2)
{
char *p;
uint64_t lval = strtoll (argv[2], &p, 0);
if (*p == 'K')
lval <<= 10;
if (*p == 'M')
lval <<= 20;
the_arch.ramsize = lval;
the_arch.ramsizeS = (char*)strdup(argv[2]);
}
if ((argc > 3) && !BLAZE_restore_from_checkpoint())
{
mfile_name = argv[3];
}
// mem object is global for entire system
if (mm1)
{
ui->error("RAM object is already created !!");
return 0;
}
else
{
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 );
quit_simulation();
}
if (!BLAZE_restore_from_checkpoint())
{
pa = 0x1c;
LO_W(pa) &= ~7;
#ifdef V5_FAKEPROM
memwrite64s_nl(mm1, pa, the_arch.ramsize);
#endif
}
the_arch.arch_flags |= FA_RAMSIZE;
// TO DO: why do we need these flags?
the_arch.arch_flags |= FA_STICKINCR|FA_TLBSIZE|FA_PLATFORM;
}
#ifdef MEMORY_SEGMENTED
else if (strcmp (argv[1], "memseg") == NULL)
{
assert(argc >= 5 && argc <= 6);
char *mfile_name = NULL;
const char * name = argv[2];
uint64_t base = strtoll(argv[3],0,0);
uint64_t size;
{
char *p;
char q[128];
size = strtoll (argv[4], &p, 0);
if (*p == 'K')
size <<= 10;
if (*p == 'M')
size <<= 20;
the_arch.ramsize += size;
the_arch.ramsizeS = strdup(ulltostr(the_arch.ramsize,q));
}
if ((argc > 5) && !BLAZE_restore_from_checkpoint())
{
mfile_name = argv[5];
}
if(!mm1)
mm1 = new SMemory ();
if (!mm1->addMem(name,base,size,mfile_name) )
{
ui->error("memseg: cannot allocate mem object size of %llx\n",size );
quit_simulation();
}
if (!BLAZE_restore_from_checkpoint())
{
pa = 0x1c;
LO_W(pa) &= ~7;
#ifdef V5_FAKEPROM
memwrite64s_nl(mm1, pa, the_arch.ramsize);
#endif
}
the_arch.arch_flags |= FA_RAMSIZE;
// TO DO: why do we need these flags?
the_arch.arch_flags |= FA_STICKINCR|FA_TLBSIZE|FA_PLATFORM;
}
#endif
else if (strcmp(argv[1], "mips") == 0)
{
if (argc > 2) {
sscanf (argv[2], "%lld", &the_arch.mips);
the_arch.kmips = the_arch.mips;
the_arch.umips = the_arch.mips;
}
else {
if (the_arch.umips == the_arch.kmips)
ui->output("mips: %lld\n\n", the_arch.umips);
else
ui->output("kmips: %lld, umips: %lld\n\n",
the_arch.kmips, the_arch.umips);
}
}
else if (strcmp(argv[1], "kmips") == 0)
{
if (argc > 2)
sscanf (argv[2], "%lld", &the_arch.kmips);
ui->output("conf kmips = %lld\n", the_arch.kmips);
}
else if (strcmp(argv[1], "umips") == 0)
{
if (argc > 2)
sscanf (argv[2], "%lld", &the_arch.umips);
ui->output("conf umips = %lld\n", the_arch.umips);
}
else if (strcmp(argv[1], "cmips") == 0)
{
if (argc > 2)
sscanf (argv[2], "%lld", &the_arch_cmips);
if (argc > 3)
sscanf (argv[3], "%d", &the_arch_ccntx);
if (the_arch_ccntx)
ui->output("conf cmips = %lld for context %d\n",
the_arch_cmips, the_arch_ccntx);
else
ui->output("conf cmips is ineffective when context is zero\n");
}
else if (strcmp (argv[1], "cpu_per_thread") == 0)
{
if (argc > 2) {
sscanf (argv[2], "%d", &the_arch.cpus_per_thread);
cpu_enable_changed = true;
if (g_nvcpu)
the_arch.numthreads = g_nvcpu / the_arch.cpus_per_thread;
}
if (g_nvcpu) {
ui->output ("conf cpu_per_thread = %d (numthreads = %d)\n",
the_arch.cpus_per_thread, the_arch.numthreads);
} else
ui->output ("conf cpu_per_thread = %d\n", the_arch.cpus_per_thread);
}
else if (strcmp (argv[1], "numthreads") == 0)
{
if (argc > 2) {
sscanf (argv[2], "%d", &the_arch.numthreads);
cpu_enable_changed = true;
if (g_nvcpu)
the_arch.cpus_per_thread = g_nvcpu / the_arch.numthreads;
}
if (g_nvcpu) {
ui->output ("conf numthreads = %d (cpu_per_thread = %d)\n",
the_arch.numthreads, the_arch.cpus_per_thread);
} else
ui->output ("conf numthreads = %d\n", the_arch.numthreads);
}
else if (strcmp (argv[1], "roundrobin") == 0)
{
if (argc > 2)
sscanf (argv[2], "%d", &the_arch.roundrobin);
ui->output ("conf roundrobin = %d\n", the_arch.roundrobin);
}
else if (argc == 4)
{
uint32_t id, ret;
double fv;
float ffv;
#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] );
if (vcpu != NULL)
{
int temp;
sscanf (argv[2], "%i", &temp);
if (temp >= vcpu->config.stickincr)
{
vcpu->config.loopticks = temp;
print_new_cpi ();
}
else
{
ui->error("Ignored: loopticks >= stickincr, limitation\n");
}
}
else
{
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] );
if (vcpu != NULL)
{
int temp;
sscanf (argv[2], "%i", &temp );
vcpu->config.stickincr = temp;
print_new_cpi ();
}
else
{
ui->error("Ignored: unknow cpu instance. \n");
}
}
else if (strcmp(argv[1], "cpi") == NULL)
{
// conf cpi N xx.xx
ui->error("SAM-GTSync doesn't support cpi feature \n");
if (g_vcpu[0] == NULL)
{
ui->error("conf cpi: move this line to be after cpu is created.\n");
exit (1);
}
ret = sscanf (argv[2], "%i", &id);
if ( (ret != 1) )
{
ui->error("wrong cpu id argument <%s>\n", argv[2]);
return 0;
}
Vcpu * vcpu = get_vcpu(id);
if(!vcpu){
ui->error("wrong cpu id argument <%s>\n", argv[2]);
return 0;
}
ret = sscanf (argv[3], "%f", &ffv);
fv = ffv;
if (ret != 1)
{
ui->error("wrong cpi argument <%s>\n", argv[3]);
return 0;
}
ui->output("cpu%d cpi=%f \n", id, fv);
vcpu->config.cpi = fv;
the_arch.cpi = TRUE;
}
else
{
ui->error("Ignored: wrong parameter\n");
}
#endif
}
else if (argc == 3)
{
// 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
// LOAD fakeprom ufsboot
// 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]);
exit(1);
}
the_arch.cmp_mode = true;
if (numcpus_initialized)
{
the_arch.cpus_per_core = the_arch.numcpus/the_arch.numcores;
// assume divisible
if (the_arch.numcpus % the_arch.numcores)
{
ui->error("numcpus %d not divisible by numcores %d\n", the_arch.numcpus, the_arch.numcores);
exit(1);
}
}
numcores_initialized = TRUE;
}
else if (strcmp (argv[1], "numcpu") == NULL)
{
sscanf (argv[2], "%i", &the_arch.numcpus);
pa = 0x14;
LO_W(pa) &= ~3;
#ifdef V5_FAKEPROM
memwrite32u_nl(mm1, pa, the_arch.numcpus);
#endif
the_arch.arch_flags |= FA_NCPU;
if (numcores_initialized)
{
the_arch.cpus_per_core = the_arch.numcpus/the_arch.numcores;
// assume divisible
if (the_arch.numcpus % the_arch.numcores)
{
ui->error("numcpus %d not divisible by numcores %d\n", the_arch.numcpus, the_arch.numcores);
exit(1);
}
}
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");
int temp;
sscanf (argv[2], "%i", &temp);
// set loopticks for all vcpu's
if (g_vcpu[0] != NULL)
{
if (temp >= the_arch.stickincr)
{
for (int i=0; i<=g_vcpu_id_max; i++)
{
Vcpu *vcpu = get_vcpu(i);
if (!vcpu)
continue;
vcpu->config.loopticks = temp;
}
the_arch.loopticks = temp;
the_arch.loopticks_cp = the_arch.loopticks;
print_new_cpi ();
} else {
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");
int temp;
sscanf (argv[2], "%i", &temp);
// set stickincr for all vcpu's
if (g_vcpu[0] != NULL)
{
for (int i=0; i<=g_vcpu_id_max; i++)
{
Vcpu *vcpu = get_vcpu(i);
if (!vcpu)
continue;
vcpu->config.stickincr = temp;
}
the_arch.stickincr = temp;
print_new_cpi ();
}
}
#endif
else if (strcmp (argv[1], "cpufreq") == NULL)
{
if ((the_arch.arch_flags & FA_FREQ) == 0)
{
sscanf (argv[2], "%llu", &the_arch.cpu_freq);
pa = 0x24;
LO_W(pa) &= ~7;
#ifdef V5_FAKEPROM
memwrite64s_nl(mm1, pa, the_arch.cpu_freq);
#endif
the_arch.arch_flags |= FA_FREQ;
print_new_cpi ();
}
else
{
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);
pa = 0x28;
LO_W(pa) &= ~7;
#ifdef V5_FAKEPROM
memwrite64s_nl(mm1, pa, the_arch.stick_freq);
#endif
the_arch.arch_flags |= FA_SFREQ;
print_new_cpi ();
}
else
{
// 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);
if (!vcpu)
continue;
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);
}
#ifdef V5_FAKEPROM
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);
pa = 0x30;
memwrite8u_nl(mm1, pa, idx_to_plist);
the_arch.arch_flags |= FA_PLATFORM;
}
#endif
#ifdef V5_FAKEPROM
else if (strcmp (argv[1], "bootpath") == NULL)
{
strcpy (bootpath, argv[2]);
int boot_aid,boot_dev,boot_bus;
char boot_part[3];
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);
if (result != 5) {
ui->error("unknown parameter <%s> for boot path", argv[2]);
exit(1);
}
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
pa = 0x33;
memwrite8u_nl(mm1, pa, (uint8_t)boot_dev);//pci device number of scsi hba on sysconf line
pa = 0x34;
memwrite8u_nl(mm1, pa, (uint8_t)boot_target_id);//scsi disk target id, specified from scsidisk.init
pa = 0x35;
memwrite8u_nl(mm1, pa, (uint8_t)boot_part_id);//parition id of scsi disk, from scsidisk.init
pa = 0x36;
memwrite8u_nl(mm1, pa, (uint8_t)boot_disk_id);//lun of scsi disk. always 0 for our supported disks, redundant info currently
pa = 0x4a;
memwrite8u_nl(mm1, pa, (uint8_t)boot_aid);//aid of schizo, to which scsi hba connects to
pa = 0x4b;
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
}
#endif
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);
pa = 0x48;
#ifdef V5_FAKEPROM
memwrite8u_nl(mm1, pa, the_arch.numNICs);
#endif
}
else if (strcmp (argv[2], "done") == NULL)
{
if (strcmp (argv[1], "cpu") == NULL) {
ui->error("unknown parameter <%s> ", argv[1]);
return 1;
}
}
else
{
ui->error("unknown parameter <%s> ", argv[1]);
}
} /*end-if-argc*/
if (the_arch.platform == NULL)
// set the_arch.platform to sun4u as default
the_arch.platform = strdup(default_s);
return 1;
}
/*
* 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;
int64_t stIntrpts;
ui->output("\n");
// total instructions simulated, all cpus
//
Uinstrs = atomic_and_64 (& WorkerThread::u_instrs, 0);
Kinstrs = atomic_and_64 (& WorkerThread::k_instrs, 0);
instrs = Uinstrs + Kinstrs;
if (instrs == 0)
ui->output("instructions: %12d\n", 0);
else
ui->output(
"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;
if (intervals == 0)
ui->output("sync-intervals: %12d\n", 0);
else
ui->output(
"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
//
if (intervals == 0)
ui->output("effective-mips: %12d\n", 0);
else
ui->output("effective-mips: %12lld\n",
instrs / intervals);
ui->output("\n");
return 1;
}
// this function is called by:
// fc_mod.cc
// scsi_mod.cc
//
uint8_t send_diskinfo_to_fakeprom()
{
uint64_t pa;
#ifdef V5_FAKEPROM
pa = 0x31;
memwrite8u_nl(mm1, pa, (uint8_t)SYSTEM_get_scsi_disk_enable_flag()
| (uint8_t)SYSTEM_get_fc_disk_enable_flag() <<1);
pa = 0x32;
memwrite8u_nl(mm1, pa, (uint8_t)SYSTEM_get_scsi_boot_enable_flag()
| (uint8_t)SYSTEM_get_fc_boot_enable_flag() <<1);
pa = 0x49;
memwrite8u_nl(mm1, pa, (uint8_t)SYSTEM_get_ce_enable_flag());
#endif
return 0;
}
// added for platform support, to pass down to fakeprom
const char *os_platform_lists[] = { // fakeprom must have the same table
"sun4u", // default settting
"FJSV,GPUU",
"NATE,s-Note_737S",
"NATE,s-Note_747S",
"NATE,s-Note_777S",
"sun4u",
"SUNW,Netra-T12",
"SUNW,Netra-T4",
"SUNW,Sun-Blade-100",
"SUNW,Sun-Blade-1000",
"SUNW,Sun-Fire",
"SUNW,Sun-Fire-15000",
"SUNW,Sun-Fire-280R",
"SUNW,Sun-Fire-480R",
"SUNW,Sun-Fire-880",
"SUNW,Ultra-1",
"SUNW,Ultra-1-Engine",
"SUNW,Ultra-2",
"SUNW,Ultra-250",
"SUNW,Ultra-30",
"SUNW,Ultra-4",
"SUNW,Ultra-5_10",
"SUNW,Ultra-60",
"SUNW,Ultra-80",
"SUNW,UltraAX-e",
"SUNW,UltraAX-e2",
"SUNW,UltraAX-i2",
"SUNW,UltraAX-MP",
"SUNW,Ultra-Enterprise",
"SUNW,Ultra-Enterprise-10000",
"SUNW,UltraSPARCengine_CP-20",
"SUNW,UltraSPARCengine_CP-40",
"SUNW,UltraSPARCengine_CP-60",
"SUNW,Sun-Fire-V440",
"nomore", // no found
};
uint8_t get_platform_index(char *s)
{
int retval = 0;
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"
retval++;
}
return retval;
}
///////////////////////////////////////////////
//
// WRITE <> <>
//
static int write_ui_cmd (void*, int argc, char **argv)
{
uint64_t paddr, value;
int ret;
if (argc != 4) {
ui->error("Check command format");
return(0);
}
ret = sscanf (argv[2], "%lli", &paddr);
if (ret != 1) {
ui->error("wrong address");
return 0;
}
ret = sscanf (argv[3], "%lli", &value);
if (ret != 1) {
ui->error("wrong value");
return 0;
}
if (mm1 == NULL) {
ui->error("RAM object is not ready yet!");
return 0;
}
if (strcmp(argv[1], "word") == 0) {
LO_W(paddr) &= ~3;
memwrite32u_nl(mm1, paddr, value);
} else if (strcmp(argv[1], "lword") == 0) {
LO_W(paddr) &= ~7;
memwrite64s_nl(mm1, paddr, value);
} else if (strcmp(argv[1], "hword") == 0) {
LO_W(paddr) &= ~1;
memwrite16u_nl(mm1, paddr, value);
} else if (strcmp(argv[1], "byte") == 0) {
memwrite8u_nl(mm1, paddr, value);
} else {
ui->error("wrong format (size)");
return 0;
}
return 1;
}
///////////////////////////////////////////////
//
// CONSOLE SEND "string"
//
//typedef void (*serial_send)(void *, char *);
extern serialInterface * systemConsole;
#ifdef V5_FAKEPROM
int static cs_ui_cmd (void*, int argc, char **argv)
{
char *str = NULL;
if (argc < 2) {
ui->error("command format error!\n");
return 0;
}
if(systemConsole == 0){
ui->error("system console not yet initialized\n");
return 0;
}
str = extract_string(argv[1]);
systemConsole->chars_send(str,systemConsole->portH);
free(str);
return 1;
}
#endif
///////////////////////////////////////////////
//
// RDT <filename> # redirect stdout
//
//
/*static?*/ int rdt_ui_cmd (void*, int argc, char **argv)
{
if (argc == 1) {
// redirect back (FILE->stdout)
redirect_back ();
}
else if (argc == 2) {
FILE * fp = fopen (argv[1], "w");
if (fp == NULL) {
ui->perror (argv[1]);
return 0;
}
if (redirect_stdout (fileno(fp))) {
ui->output("STDOUT redirected to <%s>\n", argv[1]);
}
}
else {
ui->error("wrong RDT command format\n");
}
return 1;
}
///////////////////////////////////////////////
//
// ON STOP <string>
//
/*static?*/ int on_ui_cmd (void*, int argc, char **argv)
{
if (argc <= 2) {
ui->error("wrong format ON command\n");
return 0;
}
if (strcmp(argv[1], "stop") == NULL) {
int ii, len = 0;
char * str;
for (ii = 2; ii < argc; ii++) {
len += (int)strlen(argv[ii]);
}
len += argc + 4; // just in case :-)
str = (char*) malloc (len);
strcpy(str, argv[2]);
strcat(str, " ");
for (ii = 3; ii < argc; ii++) {
strcat(str, " ");
strcat (str, argv[ii]);
}
if (strcmp(argv[2], "discard") == NULL) {
Ui_blcmd *pcmd = pui_misc->stop_list, *next;
for (;pcmd;) {
next = pcmd->next;
free (pcmd->cmd_str);
free ((char*)pcmd);
pui_misc->stop_list = pcmd = next;
}
return 1;
}
add_to_stop_list (str);
}
return 1;
}
///////////////////////////////////////////////
//
// SETREG <reg> <value>
//
int static setreg_ui_cmd (void*, int argc, char **argv)
{
uint64_t value;
int ret;
if (argc < 3) {
ui->error("wrong number of arguments : %d\n", argc);
return 0;
}
if (g_vcpu[0] == NULL) {
ui->error("Move this line to be after CPU is created ...\n");
exit (1);
}
if (argc == 3) {
ret = sscanf (argv[2], "%lli", &value);
if (ret != 1) {
ui->error("wrong VALUE argument <%s>\n", argv[2]);
return 0;
}
if (strcmp(argv[1], "pc") == NULL) {
for (uint32_t id = 0; id <= g_vcpu_id_max; id++) {
Vcpu *vcpu = get_vcpu(id);
if (!vcpu) continue;
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);
if (!vcpu) continue;
g_vcpu[id]->set_reg(VCPU_ASR_NPC, value);
}
}
else {
ui->error("unsupported register <%s>\n", argv[1]);
return 0;
}
}
else if (argc == 4) {
uint32_t id ;
Vcpu * vcpu = 0;
ret = sscanf (argv[1], "%i", &id);
if ( ret != 1 ) {
ui->error("wrong cpu id argument <%s>\n", argv[2]);
return 0;
}
vcpu = get_vcpu(id);
if(!vcpu){
ui->error("wrong cpu id argument <%s>\n", argv[2]);
return 0;
}
ret = sscanf (argv[3], "%lli", &value);
if (ret != 1) {
ui->error("wrong value argument <%s>\n", argv[3]);
return 0;
}
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);
}
else {
ui->error("unknown reg NAME <%s>\n", argv[2]);
return 0;
}
}
return 1;
}
///////////////////////////////////////////////
//
// ALIAS <newname> <cmd>
//
int static alias_ui_cmd (void*, int argc, char **argv)
{
if (argc == 1) {
Ui_cmd *pcmd = NULL;
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]);
ui->output("\n");
}
}
return 1;
}
else if (argc == 2){
Ui_cmd *pcmd = NULL;
for (pcmd = &ui_cmd_list[0]; pcmd;pcmd = pcmd->next) {
if (strcmp(argv[1], pcmd->name) == NULL)
break;
}
if (pcmd == NULL) {
ui->error("command <%s> not found \n", argv[1]);
return 0;
}
if (!(pcmd->flags & FUI_ALIAS)) {
ui->error("command <%s> is not an alias \n", argv[1]);
return 0;
}
ui->output("<%s> --> ", pcmd->name);
for (int32_t ndx = 0; ndx < pcmd->alias_argc; ++ndx)
ui->output("%s ", pcmd->alias_argv[ndx]);
ui->output("\n");
return 1;
}
// handle "alias new old ..."
// limit aliases to C-style identifiers i.e. alphanumeric and '_';
// no leading digits
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);
return 0;
}
}
}
Ui_cmd *pcmd = NULL;
Ui_cmd *prev_cmd = NULL;
for (pcmd = &ui_cmd_list[0];
pcmd;
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);
return 0;
}
free((void*)pcmd->name);
free((void*)pcmd->help);
while (pcmd->alias_argc)
free((void*)pcmd->alias_argv[pcmd->alias_argc--]);
free((void*)pcmd->alias_argv);
prev_cmd->next = pcmd->next;
break;
}
}
if (pcmd == NULL)
pcmd = (Ui_cmd*) calloc (1, sizeof(Ui_cmd));
if (pcmd == NULL) {
ui->error("register: cant malloc\n");
return 0;
}
pcmd->name = (char*) strdup(alias_name);
char buf[1000];
sprintf(buf, "alias for %s", pcmd->name);
pcmd->help = (char*) strdup(buf);
pcmd->cmd_exe_func = NULL;
pcmd->cmd_help_func = NULL;
pcmd->flags = FUI_ALIAS;
pcmd->alias_argc = argc - 2;
pcmd->alias_argv =
(const char**)malloc((argc-2) * sizeof(const char*));
if (pcmd->alias_argv == NULL) {
ui->error("register: cant malloc\n");
return 0;
}
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]);
return 0;
}
}
Ui_cmd* pc = &ui_cmd_list[0];
for ( ;pc->next; pc = pc->next)
;
pc->next = pcmd;
return 1;
}
///////////////////////////////////////////////
//
// UNALIAS <cmd>
//
int static unalias_ui_cmd (void*, int argc, char **argv)
{
if (argc == 2) {
Ui_cmd *pcmd = NULL;
Ui_cmd *prev_cmd = NULL;
for (pcmd = &ui_cmd_list[0];
pcmd;
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]);
return 0;
}
free((void*)pcmd->name);
free((void*)pcmd->help);
while (pcmd->alias_argc)
free((void*)pcmd->alias_argv[pcmd->alias_argc--]);
free((void*)pcmd->alias_argv);
prev_cmd->next = pcmd->next;
free(pcmd);
return 1;
}
}
ui->error("cannot find alias <%s>\n",
argv[1]);
return 0;
}
ui->error("usage: unalias <alias cmd>\n");
return 0;
}
///////////////////////////////////////////////
//
// MIPS [#|off] # compute blaze MIPS
//
//
static int
perf_ui_cmd (void*, int argc, char**argv)
{
float tmp;
if ((argc == 2 && strcmp (argv[1], "off") == 0) || argc == 1) {
perf_ui_interval = 0;
return 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 ();
return 1;
}
ui->error("usage : perf # | off \n");
return 1;
}
///////////////////////////////////////////////
//
// DEBUG, and OPTION settings
//
int static debug_ui_cmd (void*, int argc, char **argv)
{
if (argc == 2) {
blaze_debug = strtoul((const char*)argv[1], (char**)NULL, 0);
}
ui->output("blaze_debug = %d \n", blaze_debug);
return 1;
}
int static option_ui_cmd (void*, int argc, char **argv)
{
if (argc == 2) {
blaze_option = strtoul((const char*)argv[1], (char**)NULL, 0);
}
ui->output("blaze_option = %d \n", blaze_option);
return 1;
}
///////////////////////////////////////////////
//
// VERSION
//
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__);
return 1;
}
///////////////////////////////////////////////
//
// HELP
//
int static help_ui_cmd (void*, int argc, char **argv)
{
Ui_cmd *pcmd;
if (argc == 1) {
ui->output("SAM now supports UI commands: \n\n");
for (pcmd = &ui_cmd_list[0]; pcmd; pcmd = pcmd->next) {
if (pcmd->flags & FUI_INVALID)
continue;
ui->output("%s\n", pcmd->name);
}
return 1;
}
if (strcmp(argv[1], "all") == NULL) {
for (pcmd = &ui_cmd_list[0]; pcmd; pcmd = pcmd->next) {
if (pcmd->flags & FUI_INVALID)
continue;
if (pcmd->help)
ui->output ("%s : %s\n", pcmd->name, pcmd->help);
}
return 1;
}
for (pcmd = &ui_cmd_list[0]; pcmd; pcmd = pcmd->next) {
if (pcmd->flags & FUI_INVALID)
continue;
if (strcmp(pcmd->name, argv[1]) == NULL) {
if (pcmd->help) {
ui->output("%s\n", pcmd->help);
break;
}
}
}
return 1;
}
///////////////////////////////////////////////
// The interface for UI commands
//
void UI_exec_cmd (char *cmd)
{
SYSTEM_lock_UI();
exec_cmd(cmd);
SYSTEM_unlock_UI();
}
///////////////////////////////////////////////
void store_stdout_fd (int fd)
{
pui_misc->redirect_fd = fd;
}
///////////////////////////////////////////////
int get_stdout_fd()
{
return pui_misc->redirect_fd;
}
///////////////////////////////////////////////
void add_to_stop_list (char * cmd_str)
{
Ui_blcmd *pcmd = (Ui_blcmd*) calloc (1, sizeof(Ui_blcmd));
if (pcmd == NULL) {
ui->error("unable to deffer <%s> command \n", cmd_str);
return;
}
pcmd->cmd_str = cmd_str;
if (pui_misc->stop_list == NULL) {
pui_misc->stop_list = pcmd;
}
else {
Ui_blcmd *prev_cmd = pui_misc->stop_list;
while (prev_cmd->next != NULL) {
prev_cmd = prev_cmd->next;
}
prev_cmd->next = pcmd;
}
}
///////////////////////////////////////////////
//
// DISKDELAY ...
//
uint64_t
get_disk_ddelay_start_cycle(void)
{
return ddelay_start_cycle;
}
int
get_diskdelay(void)
{
return diskdelay;
}
int
get_wrdiskdelay(void)
{
return wrdiskdelay;
}
static int diskdelay_ui_cmd (void*, int argc, char **argv)
{
if (argc > 1) {
diskdelay = atoi((const char*)argv[1]);
wrdiskdelay = diskdelay;
ddelay_start_cycle = 0;
if (strchr(argv[1], '/') != NULL) {
if (sscanf(argv[1], "%d/%d", &diskdelay, &wrdiskdelay) != 2) {
ui->error("diskdelay format error !\n");
return 1;
}
}
if (argc > 2) {
ddelay_start_cycle = strtoul((const char*)argv[2], (char**)NULL, 0);
} else {
ddelay_start_cycle = SYSTEM_get_ticks ();
}
ui->output("DISK : ddelay = %d, wrddelay = %d, start_cycle = %lld\n",
diskdelay, wrdiskdelay, ddelay_start_cycle);
}
else if (argc == 1) {
ui->output("DISK : ddelay = %d, wrddelay = %d, start_cycle = %lld\n",
diskdelay, wrdiskdelay, ddelay_start_cycle);
}
return 0;
}
// ================================== 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 {
char *switchname;
} syncT;
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);
static void init_sync ()
{
syncT * msp = sync1;
//
// 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");
if (name) {
char buf[1024];
sprintf (buf, "sync:%s", name);
sync1->switchname = strdup (buf);
sync_fd = netsim_connect (sync1->switchname);
}
sync1 = msp;
}
/*
* sync UI commands
*
*/
static int sync_ui_cmd (void*, int argc, char * argv[])
{
syncT * msp = sync1;
if (argc == 2 && strcmp (argv[1], "on") == 0) { // "sync on" <--
if (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");
return 1;
}
if (sync_fd == -1) {
ui->error("time-sync not connected\n");
} else
write (sync_fd, "conn\n", 5); // Inform Sync-Master !!
SYSTEM_syncon_UI (); // transition !!!
sync_on = 1;
return 1;
}
if (argc == 2 && strcmp (argv[1], "off") == 0) { // "sync off" <-
if (!sync_on)
{
ui->error("not in time-sync mode\n");
// return 1;
}
if (sync_fd == -1) {
ui->error("time-sync not connected\n");
} else
write (sync_fd, "disconn\n", 8); // Inform Sync-Master !!!
SYSTEM_syncoff_UI (); // transition !!!
sync_on = 0;
return 1;
}
// ------------------ remote connection state ----------------------
if (argc == 1 // ""
|| (argc == 2 && strcmp (argv[1], "print") == 0)) { // "print"
if (sync_fd != -1) {
ui->output("\tsync1: %s", msp->switchname);
if (stept_seqnum != -1) {
if (IN_GTSTEP_STATE(blaze_run_state))
ui->output("\t %s, %lld *\n",
"gtstep", stept_seqnum);
else if (IN_GTWAIT_STATE(blaze_run_state))
ui->output("\t %s, %lld \n",
"gtwait", done_seqnum);
else
ui->output("\t %s, %lld \n",
(sync_on ? "on" : "off"), done_seqnum);
} else
ui->output("\t %s \n", (sync_on ? "on" : "off"));
} else
ui->output("\tsync1: disconnected\n");
return 1;
}
if (argc == 2 && strcmp (argv[1], "disconnect") == 0) { // "disconnect"
sync_disconnect (msp);
return 1;
}
if (argc == 2 && strcmp (argv[1], "connect") == 0) { // "connect"
sync_connect (msp, msp->switchname);
return 1;
}
if (argc == 3 && strcmp (argv[1], "connect") == 0) { // "connect host"
sync_connect (msp, argv[2]);
return 1;
}
// --------------------------- stuff ----------------------------
if (argc >= 2 && strcmp (argv[1], "debug") == 0) { // "debug"
if (argc == 2)
ui->output("sync debug level is %d\n", SYNCDEBUG);
else
SYNCDEBUG = atoi (argv[2]);
return 1;
}
sync_ui_usage (); /* if we haven't already returned... */
return 1;
}
// see also sync_thread_main for handling of disconnect by other end of socket
//
static void sync_disconnect (syncT * msp)
{
void * thd_status;
if (sync_fd == -1) {
ui->error("sync already disconnected\n");
return;
}
close (sync_fd);
sync_fd = -1; /* <--- ui-thread will see this <--- */
sync_on = 0;
}
static void sync_connect (syncT * msp, const char * switchname)
{
int fd;
char buf[1024];
if (sync_fd != -1) {
ui->error("sync already connected\n");
return;
} else if (switchname == NULL) {
ui->error("sync no switchname\n");
return;
}
if (SYNCDEBUG)
ui->output("sync reconnecting\n");
sprintf(buf,"sync:%s", switchname);
if ((fd = netsim_connect (buf)) >= 0) {
sync_fd = fd;
sync_on = 0;
msp->switchname = strdup (switchname);
} else {
ui->error("connection failed\n");
}
}
static void sync_ui_usage ()
{
ui->output("usage: \n");
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
{
public:
PenableDisableOptions(const std::string& cmd_)
:
cmd(cmd_),
cpu_opt(CpuSet().clear_all(), CpuOption::MULTITUDE)
{
add(cpu_opt);
}
virtual ~PenableDisableOptions() {}
std::string get_cmd() const { return cmd; }
CpuOption cpu_opt;
int usage()
{
std::string fmt =
"" + cmd + " command usage:\n"
"\t" + cmd + "\n"
"\t" + cmd + " -cpu <cpu set>\n"
"\t" + cmd + " <cpu mask>\n";
ui->error(fmt.c_str());
return 1;
}
private:
std::string cmd;
};
static int penable_disable_ui_cmd (void *, int argc, char **argv,
bool new_state, PenableDisableOptions& options)
{
int i;
Vcpu * vcpu = 0;
if (argc == 1) {
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");
}
return 1;
}
CpuSet cpu_set;
std::vector<std::string> pos_args;
bool result = options.parse(argc-1, (const char**)&argv[1], pos_args);
if (result) {
if (options.cpu_opt.is_on()) {
if (!pos_args.empty()) {
options.usage();
return 0;
}
cpu_set = options.cpu_opt.get_value();
}
else {
if (pos_args.size() != 1) {
options.usage();
return 0;
}
uint64_t cpu_mask;
std::string error_msg;
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());
return 0;
}
bool out_of_bounds = false;
cpu_set.insert_mask(cpu_mask, &out_of_bounds);
if (out_of_bounds)
ui->warning("cpu mask (%s) out of range\n",
pos_args[0].c_str());
}
for (CpuSet::iterator iter = cpu_set.begin();
iter != cpu_set.end();
++iter) {
i = *iter;
if (get_vcpu(i) != NULL)
cpu_enabled[i] = new_state;
}
cpu_enable_changed = true;
return 1;
}
std::string fmt = "UI " + options.get_cmd() + ": Syntax error\n\t%s\n";
ui->error(fmt.c_str(),options.get_error_msg().c_str());
return 0;
}
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)
{
if (pty_dev_a)
ui->output("SAM: Serial port A (pty device) for TIP connection is %s\n", pty_dev_a);
if (pty_dev_b)
ui->output("SAM: Serial port B (pty device) for TIP connection is %s\n", pty_dev_b);
if (pty_dev_c)
ui->output("SAM: Serial port C (pty device) for TIP connection is %s\n", pty_dev_c);
if (pty_dev_d)
ui->output("SAM: Serial port D (pty device) for TIP connection is %s\n", pty_dev_d);
return (1);
}
//////////////////////////////////////////////////////////////
//
// breakpoints
//
// command :
//
// break [?|cpu=[<cpu_id>|all]]
// [iaddr=<value>|opcode=<value>|data_read_addr=<value>|data_write_addr=<value>]
// [mask=<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
update_remote_ui();
return 0;
}
class BreakOptions : public CommandOptions
{
public:
BreakOptions()
:
cpu_opt(CpuSet().insert_all(), CpuOption::MULTITUDE),
trap_opt("trap", 0),
red_opt("red")
{
add(cpu_opt);
add(trap_opt);
add(red_opt);
// -trap qutiand -red are mutual exclusive
excl_opts.add(trap_opt).add(red_opt);
}
virtual ~BreakOptions() {}
CpuOption cpu_opt;
UnsignedOption trap_opt;
Option red_opt;
static int usage()
{
ui->output("set breakpoint command usage:\n");
ui->output("\tbreak\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");
return 1;
}
private:
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");
return 1;
}
BreakOptions options;
std::vector<std::string> pos_args;
bool result = options.parse(argc-1, (const char**)&argv[1], pos_args);
if (result)
{
CpuSet cpu_set = options.cpu_opt.get_value();
int bp_id;
uint64_t bp_value;
VCPU_BpType bp_type;
uint64_t bp_mask;
if (argc == 1)
{
// break
// printout all existing breakpoints
for (int i=0; i<=g_vcpu_id_max; i++)
{
if (g_vcpu[i])
{
g_vcpu[i]->print_breakpoints(ui->get_output_file());
if (ui->get_log_file())
g_vcpu[i]->print_breakpoints(ui->get_log_file());
}
}
return 0;
}
// break on trap
// break -cpu [cpu_id|all] -trap trap_type
if (options.trap_opt.is_on())
{
if (pos_args.size() == 0)
{
bp_type = VCPU_BP_TRAP;
bp_value = options.trap_opt.get_value();
}
else
{
ui->error("break on trap does not take any arguments\n");
return 1;
}
}
// break on red state
// break -cpu [cpu_id|all] -red
else if (options.red_opt.is_on())
{
if (pos_args.size() == 0)
bp_type = VCPU_BP_RED;
else
{
ui->error("break on red does not take arguments\n");
return 1;
}
}
else if (options.cpu_opt.is_on())
{
// break on pc
// break -cpu [cpu_id|all] pc_va
bp_type = VCPU_BP_INSTR_ADDR;
if (pos_args.size() > 0)
{
std::string error_msg;
if (!UnsignedOption::parse_number(pos_args[0], bp_value, error_msg))
{
error_msg += "pc-value";
ui->error("%s\n", error_msg.c_str());
return 1;
}
}
else
{
ui->error("break on PC requires a PC value\n");
return 1;
}
}
else
{
// break pc_va
// break pc_va [cpu_id]
bp_type = VCPU_BP_INSTR_ADDR;
if (pos_args.size() >= 1)
{
// set on all valid cpus
std::string error_msg;
if (!UnsignedOption::parse_number(pos_args[0], bp_value, error_msg))
{
error_msg += "pc-value";
ui->error("%s\n", error_msg.c_str());
return 1;
}
}
if (pos_args.size() == 2)
{
// set on the specified cpu
uint64_t cpu_id;
std::string error_msg;
if (!UnsignedOption::parse_number(pos_args[1], cpu_id, error_msg))
{
error_msg += "cpu-id";
ui->error("%s\n", error_msg.c_str());
return 1;
}
bool out_of_bounds = false;
cpu_set.clear_all();
cpu_set.insert(cpu_id, &out_of_bounds);
if (out_of_bounds)
{
ui->error("Cpu number %d is out of range\n", cpu_id);
return 1;
}
}
}
// set breakpoints on all valid cpus
for (CpuSet::iterator iter = cpu_set.begin();
iter != cpu_set.end();
++iter)
{
uint32_t i = *iter;
if (i > g_vcpu_id_max)
{
ui->fatal("internal error: break_ui_cmd: cpu 0x%lx out of range\n",i);
exit(-1);
}
if (g_vcpu[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());
}
return 0;
}
else
{
ui->error("break command parsing failed: %s\n",
options.get_error_msg().c_str());
return 1;
}
}
int break_ui_cmd_OLD (void*, int argc, char **argv)
{
int cpu_all = false;
int cpu_id = -1;
Vcpu * vcpu = 0;
int bp_id;
uint64_t bp_value;
VCPU_BpType bp_type;
uint64_t bp_mask;
char *name;
char *param;
if (!IN_STOP_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
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++)
{
if (g_vcpu[i])
{
g_vcpu[i]->print_breakpoints(ui->get_output_file());
if (ui->get_log_file())
g_vcpu[i]->print_breakpoints(ui->get_log_file());
}
}
return 1;
}
// 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_all = true;
}
else
{
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();
}
}
if (argc <3)
{
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" );
if (!name || !param)
{
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;
else
{
ui->error("breakpoint type should be: iaddr | opcode | data_read | data_write \n");
return BreakOptions::usage();
}
bp_mask = ~uint64_t(0);
if (argc == 4)
{
// read bp mask
name = strtok ( argv[3], " =" );
param = strtok ( NULL, "\0" );
if (!name || !param)
{
ui->error("missing breakpoint mask \n");
return BreakOptions::usage();
}
bp_mask = strtoull(param, NULL, 0);
if (bp_mask ==0)
{
ui->error("incorrect breakpoint mask\n");
return BreakOptions::usage();
}
}
// set the breakpoint
if (cpu_all)
{
for (int i=0; i<=g_vcpu_id_max; i++)
{
if (g_vcpu[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());
}
}
return 1;
}
else
{
if (
vcpu->set_breakpoint(&bp_id, bp_type, bp_value,
bp_action, bp_mask )==0)
{
ui->output("set breakpoint %i for cpu %i \n", bp_id, cpu_id);
}
return 1;
}
return BreakOptions::usage();
}
////////////////////////////////////////////////////
//
// remove breakpoint
//
// 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]"
" [bp_id=<id>]\n");
return 0;
}
int dbreak_ui_cmd (void*, int argc, char **argv)
{
int cpu_all = false;
int cpu_id = -1;
int bp_id = -1;
Vcpu * vcpu = 0;
char *name;
char *param;
if (!IN_STOP_STATE (blaze_run_state))
{
ui->error("not in stop state, use stop command first\n");
return 0;
}
if ( argc > 3)
return print_dbreak_usage();
if (argc == 1)
{
cpu_all = true;
}
if (argc > 1)
{
// 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_all = true;
}
else
{
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();
}
}
}
if (argc > 2)
{
// read bp id
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);
}
// remove breakpoint
if (cpu_all)
{
for (int i=0; i<=g_vcpu_id_max; i++)
{
if (g_vcpu[i] &&
g_vcpu[i]->delete_breakpoint(-1)== 0)
{
ui->output("delete breakpoint %i for cpu %i \n", bp_id, g_vcpu[i]->id());
}
}
return 1;
}
else
{
if (
vcpu->delete_breakpoint(bp_id)==0)
{
ui->output("delete breakpoint %i for cpu %i \n", bp_id, cpu_id);
}
return 1;
}
}
////////////////////////////////////////////////////
//
// Delete breakpoint
//
// command: delete [-all] [<bp_id> ... ]
//
class DeleteOptions : public CommandOptions
{
public:
DeleteOptions()
:
all_opt("all")
{
add(all_opt);
}
virtual ~DeleteOptions() {}
Option all_opt;
static int usage()
{
ui->output("usage: delete [-all] [<bp_id> ... ]\n");
return 1;
}
};
int delete_ui_cmd (void*, int argc, char **argv)
{
Vcpu * vcpu = 0;
char *name;
char *param;
if (!IN_STOP_STATE (blaze_run_state))
{
ui->error(" not in stop state, use stop command first\n");
return 0;
}
DeleteOptions options;
std::vector<std::string> pos_args;
bool result = options.parse(argc-1, (const char**)&argv[1], pos_args);
if (!result)
{
DeleteOptions::usage();
return 0;
}
// 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++)
if (g_vcpu[i])
g_vcpu[i]->delete_breakpoint(-1);
return 1;
}
for (std::vector<std::string>::iterator iter = pos_args.begin();
iter != pos_args.end();
++iter)
{
uint64_t bp_id;
std::string err_msg;
if (!UnsignedOption::parse_number(*iter, bp_id, err_msg))
{
err_msg += "breakpoint id\n";
ui->error(err_msg.c_str());
return 0;
}
int i = 0;
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);
break;
}
if (i > g_vcpu_id_max)
ui->error("Unknown breakpoint %d\n", bp_id);
}
return 1;
}
///////////////////////////////////////////////////////
//
// 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");
return 0;
}
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");
return 0;
}
// check command options
if ( argc == 1) // show status
{
return tracer_cmd (STRACER_STATUS);
}
if ( argc < 2 )
return print_vdebug_usage();
bool on = false;
char *cmd = "vdebug";
CommandOptions option;
CpuOption cpu_option(pselect_cpu_id,CpuOption::MULTITUDE);
StringOption out_option("o");
option.add(cpu_option);
option.add(out_option);
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());
return 0;
}
if (args.size() != 1)
{
fprintf(stderr, "ERROR: %s requires 1 positional argument - on|off.\n",cmd);
return 0;
}
else // parse on/off flag
{
if (args[0]=="on")
on = true;
else if (args[0]=="off")
on = false;
else
return print_vdebug_usage();
}
bool separate_files = false;
int tprev = -1;
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)
{
uint32_t cpu_id = *i;
Vcpu* vcpu = g_vcpu[cpu_id];
if (vcpu == 0)
{
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)
break;
// 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
sid[cpu_id] = 1;
}
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 );
}
///////////////////////////////////////////////////////
//
// print all tlb entries
//
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");
return 1;
}
if (argc < 2 || argc > 3)
{
ui->error("print all valid TTEs, usage: tlbs <cpuid> [<outfile>]\n");
return 1;
}
int cpu_id = strtol(argv[1], NULL, 0);
Vcpu* vcpu = get_vcpu(cpu_id);
if (vcpu == 0)
{
ui->error("SAM: There is no vcpu %i instance \n", cpu_id);
return 1;
}
if(argc == 3)
{
char * fname = argv[2];
FILE* stream = fopen (fname, "w");
ui->output("print tlb entries to %s\n", fname);
vcpu->print_tlbs(stream);
fclose(stream);
}
else
{
vcpu->print_tlbs(ui->get_output_file());
if (ui->get_log_file())
vcpu->print_tlbs(ui->get_log_file());
}
return 0;
}
///////////////////////////////////////////////////////
//
// set the log level
//
static int
loglev_ui_cmd (void*, int argc, char**argv)
{
int tmp;
if (argc == 1) {
}
else if (argc == 2 && sscanf (argv[1], "%d", &tmp) == 1 &&
tmp >= 1 && tmp <= 3) {
}
else {
ui->error("usage: loglev [1|2|3] \n");
return 1;
}
return 0;
}
static int
devmap_ui_cmd (void*, int argc, char**argv)
{
int tmp;
if(argc > 1){
ui->error("no arguments are allowed\n");
}
extern devRegistry * samDevs;
if (ui->get_log_file())
samDevs->dump(ui->get_log_file());
return 1;
}
// find a vcpu pointer by cpu instance name
static Vcpu * get_vcpu_by_name ( char *name )
{
Vcpu *vcpu = NULL;
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
break;
}
}
return vcpu;
}
///////////////////////////////////////////////////
//
// 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");
return 0;
}
if (argc < 2)
{
ui->error("usage: run-python-file <file_name> \n");
return 0;
}
// check if py module was loaded already
if (!python_UI)
{
char* sam_py_argv[1];
exec_cmd("mod load py py.so\n");
sam_py_argv[0] = "$SAM/pfe/sam.py";
if (py_source)
(py_source)(1,sam_py_argv);
}
if (!py_source)
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");
return 0;
}
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");
return 1;
}
CommandOptions cmd_options;
std::vector<std::string> pos_args;
bool result = cmd_options.parse(argc-1, (const char**)&argv[1], pos_args);
if (result)
{
if (argc == 1)
{
// pselect
ui->error("cpu %d is currently selected\n", pselect_cpu_id);
return 0;
}
else
{
// pselect cpu_id
uint64_t cpu_id;
std::string error_msg;
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])
{
pselect_cpu_id = cpu_id;
}
else
{
ui->error("No cpu matching cpu number: %lld\n", cpu_id);
return 1;
}
}
return 0;
}
else
{
ui->error("pselect command parsing failed: %s\n", cmd_options.get_error_msg().c_str());
return 1;
}
}
//////////////////////////////////////////////////////////////////////
// t r a n s l a t e
//////////////////////////////////////////////////////////////////////
class TranslateOptions : public CommandOptions
{
public:
TranslateOptions( int cpu_id )
:
cpu(cpu_id,CpuOption::MULTITUDE),
addressing(AddressingOptions::VA)
{
add(cpu);
add(addressing);
}
CpuOption cpu;
AddressingOptions addressing;
static int usage()
{
// We need to get this from the Options class
// CommandOptions::usage('translate');
return 1;
}
};
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");
return 1;
}
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());
return 1;
}
if (args.size() != 1)
{
ui->error("%s requires 1 positional argument; the address to translate.\n",cmd);
return 1;
}
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 pa;
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)
{
uint32_t cpu_id = *i;
ui->output("%d: ",cpu_id);
Vcpu* vcpu = g_vcpu[cpu_id];
if (vcpu == 0)
ui->output("not available\n");
else if (vcpu->translate(mode,ea,ctx,pid,&pa) != Vcpu::TRANSLATE_OK)
ui->output("no mapping available\n");
else
ui->output("pa = 0x%llx\n",pa);
}
return 0;
}
//////////////////////////////////////////////////////////////////////
// g e t
//////////////////////////////////////////////////////////////////////
class GetOptions : public CommandOptions
{
public:
GetOptions( int cpu_id )
:
cpu(cpu_id),
addressing(AddressingOptions::PA),
count("count",1),
size("size",4)
{
add(cpu);
add(addressing);
add(size);
add(count);
}
CpuOption cpu;
AddressingOptions addressing;
UnsignedOption size;
UnsignedOption count;
static int usage()
{
// We need to get this from the Options class
// CommandOptions::usage('get');
return 1;
}
};
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");
return 1;
}
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());
return 1;
}
uint32_t size;
uint32_t count;
switch (args.size())
{
case 2:
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);
return 1;
}
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);
return 1;
}
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;
break;
case 1:
size = options.size.get_value();
count = options.count.get_value();
break;
case 0:
default:
ui->error("%s requires address positional argument.\n",cmd);
return 1;
}
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);
return 1;
}
else
{
if (size & 7)
ui->warning("%s rounded size up to nearest multiple of 8.\n",cmd);
size = 8;
}
}
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 pa;
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];
if (vcpu == 0)
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);
else
{
uint8_t data8;
uint16_t data16;
uint32_t data32;
uint64_t data64;
uint_t n;
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);
break;
}
if ((n % (32 / size)) == 0)
ui->output("0x%016llx: ",pa);
switch (size)
{
case 1:
mmi_memread(pa,(uint8_t*)&data8,1);
ui->output("0x%02llx ",data8);
break;
case 2:
mmi_memread(pa,(uint8_t*)&data16,2);
ui->output("0x%04llx ",data16);
break;
case 4:
mmi_memread(pa,(uint8_t*)&data32,4);
ui->output("0x%08llx ",data32);
break;
case 8:
mmi_memread(pa,(uint8_t*)&data64,8);
ui->output("0x%016llx ",data64);
break;
}
if (((n + 1) % (32 / size)) == 0)
ui->output("\n");
}
if (n % (32 / size))
ui->output("\n");
}
return 0;
}
//////////////////////////////////////////////////////////////////////
// s e t
//////////////////////////////////////////////////////////////////////
class SetOptions : public CommandOptions
{
public:
SetOptions( int cpu_id )
:
cpu(cpu_id),
addressing(AddressingOptions::PA),
size("size",4),
count("count",1)
{
add(cpu);
add(addressing);
add(size);
add(count);
}
CpuOption cpu;
AddressingOptions addressing;
UnsignedOption size;
UnsignedOption count;
static int usage()
{
// We need to get this from the Options class
// CommandOptions::usage('set');
return 1;
}
};
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");
return 1;
}
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());
return 1;
}
uint32_t size;
uint32_t count;
switch (args.size())
{
case 3:
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);
return 1;
}
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);
return 1;
}
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;
break;
case 2:
size = options.size.get_value();
count = options.count.get_value();
break;
case 0:
default:
ui->error("%s requires address [size] positional arguments.\n",cmd);
return 1;
}
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);
return 1;
}
else
{
if (size & 7)
ui->warning("%s rounded size up to nearest multiple of 8.\n",cmd);
size = 8;
}
}
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 pa;
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];
if (vcpu == 0)
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);
else
{
uint64_t data64 = strtoull(args[1].c_str(),NULL,0);
uint32_t data32 = data64;
uint16_t data16 = data64;
uint8_t data8 = 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);
break;
}
switch (size)
{
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;
}
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////
// d i s a s s e m b l e
//////////////////////////////////////////////////////////////////////
class DisassembleOptions : public CommandOptions
{
public:
DisassembleOptions( int cpu_id )
:
cpu(cpu_id),
addressing(AddressingOptions::VA),
count("count",1)
{
add(cpu);
add(addressing);
add(count);
}
CpuOption cpu;
AddressingOptions addressing;
UnsignedOption count;
static int usage()
{
// We need to get this from the Options class
// CommandOptions::usage('disassemble');
return 1;
}
};
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");
return 1;
}
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());
return 1;
}
uint64_t ea;
uint32_t cpu_id = *options.cpu.get_value().begin();
uint32_t count;
Vcpu* vcpu = g_vcpu[cpu_id];
if (vcpu == 0)
{
ui->error("cpu %d not available\n",cpu_id);
return 0;
}
switch (args.size())
{
case 2:
if (options.count.is_on())
{
ui->error("%s used with confusing arguments: both positional "
"count argument and -count option given: use -count.\n",cmd);
return 1;
}
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);
break;
case 1:
ea = strtoull(args[0].c_str(),NULL,0);
count = options.count.get_value();
break;
case 0:
#if TO_BE_IMPLEMENTED
vcpu->get_reg(VCPU_ASR_PC,&ea);
count = options.count.get_value();
break;
#endif
default:
ui->error("%s requires address positional arguments.\n",cmd);
return 1;
}
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 pa;
if (ea & 3)
{
ui->warning("%s likes the address argument to be 4 byte aligned\n",cmd);
ea &= ~3ull;
}
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);
else
{
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);
break;
}
char inst[256];
uint32_t data;
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);
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////
// r e a d - a s i
//////////////////////////////////////////////////////////////////////
class ReadAsiOptions : public CommandOptions
{
public:
ReadAsiOptions( int cpu_id )
:
cpu(cpu_id)
{
add(cpu);
}
CpuOption cpu;
static int usage()
{
// We need to get this from the Options class
// CommandOptions::usage('disassemble');
return 1;
}
};
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");
return 1;
}
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());
return 1;
}
if (args.size() != 2)
{
ui->error("%s requires <asi> <address> positional arguments.\n",cmd);
return 1;
}
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();
if (asi > 0xff)
{
ui->error("valid non-translating asi values range from 0 to 0xff\n",cmd);
return 1;
}
if (va & 7)
{
ui->warning("%s requires the address argument to be 8 byte aligned\n",cmd);
va &= ~7ull;
}
Vcpu* vcpu = g_vcpu[cpu_id];
if (vcpu == 0)
{
ui->error("cpu %d not available\n",cpu_id);
return 1;
}
uint64_t data;
int fail = vcpu->get_asi(asi,va,data);
if (fail)
{
ui->error("0x%02llx:0x%llx is not a valid non-translating asi:va pair\n",asi,va);
return 1;
}
ui->output("0x%02llx:0x%llx = 0x%llx\n",asi,va,data);
return 0;
}
//////////////////////////////////////////////////////////////////////
// w r i t e - a s i
//////////////////////////////////////////////////////////////////////
class WriteAsiOptions : public CommandOptions
{
public:
WriteAsiOptions( int cpu_id )
:
cpu(cpu_id)
{
add(cpu);
}
CpuOption cpu;
static int usage()
{
// We need to get this from the Options class
// CommandOptions::usage('disassemble');
return 1;
}
};
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");
return 1;
}
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());
return 1;
}
if (args.size() != 3)
{
ui->error("%s requires <asi> <address> <value> positional arguments.\n",cmd);
return 1;
}
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();
if (asi > 0xff)
{
ui->error("valid non-translating asi values range from 0 to 0xff\n",cmd);
return 1;
}
if (va & 7)
{
ui->warning("%s requires the address argument to be 8 byte aligned\n",cmd);
va &= ~7ull;
}
Vcpu* vcpu = g_vcpu[cpu_id];
if (vcpu == 0)
{
ui->error("cpu %d not available\n",cpu_id);
return 1;
}
int fail = vcpu->set_asi(asi,va,data);
if (fail)
{
ui->error("0x%02llx:0x%llx is not a valid non-translating asi:va pair\n",asi,va);
return 1;
}
return 0;
}
///////////////////////////////////////////////
//
// ECHO
//
int static echo_ui_cmd (void*, int argc, char **argv)
{
for (int i = 1; i < argc; ++i)
{
const char* arg = argv[i];
if (arg[0] == '"')
{
int len = strlen(arg);
if (len > 2 && arg[len-1] == '"')
{
ui->output("%.*s ", len-2, &arg[1]);
continue;
}
}
ui->output("%s ", arg);
}
ui->output("\n");
return 0;
}
///////////////////////////////////////////////
//
// LIST-BREAKPOINTS
//
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++)
{
if (g_vcpu[i])
{
g_vcpu[i]->print_breakpoints(ui->get_output_file());
if (ui->get_log_file())
g_vcpu[i]->print_breakpoints(ui->get_log_file());
}
}
return 0;
}