OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [bench/] [sysc/] [src/] [Or1200MonitorSC.cpp] - Blame information for rev 354

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 6 julius
// ----------------------------------------------------------------------------
2
 
3
// SystemC OpenRISC 1200 Monitor: implementation
4
 
5
// Copyright (C) 2008  Embecosm Limited <info@embecosm.com>
6
 
7
// Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
8 44 julius
// Contributor Julius Baxter <jb@orsoc.se>
9 6 julius
 
10
// This file is part of the cycle accurate model of the OpenRISC 1000 based
11
// system-on-chip, ORPSoC, built using Verilator.
12
 
13
// This program is free software: you can redistribute it and/or modify it
14
// under the terms of the GNU Lesser General Public License as published by
15
// the Free Software Foundation, either version 3 of the License, or (at your
16
// option) any later version.
17
 
18
// This program is distributed in the hope that it will be useful, but WITHOUT
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
21
// License for more details.
22
 
23
// You should have received a copy of the GNU Lesser General Public License
24
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
25
 
26
// ----------------------------------------------------------------------------
27
 
28 57 julius
// $Id$
29 6 julius
 
30
#include <iostream>
31
#include <iomanip>
32 44 julius
#include <fstream>
33 52 julius
#include <sys/types.h>
34
#include <netinet/in.h>
35 44 julius
using namespace std;
36
 
37 6 julius
#include "Or1200MonitorSC.h"
38 44 julius
#include "OrpsocMain.h"
39 6 julius
 
40 63 julius
#include <errno.h>
41
int monitor_to_gdb_pipe[2][2]; // [0][] - monitor to gdb, [1][] - gdb to monitor, [][0] - read, [][1] - write
42 6 julius
 
43
SC_HAS_PROCESS( Or1200MonitorSC );
44
 
45
//! Constructor for the OpenRISC 1200 monitor
46
 
47
//! @param[in] name  Name of this module, passed to the parent constructor.
48
//! @param[in] accessor  Accessor class for this Verilated ORPSoC model
49
 
50
Or1200MonitorSC::Or1200MonitorSC (sc_core::sc_module_name   name,
51 49 julius
                                  OrpsocAccess             *_accessor,
52 51 julius
                                  MemoryLoad               *_memoryload,
53 49 julius
                                  int argc,
54
                                  char *argv[]) :
55 6 julius
  sc_module (name),
56 51 julius
  accessor (_accessor),
57
  memoryload(_memoryload)
