Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / system / blaze / system.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: system.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
//
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
/*
* Copyright (C) 2001, 2005 Sun Microsystems, Inc.
* All rights reserved.
*/
/* file layout, icqs:
* UICMDS (ie functions called by ui)
* DUMPRESTORE
* CPUACCESS (
* SYSCONF (legacy api, to be replace with real sysconf api soon...)
* HOSTCONFIG
*/
/* standard C includes */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <synch.h>
#include <thread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
/* project includes */
#include "types.h"
#include "blaze_globals.h"
#include "system.h"
#include "ui.h"
#include "dr.h"
#include "system_impl.h"
#include "ui_utils.h"
#include "workerthread.h"
uint32_t boot_ctrl_id = 0;
uint32_t boot_target_id = 0;
uint32_t boot_part_id = 0;
uint32_t boot_disk_id = 0;
extern void term_console_destroy (); // defined in term.cc
// ========================== GLOBAL VARIABLES ================================
// BS flags. Majority of them are needed only within startp time
//
static bool_t ce_enable_flag = FALSE;
static bool_t scsi_disk_enable_flag = FALSE;
static bool_t scsi_boot_enable_flag = FALSE;
static bool_t fc_disk_enable_flag = FALSE;
static bool_t fc_boot_enable_flag = FALSE;
static bool_t mem_reserve_flag = TRUE;
SystemT the_sys = {0};
SystemT *psys = &the_sys;
uint64_t goodtrap_pc;
uint64_t badtrap_pc;
// The SAM UI is multi threaded; input can come from the user,
// the global time sync or a remote debugger for example. Every
// ui command needs to be executed whilst holding the lock. The
// ui_lock_held booleans is added to help in asserting this.
// The ui_cond variable is for synchronizing stop, see SYSTEM_wait_stop()
static mutex_t ui_lock;
static cond_t ui_cond;
static bool ui_lock_held;
// ============================================================================
//
// SYSTEM_open (like tracemod/mod_dlopen) is to look for files in the
// installation directory of blaze if the cwd doesn't work
//
// we don't search install dir if filename begins with '/'
// or './', but we do search install dir for '../' because
// "../lib/" or "../demo/" or "../etc/" are common
//
static char * blaze_exec_path = NULL;
FILE* SYSTEM_fopen (const char * filename, const char * flags)
{
FILE * fp;
fp = fopen (filename, flags);
if (!fp && blaze_exec_path && !(filename[0] == '/')
&& !(strncmp(filename, "../", 3) == 0)) {
char * temp = (char*) malloc (strlen (blaze_exec_path)
+ strlen (filename) + 1);
strcpy (temp, blaze_exec_path);
strcat (temp, filename);
fp = fopen (temp, flags);
}
return fp;
}
int SYSTEM_open (const char * filename, int oflag)
{
int fd;
fd = open (filename, oflag);
if (fd<0 && blaze_exec_path && !(filename[0] == '/')
&& !(strncmp(filename, "../", 3) == 0)) {
char * temp = (char*) malloc (strlen (blaze_exec_path)
+ strlen (filename) + 1);
strcpy (temp, blaze_exec_path);
strcat (temp, filename);
fd = open (temp, oflag);
}
return fd;
}
void init_SYSTEM_open ()
{
blaze_exec_path = strdup (getexecname ());
if (blaze_exec_path && strlen(blaze_exec_path) > 0) {
int i = strlen (blaze_exec_path) - 1;
while (i>0 && blaze_exec_path[i] != '/') --i;
blaze_exec_path[i+1] = '\0';
} else {
ui->verbose("getexecname = \"%s\"\n", blaze_exec_path);
ui->error("SAM cannot determine its own install dir path, "
"\"load <filename>\" cannot search install dir for files\n");
}
}
///////////////////////////////////////////////////////////
void SYSTEM_set_memreserve (bool_t flag)
{
mem_reserve_flag = flag;
}
bool_t SYSTEM_get_memreserve()
{
return mem_reserve_flag;
}
void SYSTEM_cycle_delay (uint32_t cpuid, uint32_t delay)
{
Vcpu *vcpu = get_vcpu(cpuid);
if (vcpu) {
vcpu->config.delay = delay;
} else {
ui->error("SYSTEM_cycle_delay: bad CPU id %d \n", cpuid);
}
}
int SYSTEM_in_execution_driven_mode()
{
return g_vcpu ? g_vcpu[0]->config.execution_driven : 0;
}
// must be called in response to a UI command, from the ui thread
void SYSTEM_enable_execution_driven_mode()
{
if (! IN_STOP_STATE(blaze_run_state))
{
ui->error("not in stop state \n");
return;
}
if (SYSTEM_in_execution_driven_mode())
{
ui->warning("enable_execution_driven_mode: exec-driven mode already enabled\n");
}
else
{
ui->output("enabling exec-driven mode. Setting numthreads to 1\n");
for(int i = 0; i <= g_vcpu_id_max; i++)
{
Vcpu *vcpu = get_vcpu(i);
if (!vcpu)
continue;
vcpu->config.execution_driven = 1;
}
the_arch.numthreads = 1;
cpu_enable_changed = 1;
}
} // void VCPU_Config::enable_execution_driven_mode()
void SYSTEM_disable_execution_driven_mode()
{
for(int i = 0; i <= g_vcpu_id_max; i++)
{
Vcpu *vcpu = get_vcpu(i);
if (!vcpu)
continue;
vcpu->config.execution_driven = 0;
}
cpu_enable_changed = 1;
} // void VCPU_Config::disable_execution_driven_mode()
cpuT *SYSTEM_cpu_by_sid(int n)
{
return get_vcpu(n);
}
void SYSTEM_unlock ()
{
}
void * SYSTEM_is_ready ()
{
return psys;
}
void SYSTEM_init(void)
{
BLAZE_STOP(blaze_run_state); // transition from INVALID to STOP !!!
mutex_init (&ui_lock, USYNC_THREAD, 0);
cond_init (&ui_cond, USYNC_THREAD, 0);
ui_lock_held = false;
}
void SYSTEM_lock_UI()
{
assert(!ui_lock_held);
mutex_lock (&ui_lock);
ui_lock_held = true;
}
void SYSTEM_unlock_UI()
{
assert(ui_lock_held);
ui_lock_held = false;
mutex_unlock(&ui_lock);
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//
// External interrupt delivery. This function is being called
// by SCHIZO as well as in other CPU (xcalls) in order to send INTR.
//
void SYSTEM_interrupt_by_sid(int dst_aid, int src_aid, intrT *intr)
{
Vcpu *vcpu = get_vcpu(dst_aid);
if(vcpu)
vcpu->interrupt ( intr );
}
static sint64_t system_intervalstart_usecs = 0;
static sint64_t system_intervallength_usecs = 0;
static sint64_t system_interval_sequencenum = 0;
bool SYSTEM_is_sync_on ()
{
if (IN_GTWAIT_STATE (blaze_run_state) || IN_GTSTEP_STATE (blaze_run_state))
return true;
return false;
}
void SYSTEM_mark_intervalstart (sint64_t usecs, uint64_t seqnum)
{
system_intervalstart_usecs = SYSTEM_get_global_time();
system_intervallength_usecs = usecs;
system_interval_sequencenum = seqnum;
}
void SYSTEM_mark_intervalstop ()
{
}
sint64_t SYSTEM_get_sequencenum ()
{
return system_interval_sequencenum;
}
int64_t SYSTEM_get_time (timewhence_t whence /*= TW_CURRENT*/)
{
if (whence == TW_CURRENT)
return SYSTEM_get_global_time();
else if (whence == TW_INTERVAL)
return SYSTEM_get_global_time() - system_intervalstart_usecs;
else if (whence == TW_MARK)
return system_intervalstart_usecs;
else if (whence == TW_LENGTH)
return system_intervallength_usecs;
return 0ull;
}
extern doneftn_t volatile wrkthdCBFunc;
extern void * volatile wrkthdCBArg;
extern sema_t wrkthdDONE;
static void check_mips_stickfreq()
{
// stickfreq not being set will cause kernel panic, so error anyway.
if (the_arch.stick_freq == 0){
ui->error("stickfreq not conf'ed. Add conf stickfreq <value> in rc file.\n");
exit(1);
}
if (the_arch.mips == 0) {
// if running from a checkpoint, then walk around
if (BLAZE_restore_from_checkpoint ()) {
// calculate the mips from the loopticks, stickincr
// recalculate to reflect changes in loopticks/stickincr/etc
the_arch.mips = ((the_arch.loopticks * the_arch.stick_freq )
/ the_arch.stickincr) / 1000000ULL;
the_arch.umips = the_arch.kmips = the_arch.mips;
}else{
ui->error("mips not conf'ed, exit. Add conf mips <value> in rc file.\n");
exit(1);
}
}
}
void SYSTEM_kick_usecs (int64_t nusecs)
{
if (cpu_enable_changed)
WorkerThread::create_worker_threads (SYSTEM_get_ncpu(),SYSTEM_get_cpus_per_thread(),\
SYSTEM_get_numthreads());
while (sema_trywait (&wrkthdDONE) == 0) ; // "sema_reset()"
check_mips_stickfreq();
if (SYSTEM_in_execution_driven_mode()) {
WorkerThread::kick_stepc(nusecs * (g_vcpu[0]->config.cpufreq / 1000000));
} else {
WorkerThread::kick_stept(nusecs);
}
}
void SYSTEM_kick_instrs (int64_t ninstrs)
{
if (cpu_enable_changed)
WorkerThread::create_worker_threads (SYSTEM_get_ncpu(),SYSTEM_get_cpus_per_thread(),\
SYSTEM_get_numthreads());
while (sema_trywait (&wrkthdDONE) == 0) ; // "sema_reset()"
check_mips_stickfreq();
WorkerThread::kick_stepi(ninstrs);
}
void SYSTEM_kick_cycles(int64_t ncycles)
{
if (cpu_enable_changed)
WorkerThread::create_worker_threads(SYSTEM_get_ncpu(), SYSTEM_get_cpus_per_thread(),
SYSTEM_get_numthreads());
while (sema_trywait (&wrkthdDONE) == 0) ; // "sema_reset()"
check_mips_stickfreq();
WorkerThread::kick_stepc(ncycles);
}
void
SYSTEM_kick_with_callback (int64_t nusecs, doneftn_t callback)
{
// only used by G-T-Sync, hence only a `usecs' version
wrkthdCBFunc = callback;
wrkthdCBArg = NULL;
SYSTEM_kick_usecs (nusecs);
}
// -------- Time and Events ---------------------------------------------------
// \___ microsecs.
void SYSTEM_register_event (
uint64_t stime,
EventFunc_T * callbackfunc, void * arg1, void * arg2,
UnloadFunc_T * unloadfunc,
const char * debugstring)
{
WorkerThread::registerEvent(stime, callbackfunc, arg1, arg2,
unloadfunc, debugstring);
}
int eventque_ui_cmds (void*, int argc, char **argv)
{
if (argc > 1 && strcmp (argv[1], "debug") == 0) {
if (argc > 2) {
EventQue::debug = strtol (argv[2], NULL, 0);
}
ui->verbose("events debug = %d\n", EventQue::debug);
return 1;
}
WorkerThread::doEventquePrint ();
return 1;
}
int64_t SYSTEM_get_ticks () // for perf_ui_cmd() only.!.
{
return WorkerThread::get_ticks();
}
uint64_t SYSTEM_get_globaltick_per_cpu () // for fc device, deprecated
{
return WorkerThread::get_ticks(); // also deprecated
}
uint64_t SYSTEM_get_global_time() // in MicroSecs, always !!!
{
return WorkerThread::get_time();
}
// ========================================================================== {
// UICMDS
//
// The routines below are being called in context of UI thread !!
//
/**********************************************************
* Blaze Run State Diagram for UI commands:
*
*
* "run"
* +--------+ "stepi" +--------+
* | |- - - - - - ->>| |
* | STOP | | RUN |
* | |<<- - - - - - -| |
* +--------+ "stop" +--------+
* | ^ CTRL-C
* | ^
* | |
* "syncOn"| |"syncOff"
* "resume"| |"stop", CTRL-C
* | |
* V |
* V |
* +--------+ "stept" +--------+
* | |- - - - - - ->>| |
* | GTWAIT | | GTSTEP |
* | |<<- - - - - - -| |
* +--------+ +--------+
*
*
* Note: we call device start/stop_action() when leaving/entering
* the STOP state, but not when cycling between the GT* states.
*
**********************************************************/
void SYSTEM_ss_register (ss_action stop, ss_action restart, void* d)
{
SS_entry *pentry = (SS_entry*) calloc (1, sizeof(SS_entry));
pentry->stop_action = stop;
pentry->start_action = restart;
pentry->client_data = d;
if (psys == NULL) {
ui->fatal("internal error (psys is not init yet)\n");
exit (1);
}
pentry->next = psys->ss_head;
psys->ss_head = pentry;
}
static void SYSTEM_device_stop_action()
{
for (SS_entry *pentry = psys->ss_head; pentry; pentry = pentry->next) {
if (pentry->stop_action)
pentry->stop_action (pentry->client_data);
}
}
static void SYSTEM_devices_start_action()
{
for (SS_entry *pentry = psys->ss_head; pentry; pentry = pentry->next) {
if (pentry->start_action)
pentry->start_action (pentry->client_data);
}
}
// put the cpu-sims into async run mode ----------------------------------
//
void SYSTEM_run_UI ()
{
assert(ui_lock_held);
if (! IN_STOP_STATE(blaze_run_state))
return;
BLAZE_RUN(blaze_run_state);
SYSTEM_kick_usecs (1ULL <<48/*infinity*/); // Start cpus
SYSTEM_devices_start_action();
}
// The stop, stepi, stepc, and syncoff all end with a call to
// SYSTEM_wait_stop() which will wait for the workerthread to
// finish and and then stop the rest.
static void SYSTEM_wait_stop()
{
static bool sema_wait_pending = false;
// Only one thread can be waiting in the semaphore for the
// worker threads to stop. So when a wait is pending then we
// just synchronize the return when stop really occurs.
if (sema_wait_pending)
{
while (sema_wait_pending)
cond_wait(&ui_cond,&ui_lock);
return;
}
sema_wait_pending = true;
// We know that we get here holding the ui_lock. We wait here
// for the worker threads to finish. While we wait we release
// the ui lock. If we don't release the lock then we have a
// potential deadlock situation where stop is holding the lock
// and a probe action is waiting for the lock - blocking the
// workerthread from stopping.
SYSTEM_unlock_UI();
sema_wait (&wrkthdDONE); // ------ wait for all to finish ------
SYSTEM_lock_UI();
sema_wait_pending = false;
cond_broadcast(&ui_cond);
// cpu threads stop first to make io stop safe logic easy
SYSTEM_device_stop_action();
BLAZE_CLEAR(blaze_stop_request); // Reset stop request if any pending
BLAZE_STOP(blaze_run_state); // Reset
update_remote_ui(); // signal stop to remote debug client
}
// stop the async run mode ----------------------------------
//
void SYSTEM_stop_UI ()
{
assert(ui_lock_held);
/* gtwait means we're already stopped !! */
if (IN_GTWAIT_STATE (blaze_run_state)) {
SYSTEM_device_stop_action();
BLAZE_STOP(blaze_run_state);
return;
}
if (IN_STOP_STATE (blaze_run_state))
return;
BLAZE_STOP(blaze_stop_request);
SYSTEM_wait_stop();
}
// run the cpu-sims synchronously (ui waits) --------------------------------
void SYSTEM_stepi_UI (int64_t ni)
{
assert(IN_STOP_STATE(blaze_run_state));
BLAZE_STEP(blaze_run_state);
SYSTEM_kick_instrs(ni);
SYSTEM_devices_start_action();
SYSTEM_wait_stop();
}
void SYSTEM_stepc_UI (int64_t nc)
{
assert(IN_STOP_STATE(blaze_run_state));
BLAZE_STEP(blaze_run_state);
SYSTEM_kick_cycles(nc);
SYSTEM_devices_start_action();
SYSTEM_wait_stop();
}
// -------------------- a Global-Time-Sync interval ---------------------
//
extern "C" {
static void SYSTEM_stept_callback (void * arg);
};
static doneftn_t stept_callback_ftn;
static void * stept_callback_arg;
void SYSTEM_stept_UI (int64_t usecs, int64_t seqnum, doneftn_t callback)
{
assert(ui_lock_held);
if (!IN_GTWAIT_STATE(blaze_run_state))
return;
SYSTEM_mark_intervalstart (usecs, seqnum); // MARK BEGIN <---
BLAZE_GTSTEP(blaze_run_state); // Set
stept_callback_ftn = callback;
stept_callback_arg = NULL;
SYSTEM_kick_with_callback (usecs, SYSTEM_stept_callback); // Start cpus
// N.B. `devices' are started at syncON, not here. // devices
}
extern "C" {
static void SYSTEM_stept_callback (void * /* arg */)
{
BLAZE_GTWAIT(blaze_run_state); // Reset
// N.B. `devices' are stopped at syncOFF, not here. // devices
SYSTEM_mark_intervalstop (); // MARK END <---
doneftn_t FTN = stept_callback_ftn;
if (FTN != NULL) {
stept_callback_ftn = NULL;
(*FTN) (stept_callback_arg);
}
}
};
// "sync on" ----------------------------------------------------------
//
void SYSTEM_syncon_UI ()
{
assert(ui_lock_held);
if (!IN_STOP_STATE(blaze_run_state))
return;
SYSTEM_devices_start_action();
BLAZE_GTWAIT(blaze_run_state);
}
// "sync off" ----------------------------------------------------------
//
void SYSTEM_syncoff_UI ()
{
assert(ui_lock_held);
if (!IN_SYNC_STATE(blaze_run_state))
return;
if (IN_GTSTEP_STATE(blaze_run_state)) {
BLAZE_STOP(blaze_stop_request); // Request halt
SYSTEM_wait_stop();
return;
}
assert(IN_GTWAIT_STATE(blaze_run_state));
SYSTEM_device_stop_action();
BLAZE_STOP(blaze_run_state); // Reset
}
// quit,exit,terminate,... ----------------------------------------------------
// this is being call from entirely too many places...
void quit_simulation ()
{
#ifdef V5_FAKEPROM
term_console_destroy ();
#endif
if ( mm1 != NULL )
delete mm1;
ui->output("quitting ...\n");
exit (0);
}
// devices/scsi_disk.cc should not be calling this...
void SYSTEM_quit ()
{
quit_simulation();
exit (0);
}
void SYSTEM_quit_UI ()
{
quit_simulation();
exit (0);
}
///////////////////////////////////////////////
void SYSTEM_ss_unregister (void *d)
{
if (psys) {
SS_entry *pentry = psys->ss_head;
SS_entry *prev = NULL;
while (pentry) {
if (pentry->client_data == d) {
if (prev)
prev->next = pentry->next;
else
psys->ss_head = pentry->next;
free(pentry);
pentry = psys->ss_head;
prev = NULL;
}
else {
prev = pentry;
pentry = pentry->next;
}
}
}
}
bool_t SYSTEM_is_stopped ()
{
return IN_STOP_STATE(blaze_run_state) ? TRUE : FALSE;
}
bool_t SYSTEM_is_running ()
{
return ANY_RUNNING_STATE(blaze_run_state) ? TRUE : FALSE;
}
bool_t SYSTEM_is_notready ()
{
return blaze_run_state == e_BLAZE_INVALID ? TRUE : FALSE;
}
// ========================================================================== }
// ========================================================================== {
// DUMPRESTORE
extern void write_scalar_64 (FILE *fp, const char * name, uint64_t v);
extern void write_scalar_32 (FILE *fp, const char * name, uint32_t v);
extern void write_string (FILE *fp, const char * name, char *s);
extern bool_t read_scalar_64 (FILE *fp, const char * name, uint64_t *v);
extern bool_t read_scalar_32 (FILE *fp, const char * name, uint32_t *v);
extern char* read_string (FILE *fp, const char * name, int , char *s);
extern char* read_string_2 (FILE *fp, const char * name, const char * alt_name, int , char *s);
void
SYSTEM_dump (FILE *fp)
{
write_scalar_64 (fp, "global_tick", global_tick);
write_scalar_32 (fp, "numcpus", the_arch.numcpus);
write_scalar_32 (fp, "nwins", the_arch.nwins);
write_scalar_64 (fp, "ramsize", the_arch.ramsize);
write_scalar_32 (fp, "tlbsize", the_arch.tlbsize);
write_scalar_32 (fp, "loopticks", the_arch.loopticks);
write_scalar_32 (fp, "loopticks_cp", the_arch.loopticks_cp);
write_scalar_32 (fp, "stickincr", the_arch.stickincr);
write_scalar_32 (fp, "cpus_per_thread", the_arch.cpus_per_thread);
write_scalar_64 (fp, "cpu_freq", the_arch.cpu_freq);
write_scalar_64 (fp, "stick_freq", the_arch.stick_freq);
write_scalar_32 (fp, "arch_flags", the_arch.arch_flags);
write_string (fp, "cputype", the_arch.mmutype);
write_string (fp, "platform", the_arch.platform);
write_scalar_32 (fp, "cpi", the_arch.cpi);
write_scalar_32 (fp, "boot_ctrl_id", boot_ctrl_id);
write_scalar_32 (fp, "boot_target_id", boot_target_id);
//write_scalar_32 (fp, "boot_disk_id", boot_disk_id);
write_scalar_32 (fp, "boot_part_id", boot_part_id);
write_scalar_32 (fp, "numNICs", the_arch.numNICs);
write_scalar_32 (fp, "numDCs", the_arch.numDCs); // number of disk controllers on pciA
write_scalar_64 (fp, "mips", the_arch.mips);
write_scalar_64 (fp, "umips", the_arch.umips);
write_scalar_64 (fp, "kmips", the_arch.kmips);
write_scalar_32 (fp, "roundrobin", the_arch.roundrobin);
WorkerThread::dump(fp);
}
bool_t
SYSTEM_restore (FILE *fp)
{
char line[1000], temp[1000];
do {
if (fgets (line, sizeof(line), fp) == NULL)
break;
else if (sscanf (line, "arch_flags %i", &the_arch.arch_flags) == 1) ;
else if (sscanf (line, "global_tick %lli", &global_tick) == 1) ;
else if (sscanf (line, "cpus_per_thread %i",&the_arch.cpus_per_thread)==1);
else if (sscanf (line, "numcpus %i", &the_arch.numcpus) == 1) ;
else if (sscanf (line, "nwins %i", &the_arch.nwins) == 1) ;
else if (sscanf (line, "ramsize %lli", &the_arch.ramsize) == 1) ;
else if (sscanf (line, "tlbsize %i", &the_arch.tlbsize) == 1) ;
else if (sscanf (line, "loopticks %i", &the_arch.loopticks) == 1) ;
else if (sscanf (line, "loopticks_cp %i", &the_arch.loopticks_cp)==1) ;
else if (sscanf (line, "stickincr %i", &the_arch.stickincr) == 1) ;
else if (sscanf (line, "cpu_freq %lli", &the_arch.cpu_freq) == 1) ;
else if (sscanf (line, "stick_freq %lli", &the_arch.stick_freq) == 1) ;
else if (sscanf (line, "cpi %i", &the_arch.cpi) == 1) ;
else if (sscanf (line, "mips %lli", &the_arch.mips) == 1) {
the_arch.umips = the_arch.kmips = the_arch.mips; }
else if (sscanf (line, "umips %lli", &the_arch.umips) == 1) ;
else if (sscanf (line, "kmips %lli", &the_arch.kmips) == 1) ;
else if (sscanf (line, "roundrobin %i", &the_arch.roundrobin) == 1) ;
else if (sscanf (line, "boot_ctrl_id %i", &boot_ctrl_id) == 1) ;
else if (sscanf (line, "boot_target_id %i", &boot_target_id) == 1) ;
else if (sscanf (line, "boot_part_id %i", &boot_part_id) == 1) ;
else if (sscanf (line, "numNICs %i", &the_arch.numNICs) == 1) ;
else if (sscanf (line, "numDCs %i", &the_arch.numDCs) == 1) ;
else if (sscanf (line, "platform %s", &temp[0]) == 1) {
the_arch.platform = strdup (temp); }
else if (sscanf (line, "cputype %s", &temp[0]) == 1) {
the_arch.mmutype = strdup (temp);
#ifdef CHPLUS
if (strcmp(the_arch.mmutype, "cheetah") == 0
|| strcmp(the_arch.mmutype, "spitfire") == 0)
ui->verbose("restore: mmutype %s NG. with CHPLUS \n",
the_arch.mmutype);
#elif CH
if (strcmp(the_arch.mmutype, "cheetahplus") == 0)
ui->verbose("restore: mmutype %s NG. with CH \n",
the_arch.mmutype);
#endif
}
else if (WorkerThread::restore(&line[0]) == 1) ;
else
ui->error("restore: unrecognized: %s\n", line);
} while (1) ;
if (restore_v4_dump() && the_arch.mips == 0) {
// need non-zero values for all of these v4 config values
//
if (the_arch.loopticks && the_arch.stickincr && the_arch.stick_freq) {
int64_t mips = (( (the_arch.stick_freq * the_arch.loopticks)
/ the_arch.stickincr) / 1000000LL);
the_arch.mips = mips;
the_arch.umips = mips;
the_arch.kmips = mips;
ui->verbose("mips computed from v4 stick_freq*loopticks/stickincr/1M"
" = %lld\n", the_arch.mips);
}
//
// hmmm, insufficient data, but this can't happen...?...
}
return TRUE;
}
// ========================================================================== {
// SYSCONF api routines
//
uint8_t SYSTEM_get_dc_num()
{
return (the_arch.numDCs);
}
uint8_t SYSTEM_get_nic_num()
{
return (the_arch.numNICs);
}
bool_t SYSTEM_chplus_mmu ()
{
#ifdef CHPLUS
return TRUE;
#else
return FALSE;
#endif
}
int SYSTEM_get_nwins()
{
return the_arch.nwins;
}
extern int get_wrdiskdelay();
int SYSTEM_get_wrdiskdelay()
{
return get_wrdiskdelay();
}
extern int get_diskdelay();
int SYSTEM_get_diskdelay()
{
return get_diskdelay();
}
int SYSTEM_get_loopticks ()
{
return the_arch.loopticks;
}
int SYSTEM_get_stickincr ()
{
return the_arch.stickincr;
}
uint64_t SYSTEM_get_stickfreq()
{
return the_arch.stick_freq;
}
uint64_t SYSTEM_get_cpufreq()
{
return the_arch.cpu_freq;
}
const char* SYSTEM_get_mmutypeS()
{
return the_arch.mmutype;
}
const char* SYSTEM_get_cputypeS()
{
return the_arch.mmutype;
}
int SYSTEM_get_tlbsize()
{
return the_arch.tlbsize;
}
const char* SYSTEM_get_infostr ()
{
return BLAZEVERSION_STRING;
}
char * SYSTEM_get_version ()
{
return (char*)BLAZEVERSION_STRING;
}
uint32_t SYSTEM_get_ncpu ()
{
return the_arch.numcpus;
}
uint32_t SYSTEM_get_ncores()
{
// this function is invoked in rs2blaze, do not remove it
// unless the caller in rs2blaze is modified accordingly.
if (the_arch.cmp_mode) {
return the_arch.numcores;
}
else {
ui->warning("SYSTEM_get_ncores call invalid unless in cmp_mode\n");
return 0;
//assert(0); // DEVENDRA commented this out
}
}
int SYSTEM_get_cpus_per_thread ()
{
return the_arch.cpus_per_thread;
}
int SYSTEM_get_numthreads ()
{
return the_arch.numthreads;
}
int SYSTEM_get_skipmp ()
{
return the_arch.skip_mp;
}
int SYSTEM_get_blockmp ()
{
return the_arch.block_mp;
}
bool_t SYSTEM_get_ce_enable_flag ()
{
return ce_enable_flag;
}
void SYSTEM_set_ce_enable_flag (bool_t flag)
{
ce_enable_flag = flag;
}
bool_t SYSTEM_get_scsi_disk_enable_flag ()
{
return scsi_disk_enable_flag;
}
void SYSTEM_set_scsi_disk_enable_flag (bool_t flag)
{
scsi_disk_enable_flag = flag;
}
bool_t SYSTEM_get_scsi_boot_enable_flag ()
{
return scsi_boot_enable_flag;
}
void SYSTEM_set_scsi_boot_enable_flag (bool_t flag)
{
scsi_boot_enable_flag = flag;
}
// to enable boot from any schizo and bus
void SYSTEM_set_boot_aid_bus(unsigned char aid, unsigned char bus)
{
scsi_boot_enable_flag += (bus << 7) | (aid << 4);
}
bool_t SYSTEM_get_fc_disk_enable_flag ()
{
return fc_disk_enable_flag;
}
void SYSTEM_set_fc_disk_enable_flag (bool_t flag)
{
fc_disk_enable_flag = flag;
}
bool_t SYSTEM_get_fc_boot_enable_flag ()
{
return fc_boot_enable_flag;
}
void SYSTEM_set_fc_boot_enable_flag (bool_t flag)
{
fc_boot_enable_flag = flag;
}
bool_t SYSTEM_is_serengeti()
{
if (the_arch.platform == NULL)
return FALSE;
if (strcmp (the_arch.platform, "SUNW,Sun-Fire") == NULL)
return TRUE;
else
return FALSE;
}
bool_t SYSTEM_is_480R()
{
if (the_arch.platform == NULL)
return FALSE;
if(strcmp (the_arch.platform, "SUNW,Sun-Fire-480R") == NULL)
return TRUE;
else
return FALSE;
}
// ========================================================================== }
// ============================================================================
//
// HOSTCONFIG property lookup table
//
// at the moment this is simply {"name", "value"} pairs, there is not yet
// any "name.subname.subsubname.etc..." convention,
//
// also note that the caller must ensure the strings are in stable memory,
// here we only save pointers...
//
#include <map> // Oh No Mr Bill,... STL ...!!!...
#if 1
class str_less : public std::binary_function<const char*A, const char*B, bool> {
public:
bool operator () (const char * A, const char * B) const {
return strcmp (A, B) < 0;
}
};
typedef std::map<const char *, const char *, str_less> Dictionary;
#else
class str_less : public std::binary_function <const char* _x, const char* _y, bool> {
public:
bool operator () (const char* _x, const char* _y) const {
return (strcmp (_x, _y) < 0);
}
};
typedef std::map<const char*, key, str_less> Dictionary;
#endif
Dictionary *hostconfig;
bool_t SYSTEM_isset_hostconfig (const char * configname)
{
if(!hostconfig){
hostconfig = new Dictionary;
}
return hostconfig->count(configname) != 0;
}
// returns config-value, given config-name, simple dictionary/map lookup.
const char * SYSTEM_get_hostconfig (const char * configname)
{
if(!hostconfig){
hostconfig = new Dictionary;
}
if (hostconfig->count (configname) != 0) {
return (*hostconfig)[ configname ];
} else
return NULL;
}
// used by ... to initially record the hostconfig info
void SYSTEM_set_hostconfig (const char * configname, const char * configvalue)
{
if(!hostconfig){
hostconfig = new Dictionary;
}
(*hostconfig)[ configname ] = configvalue;
}
// ... later ...
void SYSTEM_dump_hostconfig (FILE * f)
{
}
void SYSTEM_set_goodtrap_pc(uint64_t pc_va) {
goodtrap_pc = pc_va;
}
uint64_t SYSTEM_get_goodtrap_pc() {
return goodtrap_pc;
}
void SYSTEM_set_badtrap_pc(uint64_t pc_va) {
badtrap_pc = pc_va;
}
uint64_t SYSTEM_get_badtrap_pc() {
return badtrap_pc;
}
// used when restore from v4 and translate delaycount into usecs.
sint64_t SYSTEM_Sticks2usecs (sint64_t sticks)
{
/*
* Time is by definition equal to (sticks / stick_frequency).
*/
return (sint64_t)((double)sticks / ((double)SYSTEM_get_stickfreq()/1000000.0));
}
// used when restore from v4 and translate delaycount from cycles into usecs.
sint64_t SYSTEM_Ticks2usecs (sint64_t ticks)
{
/*
* Warning, ticks can be unreliable.
* Blaze re-computes ticks every time the user changes loopticks, or stickincr.
*/
return (sint64_t)((double)ticks
* ((double)SYSTEM_get_stickincr() / SYSTEM_get_loopticks())
/ ((double)SYSTEM_get_stickfreq() / 1000000.0));
}
/* -oOo-. */