origen_sim 0.11.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7de67b84a878cf189e64f455cfa1ab4525a5711b
4
- data.tar.gz: d091d30647c88bb40cd6fe305e158c6cb823113e
3
+ metadata.gz: c34ffd12e0b7df9632e5bad4dcb933cb46f88460
4
+ data.tar.gz: 6690aac5bb4335ac2de29b1757249eba1be026c0
5
5
  SHA512:
6
- metadata.gz: c0fda1a65fb6108cd8ec8e7020ec24c00770f433e268b2c359da210d04ab2f4e21c385fac925ddc819f6fd6efc1149b455c4d59f622ec86d34f3802ac5761b9c
7
- data.tar.gz: e1b129ab59cf25562e596c31fa05ef947833300bb3136d739d025afeb9dda4ea057af0768c66fde9e3911187c4cfaedea0fd21964f14ac68e2ec59de69ab6f00
6
+ metadata.gz: 71a090ebaa9f1440d3052773b0823187ada5fc10aab7786081b0c8274e079c78b6aab0866d85c90e7f6193c5a243d3c98012cf99e9d13b7078a4924510e3dda2
7
+ data.tar.gz: a617b1e824ef7b9c36583df618440115f35aac94462b1d9a9601f917444360729d81a26235d72bc5dd2aa91f90e398d1d240233feec2ec0d07e568ae38219d47
@@ -1,7 +1,7 @@
1
1
  module OrigenSim
2
2
  MAJOR = 0
3
- MINOR = 11
4
- BUGFIX = 1
3
+ MINOR = 12
4
+ BUGFIX = 0
5
5
  DEV = nil
6
6
 
7
7
  VERSION = [MAJOR, MINOR, BUGFIX].join(".") + (DEV ? ".pre#{DEV}" : '')
@@ -12,9 +12,10 @@
12
12
  #include <string.h>
13
13
 
14
14
  #define MAX_NUMBER_PINS 2000
15
- #define MAX_WAVE_EVENTS 10
15
+ #define MAX_WAVE_EVENTS 50
16
16
 