58 6 julius
{
59 63 julius
  string logfileDefault(DEFAULT_EXEC_LOG_FILE);
60 49 julius
  string logfileNameString;
61 63 julius
  logging_enabled = false;
62
  logfile_name_provided = false;
63
  profiling_enabled = false;
64 51 julius
  string profileFileName(DEFAULT_PROF_FILE);
65 52 julius
  memdumpFileName = (DEFAULT_MEMDUMP_FILE);
66
  int memdump_start = 0; int memdump_end = 0;
67 63 julius
  do_memdump = false; // Default is not to do a dump of RAM at finish
68
  logging_regs = true; // Execution log includes register values by default
69
  bool rsp_server_enabled = false;
70
  wait_for_stall_cmd_response = false; // Default
71
  insn_count = insn_count_rst = 0;
72
  cycle_count = cycle_count_rst = 0;
73 52 julius
 
74 63 julius
  exit_perf_summary_enabled = true; // Simulation exit performance summary is 
75
                                    // on by default. Turn off with "-q" on the 
76
                                    // cmd line
77
  monitor_for_crash = false;
78
  lookslikewevecrashed_count = crash_monitor_buffer_head = 0;
79 49 julius
 
80 63 julius
  bus_trans_log_enabled = bus_trans_log_name_provided =
81
    bus_trans_log_start_delay_enable = false; // Default
82
  string bus_trans_default_log_name(DEFAULT_BUS_LOG_FILE);
83
  string bus_trans_log_file;
84 49 julius
 
85
  // Parse the command line options
86 63 julius
  bool cmdline_name_found = false;
87 49 julius
  if (argc > 1)
88
    {
89
      // Search through the command line parameters for the "-log" option
90
      for(int i=1; i < argc; i++)
91
        {
92
          if ((strcmp(argv[i], "-l")==0) ||
93
              (strcmp(argv[i], "--log")==0))
94
            {
95 63 julius
              logging_enabled = true;
96
              binary_log_format = false;
97
              if (i+1 < argc)
98
                if(argv[i+1][0] != '-')
99
                  {
100
                    logfileNameString = (argv[i+1]);
101
                    logfile_name_provided = true;
102
                  }
103
              if (!logfile_name_provided)
104
                logfileNameString = logfileDefault;
105 49 julius
            }
106 63 julius
          else if ((strcmp(argv[i], "--log-noregs")==0))
107
            {
108
              logging_regs = false;
109
            }
110
          else if ((strcmp(argv[i], "-b")==0) ||
111
                   (strcmp(argv[i], "--binlog")==0))
112
            {
113
              logging_enabled = true;
114
              binary_log_format = true;
115
              if (i+1 < argc)
116
                if(argv[i+1][0] != '-')
117
                  {
118
                    logfileNameString = (argv[i+1]);
119
                    logfile_name_provided = true;
120
                  }
121
              if (!logfile_name_provided)
122
                logfileNameString = logfileDefault;
123
 
124
            }
125
          else if ((strcmp(argv[i], "-c")==0) ||
126
                   (strcmp(argv[i], "--crash-monitor")==0))
127
            {
128
              monitor_for_crash = true;
129
            }
130 51 julius
          else if ((strcmp(argv[i], "-q")==0) ||
131
                   (strcmp(argv[i], "--quiet")==0))
132 49 julius
            {
133 63 julius
              exit_perf_summary_enabled = false;
134 49 julius
            }
135 51 julius
          else if ((strcmp(argv[i], "-p")==0) ||
136
                   (strcmp(argv[i], "--profile")==0))
137
            {
138 63 julius
              profiling_enabled = true;
139
              // Check for !end of command line and that next thing is not a 
140
              // command
141 51 julius
              if ((i+1 < argc)){
142
                if(argv[i+1][0] != '-')
143
                  profileFileName = (argv[i+1]);
144
              }
145
            }
146 63 julius
          else if ( (strcmp(argv[i], "-r")==0) ||
147
                    (strcmp(argv[i], "--rsp")==0) )
148
            {
149
              // We need to detect this here too
150
              rsp_server_enabled = true;
151
            }
152
 
153 52 julius
          else if ((strcmp(argv[i], "-m")==0) ||
154 53 julius
                   (strcmp(argv[i], "--memdump")==0))
155 52 julius
            {
156 63 julius
              do_memdump = true;
157
              // Check for !end of command line and that next thing is not a 
158
              // command or a memory address
159 52 julius
              if (i+1 < argc)
160
                {
161
                  if((argv[i+1][0] != '-') && (strncmp("0x", argv[i+1],2) != 0))
162
                    {
163
                      // Hopefully this is the filename we want to use.
164
                      // All addresses should have preceeding hex identifier 0x
165
                      memdumpFileName = argv[i+1];
166
                      // We've used this next index, can safely increment i
167
                      i++;
168
                    }
169
                }
170
              if (i+1 < argc)
171
                {
172
                  if((argv[i+1][0] != '-') && (strncmp("0x", argv[i+1],2) == 0))
173
                    {
174
                      // Hopefully this is is the start address
175
                      // All addresses should have preceeding hex identifier 0x
176
                      sscanf( argv[i+1], "0x%x", &memdump_start);
177
                      i++;
178
                    }
179
                }
180
              if (i+1 < argc)
181
                {
182
                  if((argv[i+1][0] != '-') && (strncmp("0x", argv[i+1],2) == 0))
183
                    {
184
                      // Hopefully this is is the end address
185
                      // All addresses should have preceeding hex identifier 0x
186
                      sscanf( argv[i+1], "0x%x", &memdump_end);
187
                      i++;
188
                    }
189
                }
190
            }
191 354 julius
          /*
192 63 julius
          else if ((strcmp(argv[i], "-u")==0) ||
193
                   (strcmp(argv[i], "--bus-log")==0))
194
            {
195
              bus_trans_log_enabled = true;
196
              if (i+1 < argc)
197
                if(argv[i+1][0] != '-')
198
                  {
199
                    bus_trans_log_file = (argv[i+1]);
200
                    bus_trans_log_name_provided = true;
201
                  }
202
 
203
              if (!bus_trans_log_name_provided)
204
                bus_trans_log_file = bus_trans_default_log_name;
205
 
206
              // check for a log start delay
207
              if (i+2 < argc)
208
                if(argv[i+2][0] != '-')
209
                  {
210
                    // We have a bus transaction log start delay
211
                    bus_trans_log_start_delay_enable = true;
212
                    int time_val = atoi(argv[i+2]);
213
                    sc_time log_start_time(time_val,SC_NS);
214
                    bus_trans_log_start_delay = log_start_time;
215
                  }
216
            }
217 354 julius
          */
218 49 julius
        }
219
    }
220 63 julius
 
221 49 julius
 
222 63 julius
  if (!rsp_server_enabled)
223
    {
224
      monitor_to_gdb_pipe[0][0] = monitor_to_gdb_pipe[0][1] = NULL;
225
      monitor_to_gdb_pipe[1][0] = monitor_to_gdb_pipe[1][1] = NULL;
226
    }
227
 
228 57 julius
 
229
  // checkInstruction monitors the bus for special NOP instructionsl
230
  SC_METHOD (checkInstruction);
231
  sensitive << clk.pos();
232
  dont_initialize();
233
 
234 52 julius
 
235 51 julius
  if (profiling_enabled)
236
    {
237 63 julius
 
238 51 julius
      profileFile.open(profileFileName.c_str(), ios::out); // Open profiling log file
239
      if(profileFile.is_open())
240
        {
241
          // If the file was opened OK, then enabled logging and print a message.
242 63 julius
          profiling_enabled = true;
243 51 julius
          cout << "* Execution profiling enabled. Logging to " << profileFileName << endl;
244
        }
245
 
246
      // Setup profiling function
247
      SC_METHOD (callLog);
248
      sensitive << clk.pos();
249
      dont_initialize();
250
      start = clock();
251
    }
252 49 julius
 
253 63 julius
  if(logging_enabled)
254 49 julius
    {
255 63 julius
 
256
      /* Now open the file */
257
      if (binary_log_format)
258
        statusFile.open(logfileNameString.c_str(), ios::out | ios::binary);
259
      else
260
        statusFile.open(logfileNameString.c_str(), ios::out );
261
 
262
      /* Check the open() */
263
      if(statusFile.is_open() && binary_log_format)
264 49 julius
        {
265 63 julius
          cout << "* Processor execution logged in binary format to file: " << logfileNameString << endl;
266
          /* Write out a byte indicating whether there's register values too */
267
          statusFile.write((char*)&logging_regs, 1);
268
 
269 49 julius
        }
270 63 julius
      else if (statusFile.is_open() && !binary_log_format)
271
        cout << "* Processor execution logged to file: " << logfileNameString << endl;
272
      else
273
        /* Couldn't open */
274
        logging_enabled = false;
275 49 julius
 
276
    }
277 63 julius
 
278 51 julius
  if (logging_enabled)
279 63 julius
    {
280
      if (binary_log_format)
281
        {
282
          SC_METHOD (displayStateBinary);
283
        }
284
      else
285
        {
286
          SC_METHOD (displayState);
287
        }
288 51 julius
      sensitive << clk.pos();
289
      dont_initialize();
290
      start = clock();
291 63 julius
 
292 51 julius
    }
293 49 julius
 
294 63 julius
  if (monitor_for_crash)
295
    {
296
      cout << "* Crash monitor enabled" << endl;
297
    }
298
 
299 52 julius
  // Check sizes we were given from memory dump command line options first
300
  if (do_memdump)
301
    {
302
      if ((memdump_start > ORPSOC_SRAM_SIZE) || (memdump_end > ORPSOC_SRAM_SIZE) ||
303
          ((memdump_start > memdump_end) && (memdump_end != 0)))
304
        {
305 63 julius
          do_memdump = false;
306 52 julius
          cout << "* Memory dump addresses range incorrect. Limit of memory is 0x" << hex <<  ORPSOC_SRAM_SIZE << ". Memory dumping disabled." << endl;
307
        }
308
    }
309 49 julius
 
310 52 julius
  if (do_memdump)
311
    {
312
      // Were we given dump addresses? If not, we dump all of the memory
313
      // Size of memory isn't clearly defined in any one place. This could lead to
314
      // big problems when changing size of the RAM in simulation.
315
 
316
      if (memdump_start == 0 && memdump_end == 0)
317
        memdump_end = ORPSOC_SRAM_SIZE;
318
 
319
      if (memdump_start != 0 && memdump_end == 0)
320
        {
321
          // Probably just got the single memorydump param
322
          // Interpet as a length from 0
323
          memdump_end = memdump_start;
324
          memdump_start = 0;
325
        }
326
 
327
      if (memdump_start & 0x3) memdump_start &= ~0x3; // word-align the start address      
328
      if (memdump_end & 0x3) memdump_end = (memdump_end+4) & ~0x3; // word-align the start address
329
 
330
      memdump_start_addr = memdump_start;
331
      memdump_end_addr = memdump_end;
332 63 julius
    }
333 353 julius
 
334
  /*
335 63 julius
  if (bus_trans_log_enabled)
336
    {
337
      // Setup log file and register the bus monitoring function
338
      busTransLog.open(bus_trans_log_file.c_str(), ios::out );
339
 
340
      if (busTransLog.is_open())
341
        {
342
          cout << "* System bus transactions logged to file: " <<
343
            bus_trans_log_file;
344
 
345
          if (bus_trans_log_start_delay_enable)
346
            cout << ", on at " << bus_trans_log_start_delay.to_string();
347
          cout << endl;
348
        }
349
      else
350 353 julius
        // Couldn't open
351 63 julius
        bus_trans_log_enabled = false;
352
    }
353
 
354 353 julius
 
355 63 julius
  if (bus_trans_log_enabled)
356
    {
357
      // Setup profiling function
358
      SC_METHOD (busMonitor);
359
      sensitive << clk.pos();
360
      dont_initialize();
361
    }
362 353 julius
  */
363 49 julius
 
364 6 julius
}       // Or1200MonitorSC ()
365
 
