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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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