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

Subversion Repositories openrisc

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

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
          std::cout << " ns: printf" << std::endl;
447
          break;
448
 
449
        case NOP_PUTC:
450
          r3 = accessor->getGpr (3);
451
          std::cout << (char)r3 << std::flush;
452
          break;
453 63 julius
        case NOP_CNT_RESET:
454
          std::cout << "****************** counters reset ******************" << endl;
455
          std::cout << "since last reset: cycles " << cycle_count - cycle_count_rst << ", insn #" << insn_count - insn_count_rst << endl;
456
          std::cout << "****************** counters reset ******************" << endl;
457
          cycle_count_rst = cycle_count;
458
          insn_count_rst = insn_count;
459 6 julius
        default:
460
          break;
461
        }
462 63 julius
 
463
      if (monitor_for_crash)
464
        {
465
          current_WbPC = accessor->getWbPC();
466
          // Look at current instruction
467
          if (current_WbInsn == 0x00000000)
468
            {
469
              // Looks like we've jumped somewhere incorrectly
470
              lookslikewevecrashed_count++;
471
            }
472
#define CRASH_MONITOR_LOG_BAD_INSNS 1
473
#if CRASH_MONITOR_LOG_BAD_INSNS
474
 
475
          /* Log so-called "bad" instructions, or at least instructions we
476
          executed, no matter if they caused us to increment
477
          lookslikewevecrashed_count, this way we get them in our list too */
478
          if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
479
            {
480
              crash_monitor_buffer[crash_monitor_buffer_head][0] = current_WbPC;
481
              crash_monitor_buffer[crash_monitor_buffer_head][1] = current_WbInsn;
482
              /* Circular buffer */
483
              if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
484
                crash_monitor_buffer_head++;
485
              else
486
                crash_monitor_buffer_head = 0;
487
 
488
            }
489
 
490
#else
491
          else if (((current_WbInsn & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(current_WbInsn & (1<<16)))
492
          {
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
              /* Reset this */
503
              lookslikewevecrashed_count  = 0;
504
            }
505
#endif    
506
          if (wait_for_stall_cmd_response)
507
            {
508
              // We've already crashed, and we're issued a command to stall the
509
              // processor to the system C debug unit interface, and we're
510
              // waiting for this debug unit to send back the message that we've
511
              // stalled.
512
              char readChar;
513
              int n = read(monitor_to_gdb_pipe[1][0], &readChar, sizeof(char));
514
              if (!( ((n < 0) && (errno == EAGAIN)) || (n==0) ))
515
                wait_for_stall_cmd_response = false; // We got response
516
              lookslikewevecrashed_count = 0;
517
 
518
            }
519
          else if (lookslikewevecrashed_count > 0)
520
            {
521
 
522
              if (lookslikewevecrashed_count >= CRASH_MONITOR_BUFFER_SIZE/4)
523
                {
524
                  /* Probably crashed. Bail out, print out buffer */
525
                  std::cout << "********************************************************************************"<< endl;
526
                  std::cout << "* Looks like processor crashed. Printing last " << CRASH_MONITOR_BUFFER_SIZE << " instructions executed:" << endl;
527
 
528
                  int crash_monitor_buffer_head_end = (crash_monitor_buffer_head > 0) ? crash_monitor_buffer_head - 1 : CRASH_MONITOR_BUFFER_SIZE-1;
529
                  while (crash_monitor_buffer_head != crash_monitor_buffer_head_end)
530
                    {
531
                      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;
532
 
533
                      if(crash_monitor_buffer_head < CRASH_MONITOR_BUFFER_SIZE-1)
534
                        crash_monitor_buffer_head++;
535
                      else
536
                        crash_monitor_buffer_head = 0;
537
                    }
538
                  std::cout << "********************************************************************************"<< endl;
539
 
540
                  if ( (monitor_to_gdb_pipe[0][0] != NULL))
541
                    {
542
                      // If GDB server is running, we'll pass control back to
543
                      // the debugger instead of just quitting.
544
                      char interrupt = 0x3; // Arbitrary
545
                      write(monitor_to_gdb_pipe[0][1],&interrupt,sizeof(char));
546
                      wait_for_stall_cmd_response = true;
547
                      lookslikewevecrashed_count = 0;
548
                      std::cout << "* Stalling processor and returning control to GDB"<< endl;
549
                      // 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.
550
                      // 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).
551
                      wait_for_stall_cmd_response = true;
552
 
553
                    }
554
                  else
555
                    {
556
                      // Close down sim end exit
557
                      ts = sc_time_stamp().to_seconds() * 1000000000.0;
558
                      std::cout << std::fixed << std::setprecision (2) << ts;
559
                      std::cout << " ns: Exiting (" << r3 << ")" << std::endl;
560
                      perfSummary();
561
                      if (logging_enabled) statusFile.close();
562
                      if (profiling_enabled) profileFile.close();
563
                      if (bus_trans_log_enabled) busTransLog.close();
564
                      memdump();
565
                      SIM_RUNNING=0;
566
                      sc_stop();
567
                    }
568
                }
569
            }
570
        }
571 6 julius
    }
572
}       // checkInstruction()
573
 