366 49 julius
//! Print usage for the options of this module
367
void
368
Or1200MonitorSC::printUsage()
369
{
370 63 julius
  printf("\nLogging and diagnostic options:\n");
371
  printf("  -p, --profile [<file>]Enable execution profiling output to <file> (default is\n\t\t\t"DEFAULT_PROF_FILE")\n");
372
  printf("  -l, --log <file>\tLog processor execution to <file>\n");
373
  printf("      --log-noregs\tLog excludes register contents\n");
374
 
375
  printf("  -b, --binlog <file>\tGenerate binary format execution log (faster, smaller)\n");
376
 
377 49 julius
  printf("  -q, --quiet\t\tDisable the performance summary at end of simulation\n");
378 63 julius
  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");
379
  printf("  -c, --crash-monitor\tDetect when the processor has crashed and exit\n");
380 354 julius
/*
381 63 julius
  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");
382 354 julius
*/
383 63 julius
 
384 49 julius
}
385
 
386 6 julius
//! Method to handle special instrutions
387
 
388
//! These are l.nop instructions with constant values. At present the
389
//! following are implemented:
390
 
391
//! - l.nop 1  Terminate the program
392
//! - l.nop 2  Report the value in R3
393
//! - l.nop 3  Printf the string with the arguments in R3, etc
394
//! - l.nop 4  Print a character
395 57 julius
 
396
//#define OR1200_OR32_NOP_BITS_31_TO_26               6'b000101
397
#define OR1200_OR32_NOP               0x14000000
398
 
