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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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