Line 36... |
Line 36... |
|
|
#include "Or1200MonitorSC.h"
|
#include "Or1200MonitorSC.h"
|
#include "OrpsocMain.h"
|
#include "OrpsocMain.h"
|
|
|
#include <errno.h>
|
#include <errno.h>
|
int monitor_to_gdb_pipe[2][2]; // [0][] - monitor to gdb, [1][] - gdb to monitor, [][0] - read, [][1] - write
|
int monitor_to_gdb_pipe[2][2]; // [0][] - monitor to gdb, [1][] - gdb to
|
|
// monitor, [][0] - read, [][1] - write
|
|
|
SC_HAS_PROCESS( Or1200MonitorSC );
|
SC_HAS_PROCESS( Or1200MonitorSC );
|
|
|
//! Constructor for the OpenRISC 1200 monitor
|
//! Constructor for the OpenRISC 1200 monitor
|
|
|
Line 49... |
Line 50... |
|
|
Or1200MonitorSC::Or1200MonitorSC (sc_core::sc_module_name name,
|
Or1200MonitorSC::Or1200MonitorSC (sc_core::sc_module_name name,
|
OrpsocAccess *_accessor,
|
OrpsocAccess *_accessor,
|
MemoryLoad *_memoryload,
|
MemoryLoad *_memoryload,
|
int argc,
|
int argc,
|
char *argv[]) :
|
char *argv[]):sc_module(name),
|
sc_module (name),
|
accessor(_accessor), memoryload(_memoryload)
|
accessor (_accessor),
|
|
memoryload(_memoryload)
|
|
{
|
{
|
|
|
|
/* Assign defaults */
|
string logfileDefault(DEFAULT_EXEC_LOG_FILE);
|
string logfileDefault(DEFAULT_EXEC_LOG_FILE);
|
string logfileNameString;
|
string logfileNameString;
|
|
trace_enabled = false;
|
logging_enabled = false;
|
logging_enabled = false;
|
logfile_name_provided = false;
|
logfile_name_provided = false;
|
profiling_enabled = false;
|
profiling_enabled = false;
|
string profileFileName(DEFAULT_PROF_FILE);
|
string profileFileName(DEFAULT_PROF_FILE);
|
memdumpFileName = (DEFAULT_MEMDUMP_FILE);
|
memdumpFileName = (DEFAULT_MEMDUMP_FILE);
|
int memdump_start = 0; int memdump_end = 0;
|
int memdump_start = -1;
|
|
int memdump_end = -1;
|
do_memdump = false; // Default is not to do a dump of RAM at finish
|
do_memdump = false; // Default is not to do a dump of RAM at finish
|
logging_regs = true; // Execution log includes register values by default
|
logging_regs = true; // Execution log has GPR values by default
|
bool rsp_server_enabled = false;
|
bool rsp_server_enabled = false;
|
wait_for_stall_cmd_response = false; // Default
|
wait_for_stall_cmd_response = false; // Default
|
insn_count = insn_count_rst = 0;
|
insn_count = insn_count_rst = 0;
|
cycle_count = cycle_count_rst = 0;
|
cycle_count = cycle_count_rst = 0;
|
|
|
quiet = false;
|
perf_summary = false;
|
monitor_for_crash = false;
|
monitor_for_crash = false;
|
lookslikewevecrashed_count = crash_monitor_buffer_head = 0;
|
lookslikewevecrashed_count = crash_monitor_buffer_head = 0;
|
|
|
bus_trans_log_enabled = bus_trans_log_name_provided =
|
bus_trans_log_enabled = bus_trans_log_name_provided = bus_trans_log_start_delay_enable = false; // Default
|
bus_trans_log_start_delay_enable = false; // Default
|
|
string bus_trans_default_log_name(DEFAULT_BUS_LOG_FILE);
|
string bus_trans_default_log_name(DEFAULT_BUS_LOG_FILE);
|
string bus_trans_log_file;
|
string bus_trans_log_file;
|
|
|
// Parse the command line options
|
// Parse the command line options
|
bool cmdline_name_found = false;
|
bool cmdline_name_found = false;
|
if (argc > 1)
|
|
{
|
/* Search through the command line parameters for the "-log" option */
|
// Search through the command line parameters for the "-log" option
|
for (int i = 1; i < argc && argc > 1; i++) {
|
for(int i=1; i < argc; i++)
|
|
{
|
|
if ((strcmp(argv[i], "-l")==0) ||
|
if ((strcmp(argv[i], "-l")==0) ||
|
(strcmp(argv[i], "--log")==0))
|
(strcmp(argv[i], "--log") == 0)) {
|
{
|
|
logging_enabled = true;
|
logging_enabled = true;
|
binary_log_format = false;
|
binary_log_format = false;
|
if (i+1 < argc)
|
if (i+1 < argc)
|
if(argv[i+1][0] != '-')
|
if (argv[i + 1][0] != '-') {
|
{
|
|
logfileNameString = (argv[i+1]);
|
logfileNameString = (argv[i+1]);
|
logfile_name_provided = true;
|
logfile_name_provided = true;
|
}
|
}
|
if (!logfile_name_provided)
|
if (!logfile_name_provided)
|
logfileNameString = logfileDefault;
|
logfileNameString = logfileDefault;
|
}
|
} else if ((strcmp(argv[i], "--log-noregs") == 0)) {
|
else if ((strcmp(argv[i], "--log-noregs")==0))
|
|
{
|
|
logging_regs = false;
|
logging_regs = false;
|
}
|
} else if ((strcmp(argv[i], "--trace") == 0)) {
|
else if ((strcmp(argv[i], "-b")==0) ||
|
trace_enabled = true;
|
(strcmp(argv[i], "--binlog")==0))
|
|
{
|
} else if ((strcmp(argv[i], "-b") == 0) ||
|
|
(strcmp(argv[i], "--binlog") == 0)) {
|
logging_enabled = true;
|
logging_enabled = true;
|
binary_log_format = true;
|
binary_log_format = true;
|
if (i+1 < argc)
|
if (i+1 < argc)
|
if(argv[i+1][0] != '-')
|
if (argv[i + 1][0] != '-') {
|
{
|
|
logfileNameString = (argv[i+1]);
|
logfileNameString = (argv[i+1]);
|
logfile_name_provided = true;
|
logfile_name_provided = true;
|
}
|
}
|
if (!logfile_name_provided)
|
if (!logfile_name_provided)
|
logfileNameString = logfileDefault;
|
logfileNameString = logfileDefault;
|
|
|
}
|
} else if ((strcmp(argv[i], "-c") == 0) ||
|
else if ((strcmp(argv[i], "-c")==0) ||
|
(strcmp(argv[i], "--crash-monitor") == 0)) {
|
(strcmp(argv[i], "--crash-monitor")==0))
|
|
{
|
|
monitor_for_crash = true;
|
monitor_for_crash = true;
|
}
|
} else if ((strcmp(argv[i], "-u") == 0) ||
|
else if ((strcmp(argv[i], "-q")==0) ||
|
(strcmp(argv[i], "--summary") == 0)) {
|
(strcmp(argv[i], "--quiet")==0))
|
perf_summary = true;
|
{
|
} else if ((strcmp(argv[i], "-p") == 0) ||
|
quiet = true;
|
(strcmp(argv[i], "--profile") == 0)) {
|
}
|
|
else if ((strcmp(argv[i], "-p")==0) ||
|
|
(strcmp(argv[i], "--profile")==0))
|
|
{
|
|
profiling_enabled = true;
|
profiling_enabled = true;
|
// Check for !end of command line and that next thing is not a
|
// Check for !end of command line and that
|
// command
|
// next thing is not a command
|
if ((i+1 < argc)){
|
if ((i+1 < argc)){
|
if(argv[i+1][0] != '-')
|
if(argv[i+1][0] != '-')
|
profileFileName = (argv[i+1]);
|
profileFileName = (argv[i+1]);
|
}
|
}
|
}
|
} else if ((strcmp(argv[i], "-r") == 0) ||
|
else if ( (strcmp(argv[i], "-r")==0) ||
|
(strcmp(argv[i], "--rsp") == 0)) {
|
(strcmp(argv[i], "--rsp")==0) )
|
|
{
|
|
// We need to detect this here too
|
// We need to detect this here too
|
rsp_server_enabled = true;
|
rsp_server_enabled = true;
|
}
|
}
|
|
|
else if ((strcmp(argv[i], "-m")==0) ||
|
else if ((strcmp(argv[i], "-m")==0) ||
|
(strcmp(argv[i], "--memdump")==0))
|
(strcmp(argv[i], "--memdump") == 0)) {
|
{
|
|
do_memdump = true;
|
do_memdump = true;
|
// Check for !end of command line and that next thing is not a
|
/* Check for !end of command line and that next thing
|
// command or a memory address
|
is not a command or a memory address.
|
if (i+1 < argc)
|
*/
|
{
|
if (i + 1 < argc) {
|
if((argv[i+1][0] != '-') && (strncmp("0x", argv[i+1],2) != 0))
|
if ((argv[i + 1][0] != '-')
|
{
|
&& (strncmp("0x", argv[i + 1], 2) != 0)) {
|
// Hopefully this is the filename we want to use.
|
/* Hopefully this is the filename we
|
// All addresses should have preceeding hex identifier 0x
|
want to use. All addresses should
|
|
have preceeding hex identifier 0x
|
|
*/
|
memdumpFileName = argv[i+1];
|
memdumpFileName = argv[i+1];
|
// We've used this next index, can safely increment i
|
/* We've used this next index, can
|
|
safely increment i
|
|
*/
|
i++;
|
i++;
|
}
|
}
|
}
|
}
|
if (i+1 < argc)
|
if (i + 1 < argc) {
|
{
|
if ((argv[i + 1][0] != '-')
|
if((argv[i+1][0] != '-') && (strncmp("0x", argv[i+1],2) == 0))
|
&& (strncmp("0x", argv[i + 1], 2) == 0)) {
|
{
|
sscanf(argv[i + 1], "0x%x",
|
// Hopefully this is is the start address
|
&memdump_start);
|
// All addresses should have preceeding hex identifier 0x
|
|
sscanf( argv[i+1], "0x%x", &memdump_start);
|
|
i++;
|
i++;
|
}
|
}
|
}
|
}
|
if (i+1 < argc)
|
if (i + 1 < argc) {
|
{
|
if ((argv[i + 1][0] != '-')
|
if((argv[i+1][0] != '-') && (strncmp("0x", argv[i+1],2) == 0))
|
&& (strncmp("0x", argv[i + 1], 2) == 0)) {
|
{
|
sscanf(argv[i + 1], "0x%x",
|
// Hopefully this is is the end address
|
&memdump_end);
|
// All addresses should have preceeding hex identifier 0x
|
|
sscanf( argv[i+1], "0x%x", &memdump_end);
|
|
i++;
|
i++;
|
}
|
}
|
}
|
}
|
}
|
}
|
/*
|
#if 0
|
else if ((strcmp(argv[i], "-u")==0) ||
|
else if ((strcmp(argv[i], "-u") == 0) ||
|
(strcmp(argv[i], "--bus-log")==0))
|
(strcmp(argv[i], "--bus-log") == 0)) {
|
{
|
bus_trans_log_enabled = true;
|
bus_trans_log_enabled = true;
|
if (i + 1 < argc)
|
if (i+1 < argc)
|
if (argv[i + 1][0] != '-') {
|
if(argv[i+1][0] != '-')
|
bus_trans_log_file = (argv[i + 1]);
|
{
|
bus_trans_log_name_provided = true;
|
bus_trans_log_file = (argv[i+1]);
|
}
|
bus_trans_log_name_provided = true;
|
|
}
|
if (!bus_trans_log_name_provided)
|
|
bus_trans_log_file = bus_trans_default_log_name;
|
if (!bus_trans_log_name_provided)
|
|
bus_trans_log_file = bus_trans_default_log_name;
|
/* check for a log start delay */
|
|
if (i + 2 < argc)
|
// check for a log start delay
|
if (argv[i + 2][0] != '-') {
|
if (i+2 < argc)
|
/* We have a bus transaction log start
|
if(argv[i+2][0] != '-')
|
delay */
|
{
|
bus_trans_log_start_delay_enable = true;
|
// We have a bus transaction log start delay
|
int time_val = atoi(argv[i + 2]);
|
bus_trans_log_start_delay_enable = true;
|
sc_time log_start_time(time_val, SC_NS);
|
int time_val = atoi(argv[i+2]);
|
bus_trans_log_start_delay =
|
sc_time log_start_time(time_val,SC_NS);
|
log_start_time;
|
bus_trans_log_start_delay = log_start_time;
|
|
}
|
|
}
|
|
*/
|
|
}
|
}
|
}
|
}
|
|
#endif
|
|
|
|
}
|
|
|
if (!rsp_server_enabled)
|
if (!rsp_server_enabled) {
|
{
|
|
monitor_to_gdb_pipe[0][0] = monitor_to_gdb_pipe[0][1] = NULL;
|
monitor_to_gdb_pipe[0][0] = monitor_to_gdb_pipe[0][1] = NULL;
|
monitor_to_gdb_pipe[1][0] = monitor_to_gdb_pipe[1][1] = NULL;
|
monitor_to_gdb_pipe[1][0] = monitor_to_gdb_pipe[1][1] = NULL;
|
}
|
}
|
|
/* checkInstruction monitors the bus for special NOP instructionsl */
|
|
|
// checkInstruction monitors the bus for special NOP instructionsl
|
|
SC_METHOD (checkInstruction);
|
SC_METHOD (checkInstruction);
|
sensitive << clk.pos();
|
sensitive << clk.pos();
|
dont_initialize();
|
dont_initialize();
|
|
|
|
if (profiling_enabled) {
|
if (profiling_enabled)
|
// Open profiling log file
|
{
|
profileFile.open(profileFileName.c_str(), ios::out);
|
|
if (profileFile.is_open()) {
|
profileFile.open(profileFileName.c_str(), ios::out); // Open profiling log file
|
/* If the file was opened OK, then enabled logging and
|
if(profileFile.is_open())
|
print a message.
|
{
|
*/
|
// If the file was opened OK, then enabled logging and print a message.
|
|
profiling_enabled = true;
|
profiling_enabled = true;
|
cout << "* Execution profiling enabled. Logging to " << profileFileName << endl;
|
cout << "* Execution profiling enabled. Logging to " <<
|
|
profileFileName << endl;
|
}
|
}
|
|
|
// Setup profiling function
|
// Setup profiling function
|
SC_METHOD (callLog);
|
SC_METHOD (callLog);
|
sensitive << clk.pos();
|
sensitive << clk.pos();
|
dont_initialize();
|
dont_initialize();
|
start = clock();
|
|
}
|
}
|
|
|
if(logging_enabled)
|
if (logging_enabled) {
|
{
|
|
|
|
/* Now open the file */
|
/* Now open the file */
|
if (binary_log_format)
|
if (binary_log_format)
|
statusFile.open(logfileNameString.c_str(), ios::out | ios::binary);
|
statusFile.open(logfileNameString.c_str(),
|
|
ios::out | ios::binary);
|
else
|
else
|
statusFile.open(logfileNameString.c_str(), ios::out );
|
statusFile.open(logfileNameString.c_str(), ios::out );
|
|
|
/* Check the open() */
|
/* Check the open() */
|
if(statusFile.is_open() && binary_log_format)
|
if (statusFile.is_open() && binary_log_format) {
|
{
|
cout <<
|
cout << "* Processor execution logged in binary format to file: " << logfileNameString << endl;
|
"* Processor execution logged in binary format to file: "
|
/* Write out a byte indicating whether there's register values too */
|
<< logfileNameString << endl;
|
|
/* Write out a byte indicating whether there's register
|
|
values too
|
|
*/
|
statusFile.write((char*)&logging_regs, 1);
|
statusFile.write((char*)&logging_regs, 1);
|
|
|
}
|
} else if (statusFile.is_open() && !binary_log_format)
|
else if (statusFile.is_open() && !binary_log_format)
|
cout << "* Processor execution logged to file: " <<
|
cout << "* Processor execution logged to file: " << logfileNameString << endl;
|
logfileNameString << endl;
|
else
|
else
|
/* Couldn't open */
|
/* Couldn't open */
|
logging_enabled = false;
|
logging_enabled = false;
|
|
|
}
|
}
|
|
|
if (logging_enabled)
|
if (logging_enabled) {
|
{
|
if (binary_log_format) {
|
if (binary_log_format)
|
|
{
|
|
SC_METHOD (displayStateBinary);
|
SC_METHOD (displayStateBinary);
|
}
|
} else {
|
else
|
|
{
|
|
SC_METHOD (displayState);
|
SC_METHOD (displayState);
|
}
|
}
|
sensitive << clk.pos();
|
sensitive << clk.pos();
|
dont_initialize();
|
dont_initialize();
|
start = clock();
|
start = clock();
|
|
|
}
|
}
|
|
|
if (monitor_for_crash)
|
if (monitor_for_crash) {
|
{
|
|
cout << "* Crash monitor enabled" << endl;
|
cout << "* Crash monitor enabled" << endl;
|
}
|
}
|
|
|
// Check sizes we were given from memory dump command line options first
|
if (do_memdump) {
|
if (do_memdump)
|
// Were we given dump addresses? If not, we dump all of the
|
{
|
// memory. Size of memory isn't clearly defined in any one
|
if ((memdump_start > ORPSOC_SRAM_SIZE) || (memdump_end > ORPSOC_SRAM_SIZE) ||
|
// place. This could lead to big problems when changing size of
|
((memdump_start > memdump_end) && (memdump_end != 0)))
|
// the RAM in simulation.
|
{
|
|
do_memdump = false;
|
|
cout << "* Memory dump addresses range incorrect. Limit of memory is 0x" << hex << ORPSOC_SRAM_SIZE << ". Memory dumping disabled." << endl;
|
|
}
|
|
}
|
|
|
|
if (do_memdump)
|
|
{
|
|
// Were we given dump addresses? If not, we dump all of the memory
|
|
// Size of memory isn't clearly defined in any one place. This could lead to
|
|
// big problems when changing size of the RAM in simulation.
|
|
|
|
if (memdump_start == 0 && memdump_end == 0)
|
/* No memory dump beginning specified. Set to zero. */
|
memdump_end = ORPSOC_SRAM_SIZE;
|
if (memdump_start == -1)
|
|
|
if (memdump_start != 0 && memdump_end == 0)
|
|
{
|
|
// Probably just got the single memorydump param
|
|
// Interpet as a length from 0
|
|
memdump_end = memdump_start;
|
|
memdump_start = 0;
|
memdump_start = 0;
|
}
|
|
|
|
if (memdump_start & 0x3) memdump_start &= ~0x3; // word-align the start address
|
/* No dump end specified, assign some token amount, probably
|
if (memdump_end & 0x3) memdump_end = (memdump_end+4) & ~0x3; // word-align the start address
|
useless, but then the user should have specified more. */
|
|
if (memdump_end == -1)
|
|
memdump_end = memdump_start + 0x2000;
|
|
|
|
if (memdump_start & 0x3)
|
|
memdump_start &= ~0x3; // word-align the start address
|
|
if (memdump_end & 0x3)
|
|
memdump_end = (memdump_end + 4) & ~0x3; // word-align the start address
|
|
|
memdump_start_addr = memdump_start;
|
memdump_start_addr = memdump_start;
|
memdump_end_addr = memdump_end;
|
memdump_end_addr = memdump_end;
|
}
|
}
|
|
#if 0
|
|
if (bus_trans_log_enabled) {
|
|
// Setup log file and register the bus monitoring function
|
|
busTransLog.open(bus_trans_log_file.c_str(), ios::out);
|
|
|
|
if (busTransLog.is_open()) {
|
|
cout << "* System bus transactions logged to file: " <<
|
|
bus_trans_log_file;
|
|
|
|
if (bus_trans_log_start_delay_enable)
|
|
cout << ", on at " <<
|
|
bus_trans_log_start_delay.to_string();
|
|
cout << endl;
|
|
} else
|
|
// Couldn't open
|
|
bus_trans_log_enabled = false;
|
|
}
|
|
|
/*
|
if (bus_trans_log_enabled) {
|
if (bus_trans_log_enabled)
|
// Setup profiling function
|
{
|
SC_METHOD(busMonitor);
|
// Setup log file and register the bus monitoring function
|
sensitive << clk.pos();
|
busTransLog.open(bus_trans_log_file.c_str(), ios::out );
|
dont_initialize();
|
|
}
|
if (busTransLog.is_open())
|
#endif
|
{
|
|
cout << "* System bus transactions logged to file: " <<
|
|
bus_trans_log_file;
|
|
|
|
if (bus_trans_log_start_delay_enable)
|
|
cout << ", on at " << bus_trans_log_start_delay.to_string();
|
|
cout << endl;
|
|
}
|
|
else
|
|
// Couldn't open
|
|
bus_trans_log_enabled = false;
|
|
}
|
|
|
|
|
|
if (bus_trans_log_enabled)
|
// Record roughly when we begin execution
|
{
|
start = clock();
|
// Setup profiling function
|
|
SC_METHOD (busMonitor);
|
|
sensitive << clk.pos();
|
|
dont_initialize();
|
|
}
|
|
*/
|
|
|
|
} // Or1200MonitorSC ()
|
} // Or1200MonitorSC ()
|
|
|
//! Print usage for the options of this module
|
//! Print usage for the options of this module
|
void
|
void
|
Or1200MonitorSC::printUsage()
|
Or1200MonitorSC::printUsage()
|
{
|
{
|
printf("\nLogging and diagnostic options:\n");
|
printf("\nLogging and diagnostic options:\n");
|
printf(" -p, --profile [<file>]Enable execution profiling output to <file> (default is\n\t\t\t"DEFAULT_PROF_FILE")\n");
|
printf(" --trace\t\tEnable an execution trace to stdout during simulation\n");
|
|
printf(" -u, --summary\t\tEnable summary on exit\n");
|
|
printf
|
|
(" -p, --profile [<file>]\n\t\t\tEnable execution profiling output to <file> (default is\n\t\t\t"
|
|
DEFAULT_PROF_FILE ")\n");
|
printf(" -l, --log <file>\tLog processor execution to <file>\n");
|
printf(" -l, --log <file>\tLog processor execution to <file>\n");
|
printf(" --log-noregs\tLog excludes register contents\n");
|
printf(" --log-noregs\tLog excludes register contents\n");
|
|
|
printf(" -b, --binlog <file>\tGenerate binary format execution log (faster, smaller)\n");
|
printf
|
|
(" -b, --binlog <file>\tGenerate binary format execution log (faster, smaller)\n");
|
|
|
printf(" -m, --memdump <file> <0xstartaddr> <0xendaddr>\n\t\t\tDump data between <0xstartaddr> and <0xendaddr> from\n\t\t\tthe system's RAM to <file> in binary format on exit\n");
|
printf
|
printf(" -c, --crash-monitor\tDetect when the processor has crashed and exit\n");
|
(" -m, --memdump <file> <0xstartaddr> <0xendaddr>\n\t\t\tDump data between <0xstartaddr> and <0xendaddr> from\n\t\t\tthe system's RAM to <file> in binary format on exit\n");
|
|
printf
|
|
(" -c, --crash-monitor\tDetect when the processor has crashed and exit\n");
|
/*
|
/*
|
printf(" -u, --bus-log <file> <val>\n\t\t\tLog the wishbone bus transactions to <file>, opt. start\n\t\t\tafter <val> ns\n\n");
|
printf(" -u, --bus-log <file> <val>\n\t\t\tLog the wishbone bus transactions to <file>, opt. start\n\t\t\tafter <val> ns\n\n");
|
*/
|
*/
|
|
|
}
|
}
|
Line 388... |
Line 360... |
//! - l.nop 1 Terminate the program
|
//! - l.nop 1 Terminate the program
|
//! - l.nop 2 Report the value in R3
|
//! - l.nop 2 Report the value in R3
|
//! - l.nop 3 Printf the string with the arguments in R3, etc
|
//! - l.nop 3 Printf the string with the arguments in R3, etc
|
//! - l.nop 4 Print a character
|
//! - l.nop 4 Print a character
|
|
|
//#define OR1200_OR32_NOP_BITS_31_TO_26 6'b000101
|
#define OR1200_OR32_NOP_INSN_TOP_BYTE 0x15
|
#define OR1200_OR32_NOP 0x14000000
|
#define OR1200_OR32_NOP 0x14000000
|
|
|
extern int SIM_RUNNING;
|
|
void
|
void
|
Or1200MonitorSC::checkInstruction()
|
Or1200MonitorSC::checkInstruction()
|
{
|
{
|
uint32_t r3;
|
uint32_t r3;
|
double ts;
|
double ts;
|
uint32_t current_WbInsn, current_WbPC;
|
uint32_t currentWbInsn, currentWbPC;
|
|
clock_t now;
|
|
double elapsedTime;
|
|
int hertz, khertz;
|
|
unsigned long long int psPeriod;
|
|
char insnMSByte;
|
|
uint32_t insnImm;
|
|
|
cycle_count++;
|
cycle_count++;
|
|
|
/* Check if this counts as an "executed" instruction */
|
/* Check if this counts as an "executed" instruction */
|
if (!accessor->getWbFreeze())
|
if (!accessor->getWbFreeze()) {
|
|
// Memory writeback stage instruction
|
|
currentWbInsn = accessor->getWbInsn();
|
|
|
|
if (((((currentWbInsn & 0xfc000000) !=
|
|
(uint32_t) OR1200_OR32_NOP)
|
|
|| !(currentWbInsn & (1 << 16)))
|
|
&& !(accessor->getExceptFlushpipe()
|
|
&& accessor->getExDslot())) ||
|
|
// Exception version
|
|
accessor->getExceptFlushpipe())
|
{
|
{
|
// Cache writeback stage instruction
|
|
current_WbInsn = accessor->getWbInsn();
|
|
|
|
if ((((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
|
|
insn_count++;
|
|
else
|
|
// Exception version
|
|
if (accessor->getExceptFlushpipe())
|
|
insn_count++;
|
insn_count++;
|
|
if (trace_enabled)
|
|
printTrace();
|
}
|
}
|
|
|
|
}
|
// Check the instruction when the freeze signal is low.
|
// Check the instruction when the freeze signal is low.
|
if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0))
|
if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0)) {
|
|
// Extract MSB of instruction
|
|
insnMSByte = (currentWbInsn >> 24) & 0xff;
|
|
|
|
if (insnMSByte == OR1200_OR32_NOP_INSN_TOP_BYTE)
|
{
|
{
|
|
insnImm = currentWbInsn & 0xffff;
|
|
|
// Do something if we have l.nop
|
// Do something if we have l.nop
|
switch (current_WbInsn)
|
switch (insnImm) {
|
{
|
|
case NOP_EXIT:
|
case NOP_EXIT:
|
r3 = accessor->getGpr (3);
|
r3 = accessor->getGpr (3);
|
if (!quiet)
|
/* No timestamp with reports, so exit report is
|
{
|
same format as from or1ksim */
|
ts = sc_time_stamp().to_seconds() * 1000000000.0;
|
/*
|
std::cout << std::fixed << std::setprecision (2) << ts;
|
ts = sc_time_stamp().to_seconds() *
|
std::cout << " ns: Exiting (" << r3 << ")" << std::endl;
|
1000000000.0;
|
|
std::cout << std::fixed << std::
|
|
setprecision(2) << ts;
|
|
*/
|
|
std::
|
|
cout << "exit(" << r3 << ")" <<
|
|
std::endl;
|
|
if (perf_summary)
|
perfSummary();
|
perfSummary();
|
}
|
|
if (logging_enabled) statusFile.close();
|
if (logging_enabled)
|
if (profiling_enabled) profileFile.close();
|
statusFile.close();
|
if (bus_trans_log_enabled) busTransLog.close();
|
if (profiling_enabled)
|
|
profileFile.close();
|
|
if (bus_trans_log_enabled)
|
|
busTransLog.close();
|
memdump();
|
memdump();
|
SIM_RUNNING=0;
|
gSimRunning = 0;
|
sc_stop();
|
sc_stop();
|
break;
|
break;
|
|
|
case NOP_REPORT:
|
case NOP_REPORT:
|
if (!quiet)
|
/* No timestamp with reports, so reports are
|
{
|
same format as from or1ksim */
|
ts = sc_time_stamp().to_seconds() * 1000000000.0;
|
/*
|
|
ts = sc_time_stamp().to_seconds() *
|
|
1000000000.0;
|
|
|
|
std::cout << std::fixed << std::
|
|
setprecision(2) << ts;
|
|
*/
|
r3 = accessor->getGpr (3);
|
r3 = accessor->getGpr (3);
|
std::cout << std::fixed << std::setprecision (2) << ts;
|
std::cout << "report(0x" <<
|
std::cout << " ns: report (" << hex << r3 << ")" << std::endl;
|
std::setfill('0') << hex <<
|
}
|
std::setw(8) << r3 << ");" << std::endl;
|
break;
|
break;
|
|
|
case NOP_PRINTF:
|
case NOP_PRINTF:
|
ts = sc_time_stamp().to_seconds() * 1000000000.0;
|
/*
|
std::cout << std::fixed << std::setprecision (2) << ts;
|
ts = sc_time_stamp().to_seconds() * 1000000000.0;
|
std::cout << " ns: printf: ";
|
std::cout << std::fixed << std::setprecision(2) << ts;
|
|
*/
|
|
std::cout << "printf: ";
|
simPrintf(accessor->getGpr (4), accessor->getGpr (3));
|
simPrintf(accessor->getGpr (4), accessor->getGpr (3));
|
break;
|
break;
|
|
|
case NOP_PUTC:
|
case NOP_PUTC:
|
r3 = accessor->getGpr (3);
|
r3 = accessor->getGpr (3);
|
std::cout << (char)r3 << std::flush;
|
std::cout << (char)r3 << std::flush;
|
break;
|
break;
|
|
|
|
case NOP_GET_TICKS:
|
|
// Put number of cycles so far into r11 and r12
|
|
accessor->setGpr(11, (uint32_t) cycle_count&0xffffffff);
|
|
accessor->setGpr(12, (uint32_t) (cycle_count >> 32) &
|
|
0xffffffff);
|
|
/*
|
|
std::cout << "NOP_GET_TICKS: " << dec << cycle_count <<
|
|
" r11:" << dec << accessor->getGpr(11) <<
|
|
" r12:" << dec << accessor->getGpr(12) <<
|
|
std::endl;
|
|
*/
|
|
break;
|
|
case NOP_GET_PS:
|
|
// Put PS/cycle into r11
|
|
now = clock();
|
|
elapsedTime =
|
|
(double (now) - double (start))/CLOCKS_PER_SEC;
|
|
|
|
// Calculate execution rate so far
|
|
khertz = (int)((cycle_count / elapsedTime) / 1000);
|
|
|
|
psPeriod
|
|
= (((unsigned long long int) 1000000000) /
|
|
(unsigned long long int ) khertz);
|
|
|
|
accessor->setGpr(11, (uint32_t) psPeriod);
|
|
|
|
/*
|
|
std::cout << "NOP_GET_PS: khertz: " << dec << khertz <<
|
|
" r11:" << dec << accessor->getGpr(11) <<
|
|
endl;
|
|
*/
|
|
break;
|
|
|
case NOP_CNT_RESET:
|
case NOP_CNT_RESET:
|
if (!quiet)
|
if (!gQuiet) {
|
{
|
std::cout <<
|
std::cout << "****************** counters reset ******************" << endl;
|
"****************** counters reset ******************"
|
std::cout << "since last reset: cycles " << cycle_count - cycle_count_rst << ", insn #" << insn_count - insn_count_rst << endl;
|
<< endl;
|
std::cout << "****************** counters reset ******************" << endl;
|
std::cout << "since last reset: cycles " <<
|
|
cycle_count -
|
|
cycle_count_rst << ", insn #" << insn_count
|
|
- insn_count_rst << endl;
|
|
std::cout <<
|
|
"****************** counters reset ******************"
|
|
<< endl;
|
cycle_count_rst = cycle_count;
|
cycle_count_rst = cycle_count;
|
insn_count_rst = insn_count;
|
insn_count_rst = insn_count;
|
/* 3 separate counters we'll use for various things */
|
/* 3 separate counters we'll use for various things */
|
}
|
}
|
case NOP_CNT_RESET1:
|
case NOP_CNT_RESET1:
|
if (!quiet)
|
if (!gQuiet) {
|
{
|
std::cout << "**** counter1 cycles: " <<
|
std::cout << "**** counter1 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_1 << " resetting ********" << endl;
|
std::setfill('0') << std::setw(10) <<
|
|
cycle_count -
|
|
cycles_1 << " resetting ********" << endl;
|
cycles_1 = cycle_count;
|
cycles_1 = cycle_count;
|
}
|
}
|
break;
|
break;
|
case NOP_CNT_RESET2:
|
case NOP_CNT_RESET2:
|
if (!quiet)
|
if (!gQuiet) {
|
{
|
std::cout << "**** counter2 cycles: " <<
|
std::cout << "**** counter2 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_2 << " resetting ********" << endl;
|
std::setfill('0') << std::setw(10) <<
|
|
cycle_count -
|
|
cycles_2 << " resetting ********" << endl;
|
cycles_2 = cycle_count;
|
cycles_2 = cycle_count;
|
}
|
}
|
break;
|
break;
|
case NOP_CNT_RESET3:
|
case NOP_CNT_RESET3:
|
if (!quiet)
|
if (!gQuiet) {
|
{
|
std::cout << "**** counter3 cycles: " <<
|
std::cout << "**** counter3 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_3 << " resetting ********" << endl;
|
std::setfill('0') << std::setw(10) <<
|
|
cycle_count -
|
|
cycles_3 << " resetting ********" << endl;
|
cycles_3 = cycle_count;
|
cycles_3 = cycle_count;
|
}
|
}
|
break;
|
break;
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
|
|
if (monitor_for_crash)
|
}
|
{
|
|
current_WbPC = accessor->getWbPC();
|
if (monitor_for_crash) {
|
|
currentWbPC = accessor->getWbPC();
|
// Look at current instruction
|
// Look at current instruction
|
if (current_WbInsn == 0x00000000)
|
if (currentWbInsn == 0x00000000) {
|
{
|
|
// Looks like we've jumped somewhere incorrectly
|
// Looks like we've jumped somewhere incorrectly
|
lookslikewevecrashed_count++;
|
lookslikewevecrashed_count++;
|
}
|
}
|
#define CRASH_MONITOR_LOG_BAD_INSNS 1
|
#define CRASH_MONITOR_LOG_BAD_INSNS 0
|
#if CRASH_MONITOR_LOG_BAD_INSNS
|
#if CRASH_MONITOR_LOG_BAD_INSNS
|
|
|
/* Log so-called "bad" instructions, or at least instructions we
|
/* Log so-called "bad" instructions, or at least instructions we
|
executed, no matter if they caused us to increment
|
executed, no matter if they caused us to increment
|
lookslikewevecrashed_count, this way we get them in our list too */
|
lookslikewevecrashed_count, this way we get them in our list too */
|
if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
|
if ((insnMSByte != OR1200_OR32_NOP_INSN_TOP_BYTE)
|
{
|
|| !(currentWbInsn & (1 << 16))) {
|
crash_monitor_buffer[crash_monitor_buffer_head][0] = current_WbPC;
|
crash_monitor_buffer[crash_monitor_buffer_head]
|
crash_monitor_buffer[crash_monitor_buffer_head][1] = current_WbInsn;
|
[0] = currentWbPC;
|
|
crash_monitor_buffer[crash_monitor_buffer_head]
|
|
[1] = currentWbInsn;
|
/* Circular buffer */
|
/* Circular buffer */
|
if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
|
if (crash_monitor_buffer_head <
|
|
CRASH_MONITOR_BUFFER_SIZE - 1)
|
crash_monitor_buffer_head++;
|
crash_monitor_buffer_head++;
|
else
|
else
|
crash_monitor_buffer_head = 0;
|
crash_monitor_buffer_head = 0;
|
|
|
}
|
}
|
|
|
#else
|
#else
|
else if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
|
else if (((insnMSByte != OR1200_OR32_NOP_INSN_TOP_BYTE))
|
{
|
|| !(currentWbInsn & (1 << 16))) {
|
|
|
crash_monitor_buffer[crash_monitor_buffer_head][0] = current_WbPC;
|
crash_monitor_buffer[crash_monitor_buffer_head]
|
crash_monitor_buffer[crash_monitor_buffer_head][1] = current_WbInsn;
|
[0] = currentWbPC;
|
|
crash_monitor_buffer[crash_monitor_buffer_head]
|
|
[1] = currentWbInsn;
|
/* Circular buffer */
|
/* Circular buffer */
|
if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
|
if (crash_monitor_buffer_head <
|
|
CRASH_MONITOR_BUFFER_SIZE - 1)
|
crash_monitor_buffer_head++;
|
crash_monitor_buffer_head++;
|
else
|
else
|
crash_monitor_buffer_head = 0;
|
crash_monitor_buffer_head = 0;
|
|
|
/* Reset this */
|
/* Reset this */
|
lookslikewevecrashed_count = 0;
|
lookslikewevecrashed_count = 0;
|
}
|
}
|
#endif
|
#endif
|
if (wait_for_stall_cmd_response)
|
if (wait_for_stall_cmd_response) {
|
{
|
|
// We've already crashed, and we're issued a command to stall the
|
// We've already crashed, and we're issued a command to stall the
|
// processor to the system C debug unit interface, and we're
|
// processor to the system C debug unit interface, and we're
|
// waiting for this debug unit to send back the message that we've
|
// waiting for this debug unit to send back the message that we've
|
// stalled.
|
// stalled.
|
char readChar;
|
char readChar;
|
int n = read(monitor_to_gdb_pipe[1][0], &readChar, sizeof(char));
|
int n =
|
if (!( ((n < 0) && (errno == EAGAIN)) || (n==0) ))
|
read(monitor_to_gdb_pipe[1][0], &readChar,
|
|
sizeof(char));
|
|
if (!(((n < 0) && (errno == EAGAIN))
|
|
|| (n == 0)))
|
wait_for_stall_cmd_response = false; // We got response
|
wait_for_stall_cmd_response = false; // We got response
|
lookslikewevecrashed_count = 0;
|
lookslikewevecrashed_count = 0;
|
|
|
}
|
} else if (lookslikewevecrashed_count > 0) {
|
else if (lookslikewevecrashed_count > 0)
|
|
{
|
|
|
|
if (lookslikewevecrashed_count >= CRASH_MONITOR_BUFFER_SIZE/4)
|
if (lookslikewevecrashed_count >=
|
{
|
CRASH_MONITOR_BUFFER_SIZE / 4) {
|
/* Probably crashed. Bail out, print out buffer */
|
/* Probably crashed. Bail out, print out buffer */
|
std::cout << "********************************************************************************"<< endl;
|
std::cout <<
|
std::cout << "* Looks like processor crashed. Printing last " << CRASH_MONITOR_BUFFER_SIZE << " instructions executed:" << endl;
|
"********************************************************************************"
|
|
<< endl;
|
int crash_monitor_buffer_head_end = (crash_monitor_buffer_head > 0) ? crash_monitor_buffer_head - 1 : CRASH_MONITOR_BUFFER_SIZE-1;
|
std::cout <<
|
while (crash_monitor_buffer_head != crash_monitor_buffer_head_end)
|
"* Looks like processor crashed. Printing last "
|
{
|
<< CRASH_MONITOR_BUFFER_SIZE <<
|
std::cout << "* PC: " << std::setfill('0') << hex << std::setw(8) << crash_monitor_buffer[crash_monitor_buffer_head][0] << " INSN: " << std::setfill('0') << hex << std::setw(8) << crash_monitor_buffer[crash_monitor_buffer_head][1] << endl;
|
" instructions executed:" << endl;
|
|
|
if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
|
int crash_monitor_buffer_head_end =
|
|
(crash_monitor_buffer_head >
|
|
0) ? crash_monitor_buffer_head -
|
|
1 : CRASH_MONITOR_BUFFER_SIZE - 1;
|
|
while (crash_monitor_buffer_head !=
|
|
crash_monitor_buffer_head_end) {
|
|
std::cout << "* PC: " <<
|
|
std::setfill('0') << hex <<
|
|
std::setw(8) <<
|
|
crash_monitor_buffer
|
|
[crash_monitor_buffer_head]
|
|
[0] << " INSN: " <<
|
|
std::setfill('0') << hex <<
|
|
std::setw(8) <<
|
|
crash_monitor_buffer
|
|
[crash_monitor_buffer_head]
|
|
[1] << endl;
|
|
|
|
if (crash_monitor_buffer_head <
|
|
CRASH_MONITOR_BUFFER_SIZE -
|
|
1)
|
crash_monitor_buffer_head++;
|
crash_monitor_buffer_head++;
|
else
|
else
|
crash_monitor_buffer_head = 0;
|
crash_monitor_buffer_head
|
|
= 0;
|
}
|
}
|
std::cout << "********************************************************************************"<< endl;
|
std::cout <<
|
|
"********************************************************************************"
|
|
<< endl;
|
|
|
if ( (monitor_to_gdb_pipe[0][0] != NULL))
|
if ((monitor_to_gdb_pipe[0][0] != NULL)) {
|
{
|
|
// If GDB server is running, we'll pass control back to
|
// If GDB server is running, we'll pass control back to
|
// the debugger instead of just quitting.
|
// the debugger instead of just quitting.
|
char interrupt = 0x3; // Arbitrary
|
char interrupt = 0x3; // Arbitrary
|
write(monitor_to_gdb_pipe[0][1],&interrupt,sizeof(char));
|
write(monitor_to_gdb_pipe[0][1],
|
wait_for_stall_cmd_response = true;
|
&interrupt, sizeof(char));
|
|
wait_for_stall_cmd_response =
|
|
true;
|
lookslikewevecrashed_count = 0;
|
lookslikewevecrashed_count = 0;
|
std::cout << "* Stalling processor and returning control to GDB"<< endl;
|
std::cout <<
|
|
"* Stalling processor and returning control to GDB"
|
|
<< endl;
|
// Problem: the debug unit interface's stalling the processor over the simulated JTAG bus takes a while, in the meantime this monitor will continue running and keep triggering the crash detection code. We must somehow wait until the processor is stalled, or circumvent this crash detection output until we detect that the processor is stalled.
|
// Problem: the debug unit interface's stalling the processor over the simulated JTAG bus takes a while, in the meantime this monitor will continue running and keep triggering the crash detection code. We must somehow wait until the processor is stalled, or circumvent this crash detection output until we detect that the processor is stalled.
|
// Solution: Added another pipe, when we want to wait for preocssor to stall, we set wait_for_stall_cmd_response=true, then each time we get back to this monitor function we simply poll the pipe until we're stalled. (A blocking read didn't work - this function never yielded and the RSP server handling function never got called).
|
// Solution: Added another pipe, when we want to wait for preocssor to stall, we set wait_for_stall_cmd_response=true, then each time we get back to this monitor function we simply poll the pipe until we're stalled. (A blocking read didn't work - this function never yielded and the RSP server handling function never got called).
|
wait_for_stall_cmd_response = true;
|
wait_for_stall_cmd_response =
|
|
true;
|
|
|
}
|
} else {
|
else
|
|
{
|
|
// Close down sim end exit
|
// Close down sim end exit
|
ts = sc_time_stamp().to_seconds() * 1000000000.0;
|
ts = sc_time_stamp().to_seconds
|
std::cout << std::fixed << std::setprecision (2) << ts;
|
() * 1000000000.0;
|
std::cout << " ns: Exiting (" << r3 << ")" << std::endl;
|
std::cout << std::fixed <<
|
|
std::setprecision(2) << ts;
|
|
std::cout << " ns: Exiting (" <<
|
|
r3 << ")" << std::endl;
|
|
if (perf_summary)
|
perfSummary();
|
perfSummary();
|
if (logging_enabled) statusFile.close();
|
if (logging_enabled)
|
if (profiling_enabled) profileFile.close();
|
statusFile.close();
|
if (bus_trans_log_enabled) busTransLog.close();
|
if (profiling_enabled)
|
|
profileFile.close();
|
|
if (bus_trans_log_enabled)
|
|
busTransLog.close();
|
memdump();
|
memdump();
|
SIM_RUNNING=0;
|
gSimRunning = 0;
|
sc_stop();
|
sc_stop();
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
} // checkInstruction()
|
} // checkInstruction()
|
|
|
|
|
//! Method to log execution in terms of calls and returns
|
//! Method to log execution in terms of calls and returns
|
|
|
void
|
void
|
Or1200MonitorSC::callLog()
|
Or1200MonitorSC::callLog()
|
{
|
{
|
Line 619... |
Line 709... |
uint32_t o_b; // operand b
|
uint32_t o_b; // operand b
|
struct label_entry *tmp;
|
struct label_entry *tmp;
|
|
|
// Instructions should be valid when freeze is low and there are no exceptions
|
// Instructions should be valid when freeze is low and there are no exceptions
|
//if (!accessor->getExFreeze())
|
//if (!accessor->getExFreeze())
|
if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0))
|
if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0)) {
|
{
|
|
//exinsn = accessor->getExInsn();// & 0x3ffffff;
|
//exinsn = accessor->getExInsn();// & 0x3ffffff;
|
exinsn = accessor->getWbInsn();
|
exinsn = accessor->getWbInsn();
|
// Check the instruction
|
// Check the instruction
|
switch((exinsn >> 26) & 0x3f) { // Check Opcode - top 6 bits
|
switch((exinsn >> 26) & 0x3f) { // Check Opcode - top 6 bits
|
case 0x1:
|
case 0x1:
|
/* Instruction: l.jal */
|
/* Instruction: l.jal */
|
o_a = (exinsn >> 0) & 0x3ffffff;
|
o_a = (exinsn >> 0) & 0x3ffffff;
|
if(o_a & 0x02000000) o_a |= 0xfe000000;
|
if (o_a & 0x02000000)
|
|
o_a |= 0xfe000000;
|
|
|
//delaypc = accessor->getExPC() + (o_a * 4); // PC we're jumping to
|
//delaypc = accessor->getExPC() + (o_a * 4); // PC we're jumping to
|
delaypc = accessor->getWbPC() + (o_a * 4); // PC we're jumping to
|
delaypc = accessor->getWbPC() + (o_a * 4); // PC we're jumping to
|
// Now we have info about where we're jumping to. Output the info, with label if possible
|
// Now we have info about where we're jumping to. Output the info, with label if possible
|
// We print the PC we're jumping from + 8 which is the return address
|
// We print the PC we're jumping from + 8 which is the return address
|
if ( tmp = memoryload->get_label (delaypc) )
|
if ( tmp = memoryload->get_label (delaypc) )
|
profileFile << "+" << std::setfill('0') << hex << std::setw(8) << cycle_count << " " << hex << std::setw(8) << accessor->getWbPC() + 8 << " " << hex << std::setw(8) << delaypc << " " << tmp->name << endl;
|
profileFile << "+" << std::setfill('0') << hex
|
|
<< std::setw(8) << cycle_count << " " << hex
|
|
<< std::setw(8) << accessor->getWbPC() +
|
|
8 << " " << hex << std::setw(8) << delaypc
|
|
<< " " << tmp->name << endl;
|
else
|
else
|
profileFile << "+" << std::setfill('0') << hex << std::setw(8) << cycle_count << " " << hex << std::setw(8) << accessor->getWbPC() + 8 << " " << hex << std::setw(8) << delaypc << " @" << hex << std::setw(8) << delaypc << endl;
|
profileFile << "+" << std::setfill('0') << hex
|
|
<< std::setw(8) << cycle_count << " " << hex
|
|
<< std::setw(8) << accessor->getWbPC() +
|
|
8 << " " << hex << std::setw(8) << delaypc
|
|
<< " @" << hex << std::setw(8) << delaypc <<
|
|
endl;
|
|
|
break;
|
break;
|
case 0x11:
|
case 0x11:
|
/* Instruction: l.jr */
|
/* Instruction: l.jr */
|
// Bits 15-11 contain register number
|
// Bits 15-11 contain register number
|
Line 649... |
Line 748... |
if (o_b == 9) // l.jr r9 is typical return
|
if (o_b == 9) // l.jr r9 is typical return
|
{
|
{
|
// Now get the value in this register
|
// Now get the value in this register
|
delaypc = accessor->getGpr(o_b);
|
delaypc = accessor->getGpr(o_b);
|
// Output this jump
|
// Output this jump
|
profileFile << "-" << std::setfill('0') << hex << std::setw(8) << cycle_count << " " << hex << std::setw(8) << delaypc << endl;
|
profileFile << "-" << std::setfill('0') << hex
|
|
<< std::setw(8) << cycle_count << " " << hex
|
|
<< std::setw(8) << delaypc << endl;
|
}
|
}
|
break;
|
break;
|
case 0x12:
|
case 0x12:
|
/* Instruction: l.jalr */
|
/* Instruction: l.jalr */
|
o_b = (exinsn >> 11) & 0x1f;
|
o_b = (exinsn >> 11) & 0x1f;
|
// Now get the value in this register
|
// Now get the value in this register
|
delaypc = accessor->getGpr(o_b);
|
delaypc = accessor->getGpr(o_b);
|
// Now we have info about where we're jumping to. Output the info, with label if possible
|
// Now we have info about where we're jumping to. Output the info, with label if possible
|
// We print the PC we're jumping from + 8 which is the return address
|
// We print the PC we're jumping from + 8 which is the return address
|
if ( tmp = memoryload->get_label (delaypc) )
|
if ( tmp = memoryload->get_label (delaypc) )
|
profileFile << "+" << std::setfill('0') << hex << std::setw(8) << cycle_count << " " << hex << std::setw(8) << accessor->getWbPC() + 8 << " " << hex << std::setw(8) << delaypc << " " << tmp->name << endl;
|
profileFile << "+" << std::setfill('0') << hex
|
|
<< std::setw(8) << cycle_count << " " << hex
|
|
<< std::setw(8) << accessor->getWbPC() +
|
|
8 << " " << hex << std::setw(8) << delaypc
|
|
<< " " << tmp->name << endl;
|
else
|
else
|
profileFile << "+" << std::setfill('0') << hex << std::setw(8) << cycle_count << " " << hex << std::setw(8) << accessor->getWbPC() + 8 << " " << hex << std::setw(8) << delaypc << " @" << hex << std::setw(8) << delaypc << endl;
|
profileFile << "+" << std::setfill('0') << hex
|
|
<< std::setw(8) << cycle_count << " " << hex
|
|
<< std::setw(8) << accessor->getWbPC() +
|
|
8 << " " << hex << std::setw(8) << delaypc
|
|
<< " @" << hex << std::setw(8) << delaypc <<
|
|
endl;
|
|
|
break;
|
break;
|
|
|
}
|
}
|
}
|
}
|
} // callLog()
|
} // callLog()
|
|
|
|
void
|
|
Or1200MonitorSC::printTrace()
|
|
{
|
|
// TODO: Make this like or1ksim's trace, but for now print the basics
|
|
//XXXXXXPC: XXXXINSN l.insn rA,rB,Imm etc...
|
|
std::cout <<
|
|
std::setfill('0') << hex << std::setw(8) <<
|
|
accessor->getWbPC() << ": " <<
|
|
std::setfill('0') << hex << std::setw(8) <<
|
|
accessor->getWbInsn() <<
|
|
endl;
|
|
}
|
|
|
//! Method to output the state of the processor
|
//! Method to output the state of the processor
|
|
|
//! This function will output to a file, if enabled, the status of the processor
|
//! This function will output to a file, if enabled, the status of the processor
|
//! This copies what the verilog testbench module, or1200_monitor does in it its
|
//! This copies what the verilog testbench module, or1200_monitor does in it its
|
Line 682... |
Line 804... |
|
|
void
|
void
|
Or1200MonitorSC::displayState()
|
Or1200MonitorSC::displayState()
|
{
|
{
|
// Output the state if we're not frozen and not flushing during a delay slot
|
// Output the state if we're not frozen and not flushing during a delay slot
|
if (!accessor->getWbFreeze())
|
if (!accessor->getWbFreeze()) {
|
{
|
if ((((accessor->getWbInsn() & 0xfc000000) !=
|
if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
|
(uint32_t) OR1200_OR32_NOP)
|
{
|
|| !(accessor->getWbInsn() & (1 << 16)))
|
|
&& !(accessor->getExceptFlushpipe()
|
|
&& accessor->getExDslot())) {
|
// Print PC, instruction
|
// Print PC, instruction
|
statusFile << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << insn_count << "): " << std::setfill('0') << hex << std::setw(8) << accessor->getWbPC() << ": " << hex << std::setw(8) << accessor->getWbInsn() << endl;
|
statusFile << "\nEXECUTED(" << std::setfill(' ') <<
|
|
std::setw(11) << dec << insn_count << "): " <<
|
|
std::
|
|
setfill('0') << hex << std::setw(8) << accessor->
|
|
getWbPC() << ": " << hex << std::
|
|
setw(8) << accessor->getWbInsn() << endl;
|
}
|
}
|
// Exception version
|
// Exception version
|
else if (accessor->getExceptFlushpipe())
|
else if (accessor->getExceptFlushpipe()) {
|
{
|
|
// Print PC, instruction, indicate it caused an exception
|
// Print PC, instruction, indicate it caused an exception
|
statusFile << "\nEXECUTED("<< std::setfill(' ') << std::setw(11) << dec << insn_count << "): " << std::setfill('0') << hex << std::setw(8) << accessor->getExPC() << ": " << hex << std::setw(8) << accessor->getExInsn() << " (exception)" << endl;
|
statusFile << "\nEXECUTED(" << std::setfill(' ') <<
|
}
|
std::setw(11) << dec << insn_count << "): " <<
|
else
|
std::
|
|
setfill('0') << hex << std::setw(8) << accessor->
|
|
getExPC() << ": " << hex << std::
|
|
setw(8) << accessor->
|
|
getExInsn() << " (exception)" << endl;
|
|
} else
|
return;
|
return;
|
}
|
} else
|
else
|
|
return;
|
return;
|
|
|
if (logging_regs)
|
if (logging_regs) {
|
{
|
|
// Print general purpose register contents
|
// Print general purpose register contents
|
for (int i=0; i<32; i++)
|
for (int i = 0; i < 32; i++) {
|
{
|
if ((i % 4 == 0) && (i > 0))
|
if ((i%4 == 0)&&(i>0)) statusFile << endl;
|
statusFile << endl;
|
statusFile << std::setfill('0');
|
statusFile << std::setfill('0');
|
statusFile << "GPR" << dec << std::setw(2) << i << ": " << hex << std::setw(8) << (uint32_t) accessor->getGpr(i) << " ";
|
statusFile << "GPR" << dec << std::setw(2) << i << ": "
|
|
<< hex << std::
|
|
setw(8) << (uint32_t) accessor->getGpr(i) << " ";
|
}
|
}
|
statusFile << endl;
|
statusFile << endl;
|
|
|
statusFile << "SR : " << hex << std::setw(8) << (uint32_t) accessor->getSprSr() << " ";
|
statusFile << "SR : " << hex << std::setw(8) << (uint32_t)
|
statusFile << "EPCR0: " << hex << std::setw(8) << (uint32_t) accessor->getSprEpcr() << " ";
|
accessor->getSprSr() << " ";
|
statusFile << "EEAR0: " << hex << std::setw(8) << (uint32_t) accessor->getSprEear() << " ";
|
statusFile << "EPCR0: " << hex << std::setw(8) << (uint32_t)
|
statusFile << "ESR0 : " << hex << std::setw(8) << (uint32_t) accessor->getSprEsr() << endl;
|
accessor->getSprEpcr() << " ";
|
|
statusFile << "EEAR0: " << hex << std::setw(8) << (uint32_t)
|
|
accessor->getSprEear() << " ";
|
|
statusFile << "ESR0 : " << hex << std::setw(8) << (uint32_t)
|
|
accessor->getSprEsr() << endl;
|
|
|
}
|
}
|
|
|
return;
|
return;
|
|
|
Line 751... |
Line 888... |
Or1200MonitorSC::displayStateBinary()
|
Or1200MonitorSC::displayStateBinary()
|
{
|
{
|
struct s_binary_output_buffer outbuf;
|
struct s_binary_output_buffer outbuf;
|
|
|
// Output the state if we're not frozen and not flushing during a delay slot
|
// Output the state if we're not frozen and not flushing during a delay slot
|
if (!accessor->getWbFreeze())
|
if (!accessor->getWbFreeze()) {
|
{
|
if ((((accessor->getWbInsn() & 0xfc000000) !=
|
if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
|
(uint32_t) OR1200_OR32_NOP)
|
{
|
|| !(accessor->getWbInsn() & (1 << 16)))
|
|
&& !(accessor->getExceptFlushpipe()
|
|
&& accessor->getExDslot())) {
|
outbuf.insn_count = insn_count;
|
outbuf.insn_count = insn_count;
|
outbuf.pc = (uint32_t) accessor->getWbPC();
|
outbuf.pc = (uint32_t) accessor->getWbPC();
|
outbuf.insn = (uint32_t) accessor->getWbInsn();
|
outbuf.insn = (uint32_t) accessor->getWbInsn();
|
outbuf.exception = 0;
|
outbuf.exception = 0;
|
}
|
}
|
// Exception version
|
// Exception version
|
else if (accessor->getExceptFlushpipe())
|
else if (accessor->getExceptFlushpipe()) {
|
{
|
|
outbuf.insn_count = insn_count;
|
outbuf.insn_count = insn_count;
|
outbuf.pc = (uint32_t) accessor->getExPC();
|
outbuf.pc = (uint32_t) accessor->getExPC();
|
outbuf.insn = (uint32_t) accessor->getExInsn();
|
outbuf.insn = (uint32_t) accessor->getExInsn();
|
outbuf.exception = 1;
|
outbuf.exception = 1;
|
}
|
} else
|
else
|
|
return;
|
return;
|
}
|
} else
|
else
|
|
return;
|
return;
|
|
|
if (logging_regs)
|
if (logging_regs) {
|
{
|
|
// Print general purpose register contents
|
// Print general purpose register contents
|
for (int i=0; i<32; i++)
|
for (int i=0; i<32; i++)
|
outbuf.regs[i] = (uint32_t) accessor->getGpr(i);
|
outbuf.regs[i] = (uint32_t) accessor->getGpr(i);
|
|
|
outbuf.sr = (uint32_t) accessor->getSprSr();
|
outbuf.sr = (uint32_t) accessor->getSprSr();
|
outbuf.epcr0 = (uint32_t) accessor->getSprEpcr();
|
outbuf.epcr0 = (uint32_t) accessor->getSprEpcr();
|
outbuf.eear0 = (uint32_t) accessor->getSprEear();
|
outbuf.eear0 = (uint32_t) accessor->getSprEear();
|
outbuf.eser0 = (uint32_t) accessor->getSprEsr();
|
outbuf.eser0 = (uint32_t) accessor->getSprEsr();
|
|
|
statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer));
|
statusFile.write((char *)&outbuf,
|
|
sizeof(struct s_binary_output_buffer));
|
}
|
|
else
|
|
statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer_sans_regs));
|
|
|
|
|
|
|
} else
|
|
statusFile.write((char *)&outbuf,
|
|
sizeof(struct
|
|
s_binary_output_buffer_sans_regs));
|
|
|
return;
|
return;
|
|
|
} // displayStateBinary()
|
} // displayStateBinary()
|
|
|
//! Function to calculate the number of instructions performed and the time taken
|
//! Function to calculate the number of instructions performed and the time taken
|
void
|
void
|
Or1200MonitorSC::perfSummary()
|
Or1200MonitorSC::perfSummary()
|
{
|
{
|
if (!quiet)
|
|
{
|
|
double ts;
|
double ts;
|
ts = sc_time_stamp().to_seconds() * 1000000000.0;
|
ts = sc_time_stamp().to_seconds() * 1000000000.0;
|
int cycles = ts / (BENCH_CLK_HALFPERIOD*2); // Number of clock cycles we had
|
int cycles = ts / (BENCH_CLK_HALFPERIOD*2); // Number of clock cycles we had
|
|
|
clock_t finish = clock();
|
clock_t finish = clock();
|
double elapsed_time = (double(finish)-double(start))/CLOCKS_PER_SEC;
|
double elapsedTime =
|
// It took elapsed_time seconds to do insn_count instructions. Divide insn_count by the time to get instructions/second.
|
(double (finish) - double (start))/CLOCKS_PER_SEC;
|
double ips = (insn_count/elapsed_time);
|
// It took elapsedTime seconds to do insn_count instructions. Divide
|
double mips = (insn_count/elapsed_time)/1000000;
|
// insn_count by the time to get instructions/second.
|
int hertz = (int) ((cycles/elapsed_time)/1000);
|
double ips = (insn_count / elapsedTime);
|
std::cout << "* Or1200Monitor: simulated " << sc_time_stamp() << ", time elapsed: " << elapsed_time << " seconds" << endl;
|
double kips = (insn_count / elapsedTime) /1000;
|
std::cout << "* Or1200Monitor: simulated " << dec << cycles << " clock cycles, executed at approx " << hertz << "kHz" << endl;
|
double mips = (insn_count / elapsedTime) / 1000000;
|
std::cout << "* Or1200Monitor: simulated " << insn_count << " instructions, insn/sec. = " << ips /*<< ", mips = " << mips*/ << endl;
|
int hertz = (int)((cycles / elapsedTime) / 1000);
|
}
|
std::cout << "* Or1200Monitor: simulator time at exit: " << ts
|
|
<< " ns" << endl;
|
|
std::cout << "* Or1200Monitor: system time elapsed: " << elapsedTime
|
|
<< " seconds" << endl;
|
|
std::cout << "* Or1200Monitor: simulated " << dec << cycles <<
|
|
" clock cycles, executed at approx " << hertz << "kHz" <<
|
|
endl;
|
|
std::cout << "* Or1200Monitor: simulated " << insn_count <<
|
|
" instructions, 1000's insn/sec. = " << kips << endl;
|
return;
|
return;
|
} // perfSummary
|
} // perfSummary
|
|
|
|
|
//! Dump contents of simulation's RAM to file
|
//! Dump contents of simulation's RAM to file
|
void
|
void
|
Or1200MonitorSC::memdump()
|
Or1200MonitorSC::memdump()
|
{
|
{
|
if (!do_memdump) return;
|
if (!do_memdump)
|
|
return;
|
uint32_t current_word;
|
uint32_t current_word;
|
int size_words = (memdump_end_addr/4) - (memdump_start_addr/4);
|
int size_words = (memdump_end_addr/4) - (memdump_start_addr/4);
|
if (!(size_words > 0)) return;
|
if (!(size_words > 0))
|
|
return;
|
|
|
// First try opening the file
|
// First try opening the file
|
memdumpFile.open(memdumpFileName.c_str(), ios::binary); // Open memorydump file
|
memdumpFile.open(memdumpFileName.c_str(), ios::binary); // Open memorydump file
|
if(memdumpFile.is_open())
|
if (memdumpFile.is_open()) {
|
{
|
|
// If we could open the file then turn on logging
|
// If we could open the file then turn on logging
|
cout << "* Dumping system RAM from 0x" << hex << memdump_start_addr << "-0x" << hex << memdump_end_addr << " to file " << memdumpFileName << endl;
|
cout << "* Dumping system RAM from 0x" << hex <<
|
|
memdump_start_addr << "-0x" << hex << memdump_end_addr <<
|
|
" to file " << memdumpFileName << endl;
|
|
|
while (size_words)
|
while (size_words) {
|
{
|
|
// Read the data from the simulation memory
|
// Read the data from the simulation memory
|
current_word = accessor->get_mem32(memdump_start_addr);
|
current_word = accessor->get_mem32(memdump_start_addr);
|
// Change from whatever endian the host is (most
|
// Change from whatever endian the host is (most
|
// cases little) to big endian
|
// cases little) to big endian
|
current_word = htonl(current_word);
|
current_word = htonl(current_word);
|
memdumpFile.write((char*) ¤t_word, 4);
|
memdumpFile.write((char*) ¤t_word, 4);
|
memdump_start_addr+=4; size_words--;
|
memdump_start_addr += 4;
|
|
size_words--;
|
}
|
}
|
|
|
// Ideally we've now finished piping out the data
|
// Ideally we've now finished piping out the data
|
// not 100% about the endianess of this.
|
// not 100% about the endianess of this.
|
}
|
}
|
Line 951... |
Line 1094... |
uint32_t fmtaddr;
|
uint32_t fmtaddr;
|
int i;
|
int i;
|
fmtaddr = regparam;
|
fmtaddr = regparam;
|
|
|
i = 0;
|
i = 0;
|
while (accessor->get_mem8(fmtaddr) != '\0')
|
while (accessor->get_mem8(fmtaddr) != '\0') {
|
{
|
|
fmtstr[i++] = accessor->get_mem8(fmtaddr);
|
fmtstr[i++] = accessor->get_mem8(fmtaddr);
|
fmtaddr++;
|
fmtaddr++;
|
if (i == FMTLEN - 1)
|
if (i == FMTLEN - 1)
|
break;
|
break;
|
}
|
}
|
fmtstr[i] = '\0';
|
fmtstr[i] = '\0';
|
|
|
|
|
argaddr = stackaddr;
|
argaddr = stackaddr;
|
int index, last_index;
|
int index, last_index;
|
index = last_index = 0;
|
index = last_index = 0;
|
char tmp_char;
|
char tmp_char;
|
while (1)
|
while (1) {
|
{
|
|
/* Look for the next format argument, or end of string */
|
/* Look for the next format argument, or end of string */
|
while (!(fmtstrpart[index] == '\0' || fmtstrpart[index] == '%'))
|
while (!(fmtstrpart[index] == '\0' || fmtstrpart[index] == '%'))
|
index++;
|
index++;
|
|
|
if (fmtstrpart[index] == '\0' && index == last_index)
|
if (fmtstrpart[index] == '\0' && index == last_index)
|
/* We had something like "%d\0", so we're done*/
|
/* We had something like "%d\0", so we're done*/
|
return;
|
return;
|
|
|
if (fmtstrpart[index] == '\0')
|
if (fmtstrpart[index] == '\0') {
|
{
|
|
/* Final printf */
|
/* Final printf */
|
printf("%s", (char*) fmtstrpart + last_index);
|
printf("%s", (char*) fmtstrpart + last_index);
|
return;
|
return;
|
}
|
} else {
|
else
|
|
{
|
|
/* We have a section between last_index and index that we should print out*/
|
/* We have a section between last_index and index that we should print out*/
|
fmtstrpart[index] = '\0'; /* Replace % with \0 for now */
|
fmtstrpart[index] = '\0'; /* Replace % with \0 for now */
|
printf ("%s",fmtstrpart + last_index);
|
printf ("%s",fmtstrpart + last_index);
|
fmtstrpart[index] = '%'; /* Replace the % */
|
fmtstrpart[index] = '%'; /* Replace the % */
|
}
|
}
|
Line 999... |
Line 1136... |
|| fmtstrpart[index] == 'o' || fmtstrpart[index] == 'u'
|
|| fmtstrpart[index] == 'o' || fmtstrpart[index] == 'u'
|
|| fmtstrpart[index] == 'x' || fmtstrpart[index] == 'X'
|
|| fmtstrpart[index] == 'x' || fmtstrpart[index] == 'X'
|
|| fmtstrpart[index] == 'f' || fmtstrpart[index] == 'e'
|
|| fmtstrpart[index] == 'f' || fmtstrpart[index] == 'e'
|
|| fmtstrpart[index] == 'E' || fmtstrpart[index] == 'g'
|
|| fmtstrpart[index] == 'E' || fmtstrpart[index] == 'g'
|
|| fmtstrpart[index] == 'G' || fmtstrpart[index] == 'c'
|
|| fmtstrpart[index] == 'G' || fmtstrpart[index] == 'c'
|
|| fmtstrpart[index] == 's' || fmtstrpart[index] == '\0'
|
|| fmtstrpart[index] == 's'
|
|
|| fmtstrpart[index] == '\0'
|
|| fmtstrpart[index+1] == '%'))
|
|| fmtstrpart[index+1] == '%'))
|
index++;
|
index++;
|
|
|
if (fmtstrpart[index] == '\0')
|
if (fmtstrpart[index] == '\0') {
|
{
|
|
// Error
|
// Error
|
return;
|
return;
|
}
|
} else if (fmtstrpart[index] == '%'
|
else if (fmtstrpart[index] == '%' && fmtstrpart[index+1] == '%')
|
&& fmtstrpart[index + 1] == '%') {
|
{
|
|
/* Deal with the %% case to print a single % */
|
/* Deal with the %% case to print a single % */
|
index++;
|
index++;
|
printf("%%");
|
printf("%%");
|
}
|
} else {
|
else
|
|
{
|
|
/* We now will print the part that requires the next argument */
|
/* We now will print the part that requires the next argument */
|
/* Same trick, but this time remember what the char was */
|
/* Same trick, but this time remember what the char was */
|
tmp_char = fmtstrpart[index+1];
|
tmp_char = fmtstrpart[index+1];
|
fmtstrpart[index+1] = '\0'; /* Replace % with \0 for now */
|
fmtstrpart[index+1] = '\0'; /* Replace % with \0 for now */
|
/* Check what we're printing*/
|
/* Check what we're printing*/
|
if (fmtstrpart[index] == 's')
|
if (fmtstrpart[index] == 's') {
|
{
|
|
/* It's a string, so pull it out of memory into a local char*
|
/* It's a string, so pull it out of memory into a local char*
|
and pass it to printf() */
|
and pass it to printf() */
|
int tmp_string_len, z;
|
int tmp_string_len, z;
|
/* Assume stackaddr already pointing at appropriate value*/
|
/* Assume stackaddr already pointing at appropriate value*/
|
oraddr_t ormem_str_ptr = accessor->get_mem32(argaddr);
|
oraddr_t ormem_str_ptr =
|
|
accessor->get_mem32(argaddr);
|
|
|
while (accessor->get_mem8(ormem_str_ptr++) != '\0')
|
while (accessor->get_mem8(ormem_str_ptr++) !=
|
|
'\0')
|
tmp_string_len++;
|
tmp_string_len++;
|
tmp_string_len++; /* One for terminating char */
|
tmp_string_len++; /* One for terminating char */
|
|
|
char* str = (char *) malloc (tmp_string_len);
|
char* str = (char *) malloc (tmp_string_len);
|
if (str == NULL) return; /* Malloc failed, bigger issues than printf'ing out of sim */
|
if (str == NULL)
|
|
return; /* Malloc failed, bigger issues than printf'ing out of sim */
|
ormem_str_ptr = accessor->get_mem32(argaddr); /* Reset start pointer value*/
|
ormem_str_ptr = accessor->get_mem32(argaddr); /* Reset start pointer value*/
|
for (z=0;z<tmp_string_len;z++)
|
for (z=0;z<tmp_string_len;z++)
|
str[z] = accessor->get_mem8(ormem_str_ptr+z);
|
str[z] =
|
|
accessor->get_mem8(ormem_str_ptr +
|
|
z);
|
|
|
printf (fmtstrpart + last_index, str);
|
printf (fmtstrpart + last_index, str);
|
free (str);
|
free (str);
|
}
|
} else {
|
else
|
|
{
|
|
/*
|
/*
|
Some other kind of variable, pull it off the stack and print
|
Some other kind of variable, pull it off the stack and print
|
it out. Assume stackaddr already pointing at appropriate
|
it out. Assume stackaddr already pointing at appropriate
|
value
|
value
|
*/
|
*/
|