origen_sim 0.11.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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