574 44 julius
 
575 51 julius
//! Method to log execution in terms of calls and returns
576
 
577
void
578
Or1200MonitorSC::callLog()
579
{
580
  uint32_t  exinsn, delaypc;
581
  uint32_t o_a; // operand a
582
  uint32_t o_b; // operand b
583
  struct label_entry *tmp;
584
 
585
  // Instructions should be valid when freeze is low and there are no exceptions
586
  //if (!accessor->getExFreeze())
587
  if ((!accessor->getWbFreeze()) && (accessor->getExceptType() == 0))
588
    {
589
      //exinsn = accessor->getExInsn();// & 0x3ffffff;
590
      exinsn = accessor->getWbInsn();
591
      // Check the instruction
592
      switch((exinsn >> 26) & 0x3f) { // Check Opcode - top 6 bits
593
      case 0x1:
594
        /* Instruction: l.jal */
595
        o_a = (exinsn >> 0) & 0x3ffffff;
596
        if(o_a & 0x02000000) o_a |= 0xfe000000;
597
 
598
        //delaypc = accessor->getExPC() + (o_a * 4); // PC we're jumping to
599
        delaypc = accessor->getWbPC() + (o_a * 4); // PC we're jumping to
600
        // Now we have info about where we're jumping to. Output the info, with label if possible
601
        // We print the PC we're jumping from + 8 which is the return address
602
        if ( tmp = memoryload->get_label (delaypc) )
603
          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;
604
        else
605
          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;
606
 
607
        break;
608
      case 0x11:
609
        /* Instruction: l.jr */
610
        // Bits 15-11 contain register number
611
        o_b = (exinsn >> 11) & 0x1f;
612
        if (o_b == 9) // l.jr r9 is typical return
613
          {
614
            // Now get the value in this register
615
            delaypc = accessor->getGpr(o_b);
616
            // Output this jump
617
            profileFile << "-" << std::setfill('0') << hex << std::setw(8) << cycle_count << " "  << hex << std::setw(8) << delaypc << endl;
618
          }
619
        break;
620
      case 0x12:
621
        /* Instruction: l.jalr */
622
        o_b = (exinsn >> 11) & 0x1f;
623
        // Now get the value in this register
624
        delaypc = accessor->getGpr(o_b);
625
        // Now we have info about where we're jumping to. Output the info, with label if possible
626
        // We print the PC we're jumping from + 8 which is the return address
627
        if ( tmp = memoryload->get_label (delaypc) )
628
          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;
629
        else
630
          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;
631
 
632
        break;
633
 
634
      }
635
    }
636 57 julius
}       // callLog()
637 51 julius
 
638
 
639 44 julius
//! Method to output the state of the processor
640
 
641
//! This function will output to a file, if enabled, the status of the processor
642 57 julius
//! This copies what the verilog testbench module, or1200_monitor does in it its
643
//! process which calls the display_arch_state tasks. This is designed to be 
644
//! identical to that process, so the output is identical
645 63 julius
 
646 44 julius
void
647
Or1200MonitorSC::displayState()
648
{
649
  // Output the state if we're not frozen and not flushing during a delay slot
650 57 julius
  if (!accessor->getWbFreeze())
651 44 julius
    {
652 57 julius
      if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
653
        {
654
          // Print PC, instruction
655
          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;
656 44 julius
        }
657 63 julius
      // Exception version
658
      else if (accessor->getExceptFlushpipe())
659
        {
660
          // Print PC, instruction, indicate it caused an exception
661
          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;
662
        }
663 57 julius
      else
664 63 julius
        return;
665
    }
666
  else
667
    return;
668
 
669
  if (logging_regs)
670
    {
671
      // Print general purpose register contents
672
      for (int i=0; i<32; i++)
673 57 julius
        {
674 63 julius
          if ((i%4 == 0)&&(i>0)) statusFile << endl;
675
          statusFile << std::setfill('0');
676
          statusFile << "GPR" << dec << std::setw(2) << i << ": " <<  hex << std::setw(8) << (uint32_t) accessor->getGpr(i) << "  ";
677 57 julius
        }
678 63 julius
      statusFile << endl;
679 57 julius
 
680 63 julius
      statusFile << "SR   : " <<  hex << std::setw(8) << (uint32_t) accessor->getSprSr() << "  ";
681
      statusFile << "EPCR0: " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEpcr() << "  ";
682
      statusFile << "EEAR0: " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEear() << "  ";
683
      statusFile << "ESR0 : " <<  hex << std::setw(8) << (uint32_t) accessor->getSprEsr() << endl;
684 57 julius
 
685 44 julius
    }
686 57 julius
 
687 44 julius
  return;
688 57 julius
 
689 44 julius
}       // displayState()
690
 