399 49 julius
extern int SIM_RUNNING;
400 6 julius
void
401
Or1200MonitorSC::checkInstruction()
402
{
403
  uint32_t  r3;
404
  double    ts;
405 63 julius
  uint32_t current_WbInsn, current_WbPC;
406 51 julius
 
407 52 julius
  cycle_count++;
408 57 julius
 
409
  /* Check if this counts as an "executed" instruction */
410
  if (!accessor->getWbFreeze())
411 63 julius
    {
412
      // Cache writeback stage instruction
413
      current_WbInsn = accessor->getWbInsn();
414
 
415
      if ((((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
416 57 julius
        insn_count++;
417 63 julius
      else
418
        // Exception version
419
        if (accessor->getExceptFlushpipe())
420
          insn_count++;
421
    }
422
 
423 6 julius
  // Check the instruction when the freeze signal is low.
424 52 julius
  if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0))
425 6 julius
    {
426
      // Do something if we have l.nop
427 63 julius
      switch (current_WbInsn)
428 6 julius
        {
429
        case NOP_EXIT:
430
          r3 = accessor->getGpr (3);
431
          ts = sc_time_stamp().to_seconds() * 1000000000.0;
432
          std::cout << std::fixed << std::setprecision (2) << ts;
433
          std::cout << " ns: Exiting (" << r3 << ")" << std::endl;
434 49 julius
          perfSummary();
435 52 julius
          if (logging_enabled) statusFile.close();
436
          if (profiling_enabled) profileFile.close();
437 63 julius
          if (bus_trans_log_enabled) busTransLog.close();
438 52 julius
          memdump();
439 49 julius
          SIM_RUNNING=0;
440 6 julius
          sc_stop();
441
          break;
442
 
443
        case NOP_REPORT:
444
          ts = sc_time_stamp().to_seconds() * 1000000000.0;
445
          r3 = accessor->getGpr (3);
446
          std::cout << std::fixed << std::setprecision (2) << ts;
447
          std::cout << " ns: report (" << hex << r3 << ")" << std::endl;
448
          break;
449
 
450
        case NOP_PRINTF:
451
          ts = sc_time_stamp().to_seconds() * 1000000000.0;
452
          std::cout << std::fixed << std::setprecision (2) << ts;
453 66 julius
          std::cout << " ns: printf: ";
454
          simPrintf(accessor->getGpr (4), accessor->getGpr (3));
455 6 julius
          break;
456
 
457
        case NOP_PUTC:
458
          r3 = accessor->getGpr (3);
459
          std::cout << (char)r3 << std::flush;
460
          break;
461 63 julius
        case NOP_CNT_RESET:
462
          std::cout << "****************** counters reset ******************" << endl;
463
          std::cout << "since last reset: cycles " << cycle_count - cycle_count_rst << ", insn #" << insn_count - insn_count_rst << endl;
464
          std::cout << "****************** counters reset ******************" << endl;
465
          cycle_count_rst = cycle_count;
466
          insn_count_rst = insn_count;
467 64 julius
          /* 3 separate counters we'll use for various things */
468
        case NOP_CNT_RESET1:
469
          std::cout << "**** counter1 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_1 << " resetting ********" << endl;
470
          cycles_1 = cycle_count;
471
          break;
472
        case NOP_CNT_RESET2:
473
          std::cout << "**** counter2 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_2 << " resetting ********" << endl;
474
          cycles_2 = cycle_count;
475
          break;
476
        case NOP_CNT_RESET3:
477
          std::cout << "**** counter3 cycles: " << std::setfill('0') << std::setw(10) << cycle_count - cycles_3 << " resetting ********" << endl;
478
          cycles_3 = cycle_count;
479
          break;
480 6 julius
        default:
481
          break;
482
        }
483 63 julius
 
484
      if (monitor_for_crash)
485
        {
486
          current_WbPC = accessor->getWbPC();
487
          // Look at current instruction
488
          if (current_WbInsn == 0x00000000)
489
            {
490
              // Looks like we've jumped somewhere incorrectly
491
              lookslikewevecrashed_count++;
492
            }
493
#define CRASH_MONITOR_LOG_BAD_INSNS 1
494
#if CRASH_MONITOR_LOG_BAD_INSNS
495
 
496
          /* Log so-called "bad" instructions, or at least instructions we
497
          executed, no matter if they caused us to increment
498
          lookslikewevecrashed_count, this way we get them in our list too */
499
          if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
500
            {
501
              crash_monitor_buffer[crash_monitor_buffer_head][0] = current_WbPC;
502
              crash_monitor_buffer[crash_monitor_buffer_head][1] = current_WbInsn;
503
              /* Circular buffer */
504
              if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
505
                crash_monitor_buffer_head++;
506
              else
507
                crash_monitor_buffer_head = 0;
508
 
509
            }
510
 
511
#else
512
          else if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
513
          {
514
 
515
              crash_monitor_buffer[crash_monitor_buffer_head][0] = current_WbPC;
516
              crash_monitor_buffer[crash_monitor_buffer_head][1] = current_WbInsn;
517
              /* Circular buffer */
518
              if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
519
                crash_monitor_buffer_head++;
520
              else
521
                crash_monitor_buffer_head = 0;
522
 
523
              /* Reset this */
524
              lookslikewevecrashed_count  = 0;
525
            }
526
#endif    
527
          if (wait_for_stall_cmd_response)
528
            {
529
              // We've already crashed, and we're issued a command to stall the
530
              // processor to the system C debug unit interface, and we're
531
              // waiting for this debug unit to send back the message that we've
532
              // stalled.
533
              char readChar;
534
              int n = read(monitor_to_gdb_pipe[1][0], &readChar, sizeof(char));
535
              if (!( ((n < 0) && (errno == EAGAIN)) || (n==0) ))
536
                wait_for_stall_cmd_response = false; // We got response
537
              lookslikewevecrashed_count = 0;
538
 
539
            }
540
          else if (lookslikewevecrashed_count > 0)
541
            {
542
 
543
              if (lookslikewevecrashed_count >= CRASH_MONITOR_BUFFER_SIZE/4)
544
                {
545
                  /* Probably crashed. Bail out, print out buffer */
546
                  std::cout << "********************************************************************************"<< endl;
547
                  std::cout << "* Looks like processor crashed. Printing last " << CRASH_MONITOR_BUFFER_SIZE << " instructions executed:" << endl;
548
 
549
                  int crash_monitor_buffer_head_end = (crash_monitor_buffer_head > 0) ? crash_monitor_buffer_head - 1 : CRASH_MONITOR_BUFFER_SIZE-1;
550
                  while (crash_monitor_buffer_head != crash_monitor_buffer_head_end)
551
                    {
552
                      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;
553
 
554
                      if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
555
                        crash_monitor_buffer_head++;
556
                      else
557
                        crash_monitor_buffer_head = 0;
558
                    }
559
                  std::cout << "********************************************************************************"<< endl;
560
 
561
                  if ( (monitor_to_gdb_pipe[0][0] != NULL))
562
                    {
563
                      // If GDB server is running, we'll pass control back to
564
                      // the debugger instead of just quitting.
565
                      char interrupt = 0x3; // Arbitrary
566
                      write(monitor_to_gdb_pipe[0][1],&interrupt,sizeof(char));
567
                      wait_for_stall_cmd_response = true;
568
                      lookslikewevecrashed_count = 0;
569
                      std::cout << "* Stalling processor and returning control to GDB"<< endl;
570
                      // 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.
571
                      // 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).
572
                      wait_for_stall_cmd_response = true;
573
 
574
                    }
575
                  else
576
                    {
577
                      // Close down sim end exit
578
                      ts = sc_time_stamp().to_seconds() * 1000000000.0;
579
                      std::cout << std::fixed << std::setprecision (2) << ts;
580
                      std::cout << " ns: Exiting (" << r3 << ")" << std::endl;
581
                      perfSummary();
582
                      if (logging_enabled) statusFile.close();
583
                      if (profiling_enabled) profileFile.close();
584
                      if (bus_trans_log_enabled) busTransLog.close();
585
                      memdump();
586
                      SIM_RUNNING=0;
587
                      sc_stop();
588
                    }
589
                }
590
            }
591
        }
592 6 julius
    }
593
}       // checkInstruction()
594
 
595 44 julius
 
596 51 julius
//! Method to log execution in terms of calls and returns
597
 
598
void
599
Or1200MonitorSC::callLog()
600
{
601
  uint32_t  exinsn, delaypc;
602
  uint32_t o_a; // operand a
603
  uint32_t o_b; // operand b
604
  struct label_entry *tmp;
605
 
606
  // Instructions should be valid when freeze is low and there are no exceptions
607
  //if (!accessor->getExFreeze())
608
  if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0))
609
    {
610
      //exinsn = accessor->getExInsn();// & 0x3ffffff;
611
      exinsn = accessor->getWbInsn();
612
      // Check the instruction
613
      switch((exinsn >> 26) & 0x3f) { // Check Opcode - top 6 bits
614
      case 0x1:
615
        /* Instruction: l.jal */
616
        o_a = (exinsn >> 0) & 0x3ffffff;
617
        if(o_a & 0x02000000) o_a |= 0xfe000000;
618
 
619
        //delaypc = accessor->getExPC() + (o_a * 4); // PC we're jumping to
620
        delaypc = accessor->getWbPC() + (o_a * 4); // PC we're jumping to
621
        // Now we have info about where we're jumping to. Output the info, with label if possible
622
        // We print the PC we're jumping from + 8 which is the return address
623
        if ( tmp = memoryload->get_label (delaypc) )
624
          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;
625
        else
626
          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;
627
 
628
        break;
629
      case 0x11:
630
        /* Instruction: l.jr */
631
        // Bits 15-11 contain register number
632
        o_b = (exinsn >> 11) & 0x1f;
633
        if (o_b == 9) // l.jr r9 is typical return
634
          {
635
            // Now get the value in this register
636
            delaypc = accessor->getGpr(o_b);
637
            // Output this jump
638
            profileFile << "-" << std::setfill('0') << hex << std::setw(8) << cycle_count << " "  << hex << std::setw(8) << delaypc << endl;
639
          }
640
        break;
641
      case 0x12:
642
        /* Instruction: l.jalr */
643
        o_b = (exinsn >> 11) & 0x1f;
644
        // Now get the value in this register
645
        delaypc = accessor->getGpr(o_b);
646
        // Now we have info about where we're jumping to. Output the info, with label if possible
647
        // We print the PC we're jumping from + 8 which is the return address
648
        if ( tmp = memoryload->get_label (delaypc) )
649
          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;
650
        else
651
          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;
652
 
653
        break;
654
 
655
      }
656
    }
657 57 julius
}       // callLog()
658 51 julius
 