17
17
  typedef struct Pin {
18
+ char *name;
18
19
  vpiHandle data; // A handle to the driver data register
19
20
  vpiHandle drive; // A handle to the driver drive enable register
20
21
  vpiHandle force_data; // A handle to the driver force_data register
@@ -27,6 +28,7 @@ typedef struct Pin {
27
28
  int index; // The pin's index in the pins array
28
29
  int previous_state; // Used to keep track of whether the pin was previously driving or comparing
29
30
  bool capture_en; // Used to indicated when compare data should be captured instead of compared
31
+ bool present; // Set to true if the pin is present in the testbench
30
32
  } Pin;
31
33
 
32
34
  typedef struct Event {
@@ -76,12 +78,15 @@ static void bridge_define_pin(char * name, char * pin_ix, char * drive_wave_ix,
76
78
  Pin *pin = &pins[index];
77
79
  number_of_pins += 1;
78
80
 
81
+ (*pin).name = malloc(strlen(name) + 1);
82
+ strcpy((*pin).name, name);
79
83
  (*pin).index = index;
80
84
  (*pin).drive_wave = atoi(drive_wave_ix);
81
85
  (*pin).compare_wave = atoi(compare_wave_ix);
82
86
  (*pin).previous_state = 0;
83
87
  (*pin).capture_en = false;
84
88
 
89
+
85
90
  char * driver = (char *) malloc(strlen(name) + 16);
86
91
  strcpy(driver, ORIGEN_SIM_TESTBENCH_CAT("pins."));
87
92
  strcat(driver, name);
@@ -92,6 +97,13 @@ static void bridge_define_pin(char * name, char * pin_ix, char * drive_wave_ix,
92
97
  (*pin).data = vpi_handle_by_name(data, NULL);
93
98
  free(data);
94
99
 
100
+ if (!(*pin).data) {
101
+ vpi_printf("WARNING: Your DUT defines pin '%s', however it is not present in the testbench and will be ignored\n", (*pin).name);
102
+ (*pin).present = false;
103
+ } else {
104
+ (*pin).present = true;
105
+ }
106
+
95
107
  char * drive = (char *) malloc(strlen(driver) + 16);
96
108
  strcpy(drive, driver);
97
109
  strcat(drive, ".drive");
@@ -254,6 +266,10 @@ static void bridge_disable_compare_wave(Pin * pin) {
254
266
 
255
267
 
256
268
  static void bridge_clear_waves_and_pins() {
269
+ for (int i = 0; i < number_of_pins; i++) {
270
+ Pin *pin = &pins[i];
271
+ free((*pin).name);
272
+ }
257
273
  number_of_pins = 0;
258
274
  number_of_drive_waves = 0;
259
275
  number_of_compare_waves = 0;
@@ -286,30 +302,32 @@ static void bridge_drive_pin(char * index, char * val) {
286
302
  Pin *pin = &pins[atoi(index)];
287
303
  s_vpi_value v = {vpiIntVal, {0}};
288
304
 
289
- // Apply the data value to the pin's driver
290
- v.value.integer = (val[0] - '0');
291
- vpi_put_value((*pin).data, &v, NULL, vpiNoDelay);
292
- // Make sure not comparing
293
- v.value.integer = 0;
294
- vpi_put_value((*pin).compare, &v, NULL, vpiNoDelay);
295
-
296
- // Register it as actively driving with it's wave
297
-
298
- // If it is already driving the wave will already be setup
299
- if ((*pin).previous_state != 1) {
300
- // If the drive is for the whole cycle, then we can enable it here
301
- // and don't need a callback
302
- if (bridge_is_drive_whole_cycle(pin)) {
303
- v.value.integer = 1;
304
- vpi_put_value((*pin).drive, &v, NULL, vpiNoDelay);
305
- } else {
306
- bridge_enable_drive_wave(pin);
307
- }
305
+ if ((*pin).present) {
306
+ // Apply the data value to the pin's driver
307
+ v.value.integer = (val[0] - '0');
308
+ vpi_put_value((*pin).data, &v, NULL, vpiNoDelay);
309
+ // Make sure not comparing
310
+ v.value.integer = 0;
311
+ vpi_put_value((*pin).compare, &v, NULL, vpiNoDelay);
312
+
313
+ // Register it as actively driving with it's wave
314
+
315
+ // If it is already driving the wave will already be setup
316
+ if ((*pin).previous_state != 1) {
317
+ // If the drive is for the whole cycle, then we can enable it here
318
+ // and don't need a callback
319
+ if (bridge_is_drive_whole_cycle(pin)) {
320
+ v.value.integer = 1;
321
+ vpi_put_value((*pin).drive, &v, NULL, vpiNoDelay);
322
+ } else {
323
+ bridge_enable_drive_wave(pin);
324
+ }
308
325
 
309
- if ((*pin).previous_state == 2) {
310
- bridge_disable_compare_wave(pin);
326
+ if ((*pin).previous_state == 2) {
327
+ bridge_disable_compare_wave(pin);
328
+ }
329
+ (*pin).previous_state = 1;
311
330
  }
312
- (*pin).previous_state = 1;
313
331
  }
314
332
  }
315
333
 
@@ -319,23 +337,25 @@ static void bridge_compare_pin(char * index, char * val) {
319
337
  Pin *pin = &pins[atoi(index)];
320
338
  s_vpi_value v = {vpiIntVal, {0}};
321
339
 
322
- // Apply the data value to the pin's driver, don't enable compare yet,
323
- // the wave will do that later
324
- v.value.integer = (val[0] - '0');
325
- vpi_put_value((*pin).data, &v, NULL, vpiNoDelay);
326
- // Make sure not driving
327
- v.value.integer = 0;
328
- vpi_put_value((*pin).drive, &v, NULL, vpiNoDelay);
329
-
330
- // Register it as actively comparing with it's wave
331
-
332
- // If it is already comparing the wave will already be setup
333
- if ((*pin).previous_state != 2) {
334
- bridge_enable_compare_wave(pin);
335
- if ((*pin).previous_state == 1) {
336
- bridge_disable_drive_wave(pin);
340
+ if ((*pin).present) {
341
+ // Apply the data value to the pin's driver, don't enable compare yet,
342
+ // the wave will do that later
343
+ v.value.integer = (val[0] - '0');
344
+ vpi_put_value((*pin).data, &v, NULL, vpiNoDelay);
345
+ // Make sure not driving
346
+ v.value.integer = 0;
347
+ vpi_put_value((*pin).drive, &v, NULL, vpiNoDelay);
348
+
349
+ // Register it as actively comparing with it's wave
350
+
351
+ // If it is already comparing the wave will already be setup
352
+ if ((*pin).previous_state != 2) {
353
+ bridge_enable_compare_wave(pin);
354
+ if ((*pin).previous_state == 1) {
355
+ bridge_disable_drive_wave(pin);
356
+ }
357
+ (*pin).previous_state = 2;
337
358
  }
338
- (*pin).previous_state = 2;
339
359
  }
340
360
  }
341
361
 
@@ -361,21 +381,23 @@ static void bridge_dont_care_pin(char * index) {
361
381
  Pin *pin = &pins[atoi(index)];
362
382
  s_vpi_value v = {vpiIntVal, {0}};
363
383
 
364
- // Disable drive and compare on the pin's driver
365
- v.value.integer = 0;
366
- vpi_put_value((*pin).drive, &v, NULL, vpiNoDelay);
367
- vpi_put_value((*pin).compare, &v, NULL, vpiNoDelay);
384
+ if ((*pin).present) {
385
+ // Disable drive and compare on the pin's driver
386
+ v.value.integer = 0;
387
+ vpi_put_value((*pin).drive, &v, NULL, vpiNoDelay);
388
+ vpi_put_value((*pin).compare, &v, NULL, vpiNoDelay);
368
389
 
369
- if ((*pin).previous_state != 0) {
370
- if ((*pin).previous_state == 1) {
371
- if (!bridge_is_drive_whole_cycle(pin)) {
372
- bridge_disable_drive_wave(pin);
390
+ if ((*pin).previous_state != 0) {
391
+ if ((*pin).previous_state == 1) {
392
+ if (!bridge_is_drive_whole_cycle(pin)) {
393
+ bridge_disable_drive_wave(pin);
394
+ }
373
395
  }
396
+ if ((*pin).previous_state == 2) {
397
+ bridge_disable_compare_wave(pin);
398
+ }
399
+ (*pin).previous_state = 0;
374
400
  }
375
- if ((*pin).previous_state == 2) {
376
- bridge_disable_compare_wave(pin);
377
- }
378
- (*pin).previous_state = 0;
379
401
  }
380
402
  }
381
403
 
@@ -91,6 +91,28 @@ module OrigenSim
91
91
  @stderr_string_exceptions = val
92
92
  end
93
93
 
94
+ def self.warning_strings
95
+ @warning_strings ||= ['WARNING']
96
+ end
97
+
98
+ def self.warning_strings=(val)
99
+ unless val.is_a?(Array)
100
+ fail 'OrigenSim.warning_strings can only be set to an array of string values!'
101
+ end
102
+ @warning_strings = val
103
+ end
104
+
105
+ def self.warning_string_exceptions
106
+ @warning_string_exceptions ||= []
107
+ end
108
+
109
+ def self.warning_string_exceptions=(val)
110
+ unless val.is_a?(Array)
111
+ fail 'OrigenSim.warning_string_exceptions can only be set to an array of string values!'
112
+ end
113
+ @warning_string_exceptions = val
114
+ end
115
+
94
116
  def self.log_strings
95
117
  @log_strings ||= []
96
118
  end
@@ -28,10 +28,17 @@ module OrigenSim
28
28
  @error_count = 0
29
29
  @socket_ids = {}
30
30
 
31
- @server = UNIXServer.new(socket_id) # Socket used to send Origen -> Verilog commands
31
+ # Socket used to send Origen -> Verilog commands
32
+ @server = UNIXServer.new(socket_id)
33
+
34
+ # Socket used to capture STDOUT from the simulator
32
35
  @server_stdout = UNIXServer.new(socket_id(:stdout))
36
+ # Socket used to capture STDERR from the simulator
33
37
  @server_stderr = UNIXServer.new(socket_id(:stderr))
38
+ # Socket used to send a heartbeat pulse from Origen to process running the simulator
34
39
  @server_heartbeat = UNIXServer.new(socket_id(:heartbeat))
40
+ # Socket used to receive status updates from the process running the simulator
41
+ @server_status = UNIXServer.new(socket_id(:status))
35
42
  end
36
43
 
37
44
  def failed?(in_progress = false)
@@ -54,7 +61,11 @@ module OrigenSim
54
61
  def log_results(in_progress = false)
55
62
  if failed?(in_progress)
56
63
  if failed_to_start
57
- Origen.log.error 'The simulation failed to start!'
64
+ if Origen.debugger_enabled?
65
+ Origen.log.error 'The simulation failed to get underway!'
66
+ else
67
+ Origen.log.error 'The simulation failed to get underway! (run again with -d to see why)'
68
+ end
58
69
  else
59
70
  if in_progress
60
71
  Origen.log.error "The simulation has #{error_count} error#{error_count > 1 ? 's' : ''}!" if error_count > 0
@@ -80,7 +91,6 @@ module OrigenSim
80
91
  # heartbeats.
81
92
  def start_heartbeat
82
93
  @heartbeat = @server_heartbeat.accept
83
- @pid = @heartbeat.gets.chomp.to_i
84
94
  @heartbeat_thread = Heartbeat.new(@heartbeat)
85
95
  end
86
96
 
@@ -89,16 +99,66 @@ module OrigenSim
89
99
  end
90
100
 
91
101
  # Open the communication channels with the simulator
92
- def open
93
- start_heartbeat
94
- @stdout = @server_stdout.accept
95
- @stderr = @server_stderr.accept
96
- @socket = @server.accept
97
- @stdout_reader = StdoutReader.new(@stdout)
98
- @stderr_reader = StderrReader.new(@stderr)
102
+ def open(timeout)
103
+ timeout_connection(timeout) do
104
+ start_heartbeat
105
+ @stdout = @server_stdout.accept
106
+ @stderr = @server_stderr.accept
107
+ @status = @server_status.accept
108
+ @stdout_reader = StdoutReader.new(@stdout)
109
+ @stderr_reader = StderrReader.new(@stderr)
110
+
111
+ Origen.log.debug 'The simulation monitor has started'
112
+ Origen.log.debug @status.gets.chomp # Starting simulator
113
+ Origen.log.debug @status.gets.chomp # Simulator has started
114
+ response = @status.gets.chomp
115
+ if response =~ /finished/
116
+ abort_connection
117
+ else
118
+ @pid = response.to_i
119
+ end
120
+ # That's all status info done until the simulation process ends, start a thread
121
+ # to wait for that in case it ends before the VPI starts
122
+ Thread.new do
123
+ Origen.log.debug @status.gets.chomp # This will block until something is received
124
+ abort_connection
125
+ end
126
+ Origen.log.debug 'Waiting for Origen VPI to start...'
127
+
128
+ # This will block until the VPI extension is invoked and connects to the socket
129
+ @socket = @server.accept
130
+
131
+ @connection_established = true # Cancels timeout_connection
132
+ if @connection_aborted
133
+ self.failed_to_start = true
134
+ log_results
135
+ exit # Assume it is not worth trying another pattern in this case, some kind of environment/config issue
136
+ end
137
+ Origen.log.debug 'Origen VPI has started'
138
+ end
139
+
99
140
  @opened = true
100
141
  end
101
142
 
143
+ def timeout_connection(wait_in_s)
144
+ @connection_aborted = false
145
+ @connection_established = false
146
+ Thread.new do
147
+ sleep wait_in_s
148
+ abort_connection # Will do nothing if a successful connection has been made while we were waiting
149
+ end
150
+ yield
151
+ end
152
+
153
+ def abort_connection
154
+ # If the Verilog process has not established a connection yet, then make one to
155
+ # release our process and then exit
156
+ unless @connection_established
157
+ @connection_aborted = true
158
+ UNIXSocket.new(socket_id).puts("Time out\n")
159
+ end
160
+ end
161
+
102
162
  # Close all communication channels with the simulator
103
163
  def close
104
164
  return unless @opened
@@ -352,6 +352,7 @@ module OrigenSim
352
352
 
353
353
  # Starts up the simulator process
354
354
  def start
355
+ Origen.log.level = :verbose if Origen.debugger_enabled?
355
356
  @simulation_open = true
356
357
  @simulation = Simulation.new(wave_file_basename, view_wave_command)
357
358
  simulations << @simulation
@@ -378,16 +379,20 @@ module OrigenSim
378
379
  exit!
379
380
  end
380
381
 
382
+ status = UNIXSocket.new('#{simulation.socket_id(:status)}')
381
383
  stdout_socket = UNIXSocket.new('#{simulation.socket_id(:stdout)}')
382
384
  stderr_socket = UNIXSocket.new('#{simulation.socket_id(:stderr)}')
383
385
  heartbeat = UNIXSocket.new('#{simulation.socket_id(:heartbeat)}')
384
386
 
385
387
  begin
386
388
 
389
+ status.puts('Starting the simulator...')
390
+
387
391
  Dir.chdir '#{run_dir}' do
388
392
  Open3.popen3('#{cmd}') do |stdin, stdout, stderr, thread|
393
+ status.puts('The simulator has started')
389
394
  pid = stdout.gets.strip.to_i
390
- heartbeat.puts(pid.to_s)
395
+ status.puts(pid.to_s)
391
396
 
392
397
  # Listen for a heartbeat from the main Origen process every 5 seconds, kill the
393
398
  # simulator after two missed heartbeats
@@ -433,27 +438,26 @@ module OrigenSim
433
438
  end
434
439
  end
435
440
 
441
+ status.puts 'The simulator has finished'
442
+
436
443
  ensure
437
444
  # Make sure this process never finishes and leaves the simulator running
438
445
  kill_simulation(pid) if pid
439
446
  end
440
447
  )
441
448
 
449
+ Origen.log.debug 'Starting the simulation monitor...'
450
+
442
451
  simulator_parent_process = spawn("ruby -e \"#{launch_simulator}\"")
443
452
  Process.detach(simulator_parent_process)
444
453
 
445
- timeout_connection(config[:startup_timeout] || 60) do
446
- simulation.open # This will block until the simulation process responds
454
+ simulation.open(config[:startup_timeout] || 60) # This will block until the simulation process has started
447
455
 
448
- @connection_established = true # Cancels timeout_connection
449
- if @connection_timed_out
450
- simulation.failed_to_start = true
451
- exit # Assume it is not worth trying another pattern in this case, some kind of environment/config issue
452
- end
453
- end
456
+ # The VPI extension will send 'READY!' when it starts, make sure we get it before proceeding
454
457
  data = get
455
458
  unless data.strip == 'READY!'
456
459
  simulation.failed_to_start = true
460
+ simulation.log_results
457
461
  exit # Assume it is not worth trying another pattern in this case, some kind of environment/config issue
458
462
  end
459
463
  # Tick the simulation on, this seems to be required since any VPI puts operations before
@@ -479,6 +483,7 @@ module OrigenSim
479
483
  # At the start of a test program flow generation/simulation
480
484
  def on_flow_start(options)
481
485
  if simulation_tester? && options[:top_level]
486
+ @flow_running = true
482
487
  OrigenSim.flow = Origen.interface.flow.name
483
488
  start
484
489
  @pattern_count = 0
@@ -488,6 +493,8 @@ module OrigenSim
488
493
  # At the end of a test program flow generation/simulation
489
494
  def on_flow_end(options)
490
495
  if simulation_tester? && options[:top_level]
496
+ @flow_running = false
497
+ simulation.completed_cleanly = true
491
498
  stop
492
499
  end
493
500
  end
@@ -501,6 +508,7 @@ module OrigenSim
501
508
  # When running patterns back-to-back, only want to launch the simulator the first time
502
509
  start unless simulation
503
510
  else
511
+ simulation.completed_cleanly = true
504
512
  stop
505
513
  start
506
514
  end
@@ -511,6 +519,8 @@ module OrigenSim
511
519
  # each individual pattern has completed
512
520
  if @pattern_count > 0 && OrigenSim.flow
513
521
  simulation.log_results(true)
522
+ # Require each pattern to set this upon successful completion
523
+ simulation.completed_cleanly = false unless @flow_running
514
524
  end
515
525
  @pattern_count += 1
516
526
  end
@@ -520,7 +530,10 @@ module OrigenSim
520
530
  # sure the simulator is not running behind before potentially
521
531
  # moving onto another pattern
522
532
  def pattern_generated(path)
523
- sync_up if simulation_tester?
533
+ if simulation_tester?
534
+ sync_up
535
+ simulation.completed_cleanly = true unless @flow_running
536
+ end
524
537
  end
525
538
 
526
539
  def write_comment(comment)
@@ -717,26 +730,19 @@ module OrigenSim
717
730
  @simulation_open = false
718
731
  simulation.error_count = error_count
719
732
  Origen.listeners_for(:simulation_shutdown).each(&:simulation_shutdown)
720
- ended = Time.now
721
733
  end_simulation
722
734
  # Give the simulator time to shut down
723
735
  sleep 0.1 while simulation.running?
724
736
  simulation.close
725
- simulation.completed_cleanly = true
726
737
  simulation.log_results unless Origen.current_command == 'interactive'
738
+ rescue
739
+ simulation.completed_cleanly = false
727
740
  end
728
741
 
729
742
  def on_origen_shutdown
730
743
  unless simulations.empty?
731
744
  failed = false
732
- # Stop the current simulation, this is done with the rescue wrapper so that the rest
733
- # of the shutdown continues if we got in here via a CTRL-C, in which case the simulator
734
- # is probably already dead
735
- begin
736
- stop if simulation_open?
737
- rescue
738
- simulation.completed_cleanly = false
739
- end
745
+ stop if simulation_open?
740
746
  unless @interactive_mode
741
747
  if simulations.size == 1
742
748
  failed = simulation.failed?
@@ -784,21 +790,6 @@ module OrigenSim
784
790
  (tester && tester.is_a?(OrigenSim::Tester))
785
791
  end
786
792
 
787
- def timeout_connection(wait_in_s)
788
- @connection_timed_out = false
789
- @connection_established = false
790
- t = Thread.new do
791
- sleep wait_in_s
792
- # If the Verilog process has not established a connection yet, then make one to
793
- # release our process and then exit
794
- unless @connection_established
795
- @connection_timed_out = true
796
- UNIXSocket.new(socket_id).puts("Time out\n")
797
- end
798
- end
799
- yield
800
- end
801
-
802
793
  def sync
803
794
  put('f')
804
795
  @sync_active = true
@@ -16,6 +16,9 @@ module OrigenSim
16
16
  !OrigenSim.error_string_exceptions.any? { |s| line =~ /#{s}/ }
17
17
  @logged_errors = true
18
18
  Origen.log.error "(STDOUT): #{line}"
19
+ elsif OrigenSim.warning_strings.any? { |s| line =~ /#{s}/ } &&
20
+ !OrigenSim.warning_string_exceptions.any? { |s| line =~ /#{s}/ }
21
+ Origen.log.warn line
19
22
  else
20
23
  if OrigenSim.verbose? ||
21
24
  OrigenSim.log_strings.any? { |s| line =~ /#{s}/ }
@@ -24,6 +24,7 @@ module OrigenSimDev
24
24
  add_pin :p4, size: 4, force: 0xA
25
25
  add_pin :v1, rtl_name: 'nc'
26
26
  add_pin :v2, rtl_name: :nc
27
+ add_pin :not_present
27
28
 
28
29
  timeset :func do |t|
29
30
  # Generate a clock pulse on TCK
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: origen_sim
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.1
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen McGinty
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-21 00:00:00.000000000 Z
11
+ date: 2018-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: origen