691 63 julius
//! Method to output the state of the processor in binary format
692
//! File format is simply first byte indicating whether register
693
//! data is included, and then structs of the following type
694
struct s_binary_output_buffer{
695
  long long insn_count;
696
  uint32_t pc;
697
  uint32_t insn;
698
  char exception;
699
  uint32_t regs[32];
700
  uint32_t sr;
701
  uint32_t epcr0;
702
  uint32_t eear0;
703
  uint32_t eser0;
704
} __attribute__((__packed__));
705
 
706
struct s_binary_output_buffer_sans_regs{
707
  long long insn_count;
708
  uint32_t pc;
709
  uint32_t insn;
710
  char exception;
711
} __attribute__((__packed__));
712
 
713
void
714
Or1200MonitorSC::displayStateBinary()
715
{
716
  struct s_binary_output_buffer outbuf;
717
 
718
  // Output the state if we're not frozen and not flushing during a delay slot
719
  if (!accessor->getWbFreeze())
720
    {
721
      if ((((accessor->getWbInsn() & 0xfc000000) != (uint32_t) OR1200_OR32_NOP) || !(accessor->getWbInsn() & (1<<16))) && !(accessor->getExceptFlushpipe() && accessor->getExDslot()))
722
        {
723
          outbuf.insn_count = insn_count;
724
          outbuf.pc = (uint32_t) accessor->getWbPC();
725
          outbuf.insn = (uint32_t) accessor->getWbInsn();
726
          outbuf.exception = 0;
727
        }
728
      // Exception version
729
      else if (accessor->getExceptFlushpipe())
730
        {
731
          outbuf.insn_count = insn_count;
732
          outbuf.pc = (uint32_t) accessor->getExPC();
733
          outbuf.insn = (uint32_t) accessor->getExInsn();
734
          outbuf.exception = 1;
735
        }
736
      else
737
        return;
738
    }
739
  else
740
    return;
741
 
742
  if (logging_regs)
743
    {
744
      // Print general purpose register contents
745
      for (int i=0; i<32; i++)
746
          outbuf.regs[i] = (uint32_t) accessor->getGpr(i);
747
 
748
      outbuf.sr = (uint32_t) accessor->getSprSr();
749
      outbuf.epcr0 = (uint32_t) accessor->getSprEpcr();
750
      outbuf.eear0 = (uint32_t) accessor->getSprEear();
751
      outbuf.eser0 = (uint32_t) accessor->getSprEsr();
752
 
753
      statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer));
754
 
755
    }
756
  else
757
    statusFile.write((char*)&outbuf, sizeof(struct s_binary_output_buffer_sans_regs));
758
 
759
 
760
 
761
  return;
762
 
763
}       // displayStateBinary()
764
 
765 44 julius
//! Function to calculate the number of instructions performed and the time taken
766
void
767
Or1200MonitorSC::perfSummary()
768
{
769 49 julius
  if (exit_perf_summary_enabled)
770
    {
771
      double ts;
772
      ts = sc_time_stamp().to_seconds() * 1000000000.0;
773
      int cycles = ts / (BENCH_CLK_HALFPERIOD*2); // Number of clock cycles we had
774
 
775
      clock_t finish = clock();
776
      double elapsed_time = (double(finish)-double(start))/CLOCKS_PER_SEC;
777
      // It took elapsed_time seconds to do insn_count instructions. Divide insn_count by the time to get instructions/second.
778
      double ips = (insn_count/elapsed_time);
779
      double mips = (insn_count/elapsed_time)/1000000;
780
      int hertz = (int) ((cycles/elapsed_time)/1000);
781 57 julius
      std::cout << "* Or1200Monitor: simulated " << sc_time_stamp() << ", time elapsed: " << elapsed_time << " seconds" << endl;
782 49 julius
      std::cout << "* Or1200Monitor: simulated " << dec << cycles << " clock cycles, executed at approx " << hertz << "kHz" << endl;
783 63 julius
      std::cout << "* Or1200Monitor: simulated " << insn_count << " instructions, insn/sec. = " << ips /*<< ", mips = " << mips*/ << endl;
784 49 julius
    }
785
  return;
786
}       // perfSummary
787 44 julius
 
788 52 julius
 