659
 
660 44 julius
//! Method to output the state of the processor
661
 
662
//! This function will output to a file, if enabled, the status of the processor
663 57 julius
//! This copies what the verilog testbench module, or1200_monitor does in it its
664
//! process which calls the display_arch_state tasks. This is designed to be 
665
//! identical to that process, so the output is identical
666 63 julius
 
667 44 julius
void
668
Or1200MonitorSC::displayState()
669
{
670
  // Output the state if we're not frozen and not flushing during a delay slot
671 57 julius
  if (!accessor->getWbFreeze())
672 44 julius
    {
673 57 julius
      if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
674
        {
675
          // Print PC, instruction
676
          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;
677 44 julius
        }
678 63 julius
      // Exception version
679
      else if (accessor->getExceptFlushpipe())
680
        {
681
          // Print PC, instruction, indicate it caused an exception
682
          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;
683
        }
684 57 julius
      else
685 63 julius
        return;
686
    }
687
  else
688
    return;
689
 
690
  if (logging_regs)
691
    {
692
      // Print general purpose register contents
693
      for (int i=0; i<32; i++)
694 57 julius
        {
695 63 julius
          if ((i%4 == 0)&&(i>0)) statusFile << endl;
696
          statusFile << std::setfill('0');
697
          statusFile << "GPR" << dec << std::setw(2) << i << ": " <<  hex << std::setw(8) << (uint32_t) accessor->getGpr(i) << "  ";
698 57 julius
        }
699 63 julius
      statusFile << endl;
700 57 julius
 
701 63 julius
      statusFile << "SR   : " <<  hex << std::setw(8) << (uint32_t) accessor->getSprSr() << "  ";
702
      statusFile << "EPCR0: " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEpcr() << "  ";
703
      statusFile << "EEAR0: " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEear() << "  ";
704
      statusFile << "ESR0 : " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEsr() << endl;
705 57 julius
 
706 44 julius
    }
707 57 julius
 
708 44 julius
  return;
709 57 julius
 
710 44 julius
}       // displayState()
711
 
712 63 julius
//! Method to output the state of the processor in binary format
713
//! File format is simply first byte indicating whether register
714
//! data is included, and then structs of the following type
715
struct s_binary_output_buffer{
716
  long long insn_count;
717
  uint32_t pc;
718
  uint32_t insn;
719
  char exception;
720
  uint32_t regs[32];
721
  uint32_t sr;
722
  uint32_t epcr0;
723
  uint32_t eear0;
724
  uint32_t eser0;
725
} __attribute__((__packed__));
726
 
727
struct s_binary_output_buffer_sans_regs{
728
  long long insn_count;
729
  uint32_t pc;
730
  uint32_t insn;
731
  char exception;
732
} __attribute__((__packed__));
733
 
734
void
735
Or1200MonitorSC::displayStateBinary()
736
{
737
  struct s_binary_output_buffer outbuf;
738
 
739
  // Output the state if we're not frozen and not flushing during a delay slot
740
  if (!accessor->getWbFreeze())
741
    {
742
      if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
743
        {
744
          outbuf.insn_count = insn_count;
745
          outbuf.pc = (uint32_t) accessor->getWbPC();
746
          outbuf.insn = (uint32_t) accessor->getWbInsn();
747
          outbuf.exception = 0;
748
        }
749
      // Exception version
750
      else if (accessor->getExceptFlushpipe())
751
        {
752
          outbuf.insn_count = insn_count;
753
          outbuf.pc = (uint32_t) accessor->getExPC();
754
          outbuf.insn = (uint32_t) accessor->getExInsn();
755
          outbuf.exception = 1;
756
        }
757
      else
758
        return;
759
    }
760
  else
761
    return;
762
 
763
  if (logging_regs)
764
    {
765
      // Print general purpose register contents
766
      for (int i=0; i<32; i++)
767
          outbuf.regs[i] = (uint32_t) accessor->getGpr(i);
768
 
769
      outbuf.sr = (uint32_t) accessor->getSprSr();
770
      outbuf.epcr0 = (uint32_t) accessor->getSprEpcr();
771
      outbuf.eear0 = (uint32_t) accessor->getSprEear();
772
      outbuf.eser0 = (uint32_t) accessor->getSprEsr();
773
 
774
      statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer));
775
 
776
    }
777
  else
778
    statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer_sans_regs));
779
 
780
 
781
 
782
  return;
783
 
784
}       // displayStateBinary()
785
 