789
//! Dump contents of simulation's RAM to file
790
void
791
Or1200MonitorSC::memdump()
792
{
793
  if (!do_memdump) return;
794
  uint32_t current_word;
795
  int size_words = (memdump_end_addr/4) - (memdump_start_addr/4);
796
  if (!(size_words > 0)) return;
797
 
798
  // First try opening the file
799
  memdumpFile.open(memdumpFileName.c_str(), ios::binary); // Open memorydump file
800
  if(memdumpFile.is_open())
801
    {
802
      // If we could open the file then turn on logging
803
      cout << "* Dumping system RAM from  0x" << hex << memdump_start_addr << "-0x" << hex << memdump_end_addr << " to file " << memdumpFileName << endl;
804
 
805
      // Convert memdump_start_addr to word address
806
      memdump_start_addr = memdump_start_addr / 4;
807
      while (size_words)
808
        {
809
          // Read the data from the simulation memory
810
          current_word = accessor->get_mem(memdump_start_addr);
811
          //cout << hex << current_word << " ";
812
          /*
813
          cout << hex << ((current_word >> 24 ) & 0xff) << " ";
814
          cout << hex << ((current_word >> 16) & 0xff) << " ";
815
          cout << hex << ((current_word >> 8 ) & 0xff) << " " ;
816
          cout << hex << ((current_word >> 0 ) & 0xff) << " ";
817
          */
818
          // Change from whatever endian the host is (most
819
          // cases little) to big endian
820
          current_word = htonl(current_word);
821
          memdumpFile.write((char*) &current_word, 4);
822
          memdump_start_addr++; size_words--;
823
        }
824
 
825
      // Ideally we've now finished piping out the data
826
      // not 100% about the endianess of this.
827
    }
828
  memdumpFile.close();
829
 
830
}
831 63 julius
 
832
 
833
void
834
Or1200MonitorSC::busMonitor()
835
{
836
 
837
  // This is for the wb_conmax module. Presumably other Wishbone bus arbiters 
838
  // will need this section of the code to be re-written appropriately, along 
839
  // with the relevent functions in the OrpsocAccess module.
840
 
841
  static busLogStates busLogState = BUS_LOG_IDLE;
842
  static int currentMaster = -1;
843
  static uint32_t currentAddr = 0, currentDataIn = 0;
844
  static uint32_t currentSel = 0, currentSlave = 0;
845
  static bool currentWe = false;
846
  static int cyclesWaited = 0;
847
 
848
  if (bus_trans_log_start_delay_enable)
849
    {
850
      if (sc_time_stamp() >= bus_trans_log_start_delay)
851
        {
852
          // No longer waiting
853
          bus_trans_log_start_delay_enable = false;
854
          cout << "* System log now enabled (time =  " << bus_trans_log_start_delay.to_string() << ")" << endl;
855
        }
856
 
857
      if (bus_trans_log_start_delay_enable)
858
        return;
859
    }
860
 
861
  switch ( busLogState )
862
    {
863
    case BUS_LOG_IDLE:
864
      {
865
        // Check the current granted master's cyc and stb inputs
866
        uint32_t gnt = accessor->getWbArbGrant();
867
        if (accessor->getWbArbMastCycI(gnt) && accessor->getWbArbMastStbI(gnt) &&
868
            !accessor->getWbArbMastAckO(gnt))
869
          {
870
            currentAddr = accessor->getWbArbMastAdrI(gnt);
871
            currentDataIn = accessor->getWbArbMastDatI(gnt);
872
            currentSel = (uint32_t) accessor->getWbArbMastSelI(gnt);
873
            currentSlave = (uint32_t)accessor->getWbArbMastSlaveSelDecoded(gnt)-1;
874
            currentWe = accessor->getWbArbMastWeI(gnt);
875
            currentMaster = gnt;
876
            busLogState = BUS_LOG_WAIT_FOR_ACK;
877
            cyclesWaited = 0;
878
          }
879
      }
880
 
881
      break;
882
 
883
    case BUS_LOG_WAIT_FOR_ACK:
884
 
885
      cyclesWaited++;
886
 
887
      // Check for ACK
888
      if (accessor->getWbArbMastAckO(currentMaster))
889
        {
890
          // Transaction completed
891
          busTransLog << sc_time_stamp() << " M" << currentMaster << " ";
892
          if (currentWe)
893
            busTransLog << " W " << hex << currentSel << " " << hex << std::setfill('0') << std::setw(8) << currentAddr << " S" << dec <<  currentSlave << " " << hex << std::setw(8) << currentDataIn << " " << dec << cyclesWaited << endl;
894
          else
895
            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;
896
 
897
          busLogState = BUS_LOG_IDLE;
898
        }
899
 
900
      break;
901
 
902
    }
903
 
904
  return;
905
 
906
}       // busMonitor ()

powered by: WebSVN 2.1.0

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