786 44 julius
//! Function to calculate the number of instructions performed and the time taken
787
void
788
Or1200MonitorSC::perfSummary()
789
{
790 49 julius
  if (exit_perf_summary_enabled)
791
    {
792
      double ts;
793
      ts = sc_time_stamp().to_seconds() * 1000000000.0;
794
      int cycles = ts / (BENCH_CLK_HALFPERIOD*2); // Number of clock cycles we had
795
 
796
      clock_t finish = clock();
797
      double elapsed_time = (double(finish)-double(start))/CLOCKS_PER_SEC;
798
      // It took elapsed_time seconds to do insn_count instructions. Divide insn_count by the time to get instructions/second.
799
      double ips = (insn_count/elapsed_time);
800
      double mips = (insn_count/elapsed_time)/1000000;
801
      int hertz = (int) ((cycles/elapsed_time)/1000);
802 57 julius
      std::cout << "* Or1200Monitor: simulated " << sc_time_stamp() << ", time elapsed: " << elapsed_time << " seconds" << endl;
803 49 julius
      std::cout << "* Or1200Monitor: simulated " << dec << cycles << " clock cycles, executed at approx " << hertz << "kHz" << endl;
804 63 julius
      std::cout << "* Or1200Monitor: simulated " << insn_count << " instructions, insn/sec. = " << ips /*<< ", mips = " << mips*/ << endl;
805 49 julius
    }
806
  return;
807
}       // perfSummary
808 44 julius
 
809 52 julius
 
810
//! Dump contents of simulation's RAM to file
811
void
812
Or1200MonitorSC::memdump()
813
{
814
  if (!do_memdump) return;
815
  uint32_t current_word;
816
  int size_words = (memdump_end_addr/4) - (memdump_start_addr/4);
817
  if (!(size_words > 0)) return;
818
 
819
  // First try opening the file
820
  memdumpFile.open(memdumpFileName.c_str(), ios::binary); // Open memorydump file
821
  if(memdumpFile.is_open())
822
    {
823
      // If we could open the file then turn on logging
824
      cout << "* Dumping system RAM from  0x" << hex << memdump_start_addr << "-0x" << hex << memdump_end_addr << " to file " << memdumpFileName << endl;
825
 
826
      while (size_words)
827
        {
828
          // Read the data from the simulation memory
829 66 julius
          current_word = accessor->get_mem32(memdump_start_addr);
830 52 julius
          // Change from whatever endian the host is (most
831
          // cases little) to big endian
832
          current_word = htonl(current_word);
833
          memdumpFile.write((char*) &current_word, 4);
834 66 julius
          memdump_start_addr+=4; size_words--;
835 52 julius
        }
836
 
837
      // Ideally we've now finished piping out the data
838
      // not 100% about the endianess of this.
839
    }
840
  memdumpFile.close();
841
 
842
}
843 63 julius
 
844 353 julius
/*
845 63 julius
void
846
Or1200MonitorSC::busMonitor()
847
{
848
 
849
  // This is for the wb_conmax module. Presumably other Wishbone bus arbiters
850
  // will need this section of the code to be re-written appropriately, along
851
  // with the relevent functions in the OrpsocAccess module.
852
 
853
  static busLogStates busLogState = BUS_LOG_IDLE;
854
  static int currentMaster = -1;
855
  static uint32_t currentAddr = 0, currentDataIn = 0;
856
  static uint32_t currentSel = 0, currentSlave = 0;
857
  static bool currentWe = false;
858
  static int cyclesWaited = 0;
859
 
860
  if (bus_trans_log_start_delay_enable)
861
    {
862
      if (sc_time_stamp() >= bus_trans_log_start_delay)
863
        {
864
          // No longer waiting
865
          bus_trans_log_start_delay_enable = false;
866
          cout << "* System log now enabled (time =  " << bus_trans_log_start_delay.to_string() << ")" << endl;
867
        }
868
 
869
      if (bus_trans_log_start_delay_enable)
870
        return;
871
    }
872
 
873
  switch ( busLogState )
874
    {
875
    case BUS_LOG_IDLE:
876
      {
877
        // Check the current granted master's cyc and stb inputs
878
        uint32_t gnt = accessor->getWbArbGrant();
879
        if (accessor->getWbArbMastCycI(gnt) && accessor->getWbArbMastStbI(gnt) &&
880
            !accessor->getWbArbMastAckO(gnt))
881
          {
882
            currentAddr = accessor->getWbArbMastAdrI(gnt);
883
            currentDataIn = accessor->getWbArbMastDatI(gnt);
884
            currentSel = (uint32_t) accessor->getWbArbMastSelI(gnt);
885
            currentSlave = (uint32_t)accessor->getWbArbMastSlaveSelDecoded(gnt)-1;
886
            currentWe = accessor->getWbArbMastWeI(gnt);
887
            currentMaster = gnt;
888
            busLogState = BUS_LOG_WAIT_FOR_ACK;
889
            cyclesWaited = 0;
890
          }
891
      }
892
 
893
      break;
894
 
895
    case BUS_LOG_WAIT_FOR_ACK:
896
 
897
      cyclesWaited++;
898
 
899
      // Check for ACK
900
      if (accessor->getWbArbMastAckO(currentMaster))
901
        {
902
          // Transaction completed
903
          busTransLog << sc_time_stamp() << " M" << currentMaster << " ";
904
          if (currentWe)
905
            busTransLog << " W " << hex << currentSel << " " << hex << std::setfill('0') << std::setw(8) << currentAddr << " S" << dec <<  currentSlave << " " << hex << std::setw(8) << currentDataIn << " " << dec << cyclesWaited << endl;
906
          else
907
            busTransLog << " R " << hex << currentSel << " " << hex << std::setfill('0') << std::setw(8) << currentAddr << " S" << dec << currentSlave << " "  << hex << std::setw(8) << accessor->getWbArbMastDatO(currentMaster) << " " << dec << cyclesWaited << endl;
908
 
909
          busLogState = BUS_LOG_IDLE;
910
        }
911
 
912
      break;
913
 
914
    }
915
 
916
  return;
917
 
918
}       // busMonitor ()
919 353 julius
*/
920 66 julius
void
921
Or1200MonitorSC::simPrintf(uint32_t stackaddr, uint32_t regparam)
922
{
923
 
924
  //cerr << hex << stackaddr << " " << regparam << endl;
925
#define FMTLEN 2000
926
  char fmtstr[FMTLEN];
927
  uint32_t arg;
928
  oraddr_t argaddr;
929
  char *fmtstrend;
930
  char *fmtstrpart = fmtstr;
931
  int tee_exe_log;
932
 
933
  /*simgetstr (stackaddr, regparam);*/
934
  /* Get the format string*/
935
  uint32_t fmtaddr;
936
  int i;
937
  fmtaddr = regparam;
938
 
939
  i = 0;
940
  while (accessor->get_mem8(fmtaddr) != '\0')
941
    {
942
      fmtstr[i++] = accessor->get_mem8(fmtaddr);
943
      fmtaddr++;
944
      if (i == FMTLEN - 1)
945
        break;
946
    }
947
  fmtstr[i] = '\0';
948
 
949
 
950
  argaddr = stackaddr;
951
  int index, last_index;
952
  index = last_index = 0;
953
  char tmp_char;
954
  while (1)
955
    {
956
      /* Look for the next format argument, or end of string */
957
      while (!(fmtstrpart[index] == '\0' || fmtstrpart[index] == '%'))
958
        index++;
959
 
960
      if (fmtstrpart[index] == '\0' && index == last_index)
961
        /* We had something like "%d\0", so we're done*/
962
        return;
963
 
964
      if (fmtstrpart[index] == '\0')
965
        {
966
          /* Final printf */
967
          printf("%s", (char*) fmtstrpart + last_index);
968
          return;
969
        }
970
      else
971
        {
972
          /* We have a section between last_index and index that we should print out*/
973
          fmtstrpart[index] = '\0'; /* Replace % with \0 for now */
974
          printf ("%s",fmtstrpart + last_index);
975
          fmtstrpart[index] = '%'; /* Replace the % */
976
        }
977
 
978
      last_index = index; /* last_index now pointing at the % */
979
 
980
      /* Now extract the part that requires formatting */
981
      /* Look for the end of the format argument*/
982
      while (!(fmtstrpart[index] == 'd' || fmtstrpart[index] == 'i'
983
               || fmtstrpart[index] == 'o' || fmtstrpart[index] == 'u'
984
               || fmtstrpart[index] == 'x' || fmtstrpart[index] == 'X'
985
               || fmtstrpart[index] == 'f' || fmtstrpart[index] == 'e'
986
               || fmtstrpart[index] == 'E' || fmtstrpart[index] == 'g'
987
               || fmtstrpart[index] == 'G' || fmtstrpart[index] == 'c'
988
               || fmtstrpart[index] == 's' || fmtstrpart[index] == '\0'
989
               || fmtstrpart[index+1] == '%'))
990
        index++;
991
 
992
      if (fmtstrpart[index] == '\0')
993
        {
994
          // Error
995
          return;
996
        }
997
      else if (fmtstrpart[index] == '%' && fmtstrpart[index+1] == '%')
998
        {
999
          /* Deal with the %% case to print a single % */
1000
          index++;
1001
          printf("%%");
1002
        }
1003
      else
1004
        {
1005
          /* We now will print the part that requires the next argument */
1006
          /* Same trick, but this time remember what the char was */
1007
          tmp_char = fmtstrpart[index+1];
1008
          fmtstrpart[index+1] = '\0'; /* Replace % with \0 for now */
1009
          /* Check what we're printing*/
1010
          if (fmtstrpart[index] == 's')
1011
            {
1012
              /* It's a string, so pull it out of memory into a local char*
1013
                 and pass it to printf() */
1014
              int tmp_string_len, z;
1015
              /* Assume stackaddr already pointing at appropriate value*/
1016
              oraddr_t ormem_str_ptr = accessor->get_mem32(argaddr);
1017
 
1018
              while (accessor->get_mem8(ormem_str_ptr++) != '\0')
1019
                tmp_string_len++;
1020
              tmp_string_len++; /* One for terminating char */
1021
 
1022
              char* str = (char *) malloc (tmp_string_len);
1023
              if (str == NULL) return; /* Malloc failed, bigger issues than printf'ing out of sim */
1024
              ormem_str_ptr = accessor->get_mem32(argaddr); /* Reset start pointer value*/
1025
              for (z=0;z<tmp_string_len;z++)
1026
                str[z] = accessor->get_mem8(ormem_str_ptr+z);
1027
 
1028
              printf (fmtstrpart + last_index, str);
1029
              free (str);
1030
            }
1031
          else
1032
            {
1033
              /*
1034
                 Some other kind of variable, pull it off the stack and print
1035
                 it out. Assume stackaddr already pointing at appropriate
1036
                 value
1037
              */
1038
              arg = accessor->get_mem32(argaddr);
1039
              printf (fmtstrpart + last_index, arg);
1040
            }
1041
          argaddr+= 4; /* Increment argument pointer in stack */
1042
          fmtstrpart[index+1] = tmp_char; /* Replace the char we took out */
1043
        }
1044
      index++;
1045
      last_index = index;
1046
    }
1047
 
1048
  return;
1049
}       // simPrintf ()

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.