origen_sim 0.8.0 → 0.9.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 +4 -4
- data/config/shared_commands.rb +18 -0
- data/config/version.rb +1 -1
- data/ext/bridge.c +6 -6
- data/ext/common.h +4 -0
- data/ext/defines.h.erb +1 -0
- data/ext/origen.c +8 -0
- data/lib/origen_sim/commands/build.rb +4 -2
- data/lib/origen_sim/commands/pack.rb +37 -0
- data/lib/origen_sim/simulator.rb +206 -58
- data/lib/origen_sim/tester.rb +9 -2
- data/lib/origen_sim.rb +77 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f670da6bba360fa76ac30b10cd097cde48d6353a
|
4
|
+
data.tar.gz: 07a1c407163212fd4fd04b45336ff399751155e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f0bcd9d653bf6ba02617116e3d843c9e1f39c20f023544b9cf5bbf152289fd9fa5654be8d72b2bcd77928f0a26041ed4da9370110b1281b98e1e7568df73aa5
|
7
|
+
data.tar.gz: 1bd7de244589567b366d0213279df4f295f0ed374311bfc1b22d0666eacfd6855c19ecaa7fe4f7c6214452d54fb0ab4076b69f3714fae397dc9d25142ebfa580
|
data/config/shared_commands.rb
CHANGED
@@ -16,10 +16,28 @@ when "sim:co", "origen_sim:co"
|
|
16
16
|
require "#{Origen.root!}/lib/origen_sim/commands/co"
|
17
17
|
exit 0
|
18
18
|
|
19
|
+
when "sim:pack"
|
20
|
+
require "#{Origen.root!}/lib/origen_sim/commands/pack"
|
21
|
+
OrigenSim::Commands::Pack.pack
|
22
|
+
exit 0
|
23
|
+
|
24
|
+
when "sim:unpack"
|
25
|
+
require "#{Origen.root!}/lib/origen_sim/commands/pack"
|
26
|
+
OrigenSim::Commands::Pack.unpack
|
27
|
+
exit 0
|
28
|
+
|
29
|
+
#when "sim:list"
|
30
|
+
# require "#{Origen.root!}/lib/origen_sim/commands/pack"
|
31
|
+
# OrigenSim::Commands::Pack.list
|
32
|
+
# exit 0
|
33
|
+
|
19
34
|
else
|
20
35
|
@plugin_commands << <<-EOT
|
21
36
|
sim:ci Checkin a simulation snapshot
|
22
37
|
sim:co Checkout a simulation snapshot
|
38
|
+
sim:pack Packs the snapshot into a compressed directory
|
39
|
+
sim:unpack Unpacks a snapshot
|
40
|
+
sim:list List the available snapshot packs
|
23
41
|
EOT
|
24
42
|
|
25
43
|
end
|
data/config/version.rb
CHANGED
data/ext/bridge.c
CHANGED
@@ -83,7 +83,7 @@ static void bridge_define_pin(char * name, char * pin_ix, char * drive_wave_ix,
|
|
83
83
|
(*pin).capture_en = false;
|
84
84
|
|
85
85
|
char * driver = (char *) malloc(strlen(name) + 16);
|
86
|
-
strcpy(driver, "
|
86
|
+
strcpy(driver, ORIGEN_SIM_TESTBENCH_CAT("pins."));
|
87
87
|
strcat(driver, name);
|
88
88
|
|
89
89
|
char * data = (char *) malloc(strlen(driver) + 16);
|
@@ -661,7 +661,7 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) {
|
|
661
661
|
// Set Pattern Name
|
662
662
|
// a^atd_ramp_25mhz
|
663
663
|
case 'a' :
|
664
|
-
handle = vpi_handle_by_name("
|
664
|
+
handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("debug.pattern"), NULL);
|
665
665
|
arg1 = strtok(NULL, "^");
|
666
666
|
|
667
667
|
v.format = vpiStringVal;
|
@@ -686,7 +686,7 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) {
|
|
686
686
|
// Set Comment
|
687
687
|
// c^Some comment about the pattern
|
688
688
|
case 'c' :
|
689
|
-
handle = vpi_handle_by_name("
|
689
|
+
handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("debug.comments"), NULL);
|
690
690
|
arg1 = strtok(NULL, "^");
|
691
691
|
|
692
692
|
v.format = vpiStringVal;
|
@@ -710,14 +710,14 @@ PLI_INT32 bridge_wait_for_msg(p_cb_data data) {
|
|
710
710
|
break;
|
711
711
|
// Sync enable
|
712
712
|
case 'f' :
|
713
|
-
handle = vpi_handle_by_name("
|
713
|
+
handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("pins.sync"), NULL);
|
714
714
|
v.format = vpiDecStrVal;
|
715
715
|
v.value.str = "1";
|
716
716
|
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
717
717
|
break;
|
718
718
|
// Sync disable
|
719
719
|
case 'g' :
|
720
|
-
handle = vpi_handle_by_name("
|
720
|
+
handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("pins.sync"), NULL);
|
721
721
|
v.format = vpiDecStrVal;
|
722
722
|
v.value.str = "0";
|
723
723
|
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
@@ -751,7 +751,7 @@ static void end_simulation() {
|
|
751
751
|
s_vpi_value v;
|
752
752
|
|
753
753
|
// Setting this node will cause the testbench to call $finish
|
754
|
-
handle = vpi_handle_by_name("
|
754
|
+
handle = vpi_handle_by_name(ORIGEN_SIM_TESTBENCH_CAT("finish"), NULL);
|
755
755
|
v.format = vpiDecStrVal;
|
756
756
|
v.value.str = "1";
|
757
757
|
vpi_put_value(handle, &v, NULL, vpiNoDelay);
|
data/ext/common.h
CHANGED
@@ -11,6 +11,10 @@
|
|
11
11
|
|
12
12
|
#define ENABLE_DEBUG
|
13
13
|
|
14
|
+
/// Prepends the testbench name to the signal.
|
15
|
+
/// e.g.: TESTBENCH_CAT(pins) => TESTBENCH_NAME.pins => origen.pins
|
16
|
+
#define ORIGEN_SIM_TESTBENCH_CAT(signal) ORIGEN_SIM_TESTBENCH_NAME "." signal
|
17
|
+
|
14
18
|
#ifdef ENABLE_DEBUG
|
15
19
|
/* #define DEBUG(fmt, args...) fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt, \
|
16
20
|
__FILE__, __LINE__, __func__, ##args) */
|
data/ext/defines.h.erb
CHANGED
data/ext/origen.c
CHANGED
@@ -85,6 +85,14 @@ PLI_INT32 origen_shutdown(p_cb_data data) {
|
|
85
85
|
return 0;
|
86
86
|
}
|
87
87
|
|
88
|
+
/// Function to call the init PLI's init function
|
89
|
+
/// Some toolchains will call this automatically, some will not
|
90
|
+
/// Available here for those which do not automatically call init() for each PLI
|
91
|
+
PLI_INT32 bootstrap(p_cb_data data) {
|
92
|
+
vpi_printf("Origen Bootstrap Called!\n");
|
93
|
+
init();
|
94
|
+
return 0;
|
95
|
+
}
|
88
96
|
|
89
97
|
///
|
90
98
|
/// Registers a very basic VPI callback with reason and handler.
|
@@ -3,7 +3,7 @@ require 'origen_sim'
|
|
3
3
|
require_relative '../../../config/version'
|
4
4
|
require 'origen_verilog'
|
5
5
|
|
6
|
-
options = { source_dirs: [] }
|
6
|
+
options = { source_dirs: [], testbench_name: 'origen' }
|
7
7
|
|
8
8
|
# App options are options that the application can supply to extend this command
|
9
9
|
app_options = @application_options || []
|
@@ -18,6 +18,7 @@ Usage: origen sim:build TOP_LEVEL_VERILOG_FILE [options]
|
|
18
18
|
EOT
|
19
19
|
opts.on('-o', '--output DIR', String, 'Override the default output directory') { |t| options[:output] = t }
|
20
20
|
opts.on('-t', '--top NAME', String, 'Specify the top-level Verilog module name if OrigenSim can\'t work it out') { |t| options[:top_level_name] = t }
|
21
|
+
opts.on('--testbench NAME', String, 'Specify the testbench name if different from \'origen\'') { |t| options[:testbench_name] = t }
|
21
22
|
opts.on('-s', '--source_dir PATH', 'Directories to look for include files in (the directory containing the top-level is already considered)') do |path|
|
22
23
|
options[:source_dirs] << path
|
23
24
|
end
|
@@ -86,7 +87,8 @@ Origen.app.runner.launch action: :compile,
|
|
86
87
|
files: "#{Origen.root!}/ext",
|
87
88
|
output: output_directory,
|
88
89
|
check_for_changes: false,
|
89
|
-
quiet: true
|
90
|
+
quiet: true,
|
91
|
+
options: options
|
90
92
|
|
91
93
|
dut.export(rtl_top_module, dir: "#{output_directory}", namespace: nil)
|
92
94
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module OrigenSim
|
2
|
+
module Commands
|
3
|
+
module Pack
|
4
|
+
# Note, making this a module instead of straight code so it can be called
|
5
|
+
# programatically to auto-unpack a snapshot.
|
6
|
+
|
7
|
+
def self.pack(options = {})
|
8
|
+
testbench = "#{Origen.app.root}/simulation"
|
9
|
+
unless Dir.exist?(testbench)
|
10
|
+
fail "Could not find path #{testbench}/#{ARGV[0]}"
|
11
|
+
end
|
12
|
+
|
13
|
+
FileUtils.mkdir("#{Origen.app.root}/simulation/static") unless Dir.exist?("#{Origen.app.root}/simulation/static")
|
14
|
+
|
15
|
+
output = "#{Origen.app.root}/simulation/static/#{ARGV[0]}.tar.gz"
|
16
|
+
puts "Packing #{testbench} into #{output}..."
|
17
|
+
system "tar vczf #{output} -C #{testbench} #{Origen.target.name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.unpack(options = {})
|
21
|
+
testbench = "#{Origen.app.root}/simulation/static/#{ARGV[0]}.tar.gz"
|
22
|
+
unless File.exist?(testbench)
|
23
|
+
fail "Could not find #{testbench}"
|
24
|
+
end
|
25
|
+
|
26
|
+
output = "#{Origen.app.root}/simulation"
|
27
|
+
FileUtils.mkdir(output) unless Dir.exist?(output)
|
28
|
+
|
29
|
+
puts "Unpakcing Testbench into #{output}"
|
30
|
+
system "tar vxzf #{testbench} -C #{output} #{ARGV[0]}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.list(options = {})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/origen_sim/simulator.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'socket'
|
2
|
+
require 'io/wait'
|
2
3
|
module OrigenSim
|
3
4
|
# Responsible for managing and communicating with the simulator
|
4
5
|
# process, a single instance of this class is instantiated as
|
@@ -6,10 +7,16 @@ module OrigenSim
|
|
6
7
|
class Simulator
|
7
8
|
include Origen::PersistentCallbacks
|
8
9
|
|
9
|
-
VENDORS = [:icarus, :cadence, :synopsys]
|
10
|
+
VENDORS = [:icarus, :cadence, :synopsys, :generic]
|
10
11
|
|
11
|
-
attr_reader :socket, :failed, :configuration
|
12
|
+
attr_reader :socket, :failed, :configuration, :stderr, :stdout, :heartbeat
|
12
13
|
alias_method :config, :configuration
|
14
|
+
# Returns the PID of the simulator process
|
15
|
+
attr_reader :pid
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@socket_ids = {}
|
19
|
+
end
|
13
20
|
|
14
21
|
# When set to true the simulator will log all messages it receives, note that
|
15
22
|
# this must be run in conjunction with -d supplied to the Origen command to actually
|
@@ -22,6 +29,22 @@ module OrigenSim
|
|
22
29
|
end
|
23
30
|
end
|
24
31
|
|
32
|
+
def testbench_top
|
33
|
+
config[:testbench_top] || 'origen'
|
34
|
+
end
|
35
|
+
|
36
|
+
def rtl_top
|
37
|
+
config[:rtl_top] || 'dut'
|
38
|
+
end
|
39
|
+
|
40
|
+
def generic_run_cmd
|
41
|
+
config[:generic_run_cmd]
|
42
|
+
end
|
43
|
+
|
44
|
+
def post_process_run_cmd
|
45
|
+
config[:post_process_run_cmd]
|
46
|
+
end
|
47
|
+
|
25
48
|
def fetch_simulation_objects(options = {})
|
26
49
|
sid = options[:id] || id
|
27
50
|
ldir = "#{Origen.root}/simulation/#{sid}"
|
@@ -83,7 +106,7 @@ module OrigenSim
|
|
83
106
|
FileUtils.rm_rf tmp_dir if File.exist?(tmp_dir)
|
84
107
|
end
|
85
108
|
|
86
|
-
def configure(options)
|
109
|
+
def configure(options, &block)
|
87
110
|
fail 'A vendor must be supplied, e.g. OrigenSim::Tester.new(vendor: :icarus)' unless options[:vendor]
|
88
111
|
unless VENDORS.include?(options[:vendor])
|
89
112
|
fail "Unknown vendor #{options[:vendor]}, valid values are: #{VENDORS.map { |v| ':' + v.to_s }.join(', ')}"
|
@@ -125,14 +148,6 @@ module OrigenSim
|
|
125
148
|
end
|
126
149
|
end
|
127
150
|
|
128
|
-
def pid_dir
|
129
|
-
@pid_dir ||= begin
|
130
|
-
d = "#{Origen.root}/tmp/origen_sim/pids"
|
131
|
-
FileUtils.mkdir_p(d)
|
132
|
-
d
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
151
|
def wave_config_dir
|
137
152
|
@wave_config_dir ||= begin
|
138
153
|
d = "#{Origen.root}/config/waves/#{id}"
|
@@ -215,10 +230,42 @@ module OrigenSim
|
|
215
230
|
when :synopsys
|
216
231
|
cmd = "#{compiled_dir}/simv +socket+#{socket_id} -vpd_file origen.vpd"
|
217
232
|
|
233
|
+
when :generic
|
234
|
+
# Generic tester requires that a generic_run_command option/block be provided.
|
235
|
+
# This should either be a string, an array (which will be joined here), or a block that needs to return either
|
236
|
+
# a string or array. In the event of a block, the block will be given the simulator.
|
237
|
+
if generic_run_cmd
|
238
|
+
cmd = generic_run_cmd
|
239
|
+
if cmd.is_a?(Proc)
|
240
|
+
cmd = cmd.call(self)
|
241
|
+
end
|
242
|
+
|
243
|
+
if cmd.is_a?(Array)
|
244
|
+
# We'll join this together with the '; ' string. This means that each array element will be run
|
245
|
+
# sequentially.
|
246
|
+
cmd = cmd.join(' && ')
|
247
|
+
elsif !cmd.is_a?(String)
|
248
|
+
# If its Proc, it was already run, and if its a Array if would have gone into the other case.
|
249
|
+
# So, this is either another proc, not an array and not a string, so not sure what to do with this.
|
250
|
+
# Complain about the cmd.
|
251
|
+
fail "OrigenSim :generic_run_cmd is of class #{generic_run_cmd.class}. It must be either an Array, String, or a Proc that returns an Array or String."
|
252
|
+
end
|
253
|
+
else
|
254
|
+
fail 'OrigenSim Generic Toolchain/Vendor requires a :generic_run_cmd option/block to be provided. No options/block provided!'
|
255
|
+
end
|
256
|
+
|
218
257
|
else
|
219
258
|
fail "Run cmd not defined yet for simulator #{config[:vendor]}"
|
220
259
|
|
221
260
|
end
|
261
|
+
|
262
|
+
# Allow the user to post-process the command. This should be a block which will be given two parameters:
|
263
|
+
# 1. the command, and 2. the simulation object (self).
|
264
|
+
# In the event of a generic tester, this *could* replace the launch command, but that's not the real intention,
|
265
|
+
# since a simulator could be made that inherits from a generic simulator setup and still post process the command.
|
266
|
+
cmd = post_process_run_cmd.call(cmd, self) if post_process_run_cmd
|
267
|
+
fail "OrigenSim: :post_process_run_cmd returned object of class #{cmd.class}. Must return a String." unless cmd.is_a?(String)
|
268
|
+
|
222
269
|
cmd
|
223
270
|
end
|
224
271
|
|
@@ -253,6 +300,20 @@ module OrigenSim
|
|
253
300
|
cmd += " -session #{f}"
|
254
301
|
cmd += ' &'
|
255
302
|
|
303
|
+
when :generic
|
304
|
+
# Since this could be anything, the simulator will need to set this up. But, once it is, we can print it here.
|
305
|
+
if config[:view_waveform_cmd]
|
306
|
+
cmd = config[:view_waveform_cmd]
|
307
|
+
else
|
308
|
+
Origen.log.warn 'OrigenSim cannot provide a view-waveform command for a :generic vendor.'
|
309
|
+
Origen.log.warn 'Please supply a view-waveform command though the :view_waveform_cmd option during the OrigenSim::Generic instantiation.'
|
310
|
+
end
|
311
|
+
|
312
|
+
else
|
313
|
+
# Print a warning stating an unknown vendor was reached here.
|
314
|
+
# This shouldn't happen, but just in case.
|
315
|
+
Origen.log.warn "OrigenSim does not know the command to view waveforms for vendor :#{config[:vendor]}!"
|
316
|
+
|
256
317
|
end
|
257
318
|
cmd
|
258
319
|
end
|
@@ -270,31 +331,86 @@ module OrigenSim
|
|
270
331
|
def start
|
271
332
|
fetch_simulation_objects
|
272
333
|
|
334
|
+
# Socket used for Origen -> Verilog commands
|
273
335
|
server = UNIXServer.new(socket_id)
|
274
|
-
|
336
|
+
# Socket used to capture stdout from the simulator
|
337
|
+
stdout_socket_id = socket_id(:stdout)
|
338
|
+
# Socket used to capture stderr from the simulator
|
339
|
+
stderr_socket_id = socket_id(:stderr)
|
340
|
+
# Socket used to provide a heartbeat to let the Ruby process in charge of the simulator
|
341
|
+
# know that the mast Origen process is still alive. If the Origen process crashes and leaves
|
342
|
+
# the simulator running, the child process will automatically reap it after a couple of missed
|
343
|
+
# heartbeats
|
344
|
+
heartbeat_socket_id = socket_id(:heartbeat)
|
345
|
+
server_stdout = UNIXServer.new(stdout_socket_id)
|
346
|
+
server_stderr = UNIXServer.new(stderr_socket_id)
|
347
|
+
server_heartbeat = UNIXServer.new(heartbeat_socket_id)
|
275
348
|
cmd = run_cmd + ' & echo \$!'
|
276
349
|
|
277
350
|
launch_simulator = %(
|
278
351
|
require 'open3'
|
352
|
+
require 'socket'
|
353
|
+
require 'io/wait'
|
354
|
+
require 'origen'
|
355
|
+
|
356
|
+
pid = nil
|
357
|
+
|
358
|
+
stdout_socket = UNIXSocket.new('#{stdout_socket_id}')
|
359
|
+
stderr_socket = UNIXSocket.new('#{stderr_socket_id}')
|
360
|
+
heartbeat = UNIXSocket.new('#{heartbeat_socket_id}')
|
361
|
+
|
362
|
+
begin
|
363
|
+
|
364
|
+
Dir.chdir '#{run_dir}' do
|
365
|
+
Open3.popen3('#{cmd}') do |stdin, stdout, stderr, thread|
|
366
|
+
pid = stdout.gets.strip.to_i
|
367
|
+
heartbeat.puts(pid.to_s)
|
368
|
+
|
369
|
+
# Listen for a heartbeat from the main Origen process every 5 seconds, kill the
|
370
|
+
# simulator after two missed heartbeats
|
371
|
+
Thread.new do
|
372
|
+
missed_heartbeats = 0
|
373
|
+
loop do
|
374
|
+
sleep 5
|
375
|
+
if heartbeat.ready?
|
376
|
+
while heartbeat.ready? do
|
377
|
+
heartbeat.gets
|
378
|
+
end
|
379
|
+
missed_heartbeats = 0
|
380
|
+
else
|
381
|
+
missed_heartbeats += 1
|
382
|
+
end
|
383
|
+
if missed_heartbeats > 1
|
384
|
+
Process.kill('KILL', pid)
|
385
|
+
exit!(1)
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
279
389
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
end
|
286
|
-
threads = []
|
287
|
-
threads << Thread.new do
|
288
|
-
until (line = stdout.gets).nil?
|
289
|
-
puts line if #{verbose ? 'true' : 'false'}
|
390
|
+
threads = []
|
391
|
+
threads << Thread.new do
|
392
|
+
until (line = stdout.gets).nil?
|
393
|
+
stdout_socket.puts line
|
394
|
+
end
|
290
395
|
end
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
396
|
+
threads << Thread.new do
|
397
|
+
until (line = stderr.gets).nil?
|
398
|
+
stderr_socket.puts line
|
399
|
+
end
|
295
400
|
end
|
401
|
+
threads.each(&:join)
|
296
402
|
end
|
297
|
-
|
403
|
+
end
|
404
|
+
|
405
|
+
ensure
|
406
|
+
# Make sure this process never finishes and leaves the simulator running
|
407
|
+
begin
|
408
|
+
# If the process already finished, then we will see an Errno exception.
|
409
|
+
# It does not harm anything, but looks ugly, so catch it here and ignore.
|
410
|
+
Process.kill('KILL', pid) if pid
|
411
|
+
0
|
412
|
+
rescue Errno::ESRCH => e
|
413
|
+
0
|
298
414
|
end
|
299
415
|
end
|
300
416
|
)
|
@@ -303,6 +419,19 @@ module OrigenSim
|
|
303
419
|
Process.detach(simulator_parent_process)
|
304
420
|
|
305
421
|
timeout_connection(config[:startup_timeout] || 60) do
|
422
|
+
@heartbeat = server_heartbeat.accept
|
423
|
+
@pid = heartbeat.gets.chomp.to_i
|
424
|
+
|
425
|
+
# Send a heartbeat to the child process running the simulator every 5 seconds
|
426
|
+
Thread.new do
|
427
|
+
loop do
|
428
|
+
heartbeat.write("OK\n")
|
429
|
+
sleep 5
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
@stdout = server_stdout.accept
|
434
|
+
@stderr = server_stderr.accept
|
306
435
|
@socket = server.accept
|
307
436
|
@connection_established = true
|
308
437
|
if @connection_timed_out
|
@@ -327,22 +456,9 @@ module OrigenSim
|
|
327
456
|
Origen.listeners_for(:simulation_startup).each(&:simulation_startup)
|
328
457
|
end
|
329
458
|
|
330
|
-
# Returns the pid of the simulator process
|
331
|
-
def pid
|
332
|
-
return @pid if @pid_set
|
333
|
-
@pid = File.readlines(pid_file).first.strip.to_i if File.exist?(pid_file)
|
334
|
-
@pid ||= 0
|
335
|
-
@pid_set = true
|
336
|
-
@pid
|
337
|
-
end
|
338
|
-
|
339
|
-
def pid_file
|
340
|
-
"#{Origen.root}/tmp/origen_sim/pids/#{socket_number}"
|
341
|
-
end
|
342
|
-
|
343
459
|
# Returns true if the simulator process is running
|
344
460
|
def running?
|
345
|
-
return false
|
461
|
+
return false unless pid
|
346
462
|
begin
|
347
463
|
Process.getpgid(pid)
|
348
464
|
true
|
@@ -474,6 +590,7 @@ module OrigenSim
|
|
474
590
|
|
475
591
|
def cycle(number_of_cycles)
|
476
592
|
put("3^#{number_of_cycles}")
|
593
|
+
read_sim_output
|
477
594
|
end
|
478
595
|
|
479
596
|
# Blocks the Origen process until the simulator indicates that it has
|
@@ -484,11 +601,42 @@ module OrigenSim
|
|
484
601
|
unless data.strip == 'OK!'
|
485
602
|
fail 'Origen and the simulator are out of sync!'
|
486
603
|
end
|
604
|
+
read_sim_output
|
605
|
+
end
|
606
|
+
|
607
|
+
def read_sim_output
|
608
|
+
while stdout.ready?
|
609
|
+
line = stdout.gets.chomp
|
610
|
+
if OrigenSim.error_strings.any? { |s| line =~ /#{s}/ } &&
|
611
|
+
!OrigenSim.error_string_exceptions.any? { |s| line =~ /#{s}/ }
|
612
|
+
@simulator_logged_errors = true
|
613
|
+
Origen.log.error "(STDOUT): #{line}"
|
614
|
+
else
|
615
|
+
if OrigenSim.verbose? ||
|
616
|
+
OrigenSim.log_strings.any? { |s| line =~ /#{s}/ }
|
617
|
+
Origen.log.info line
|
618
|
+
else
|
619
|
+
Origen.log.debug line
|
620
|
+
end
|
621
|
+
end
|
622
|
+
end
|
623
|
+
while stderr.ready?
|
624
|
+
line = stderr.gets.chomp
|
625
|
+
if OrigenSim.fail_on_stderr && !OrigenSim.stderr_string_exceptions.any? { |s| line =~ /#{s}/ }
|
626
|
+
# We're failing on stderr, so print its results and log as errors if its not an exception.
|
627
|
+
@stderr_logged_errors = true
|
628
|
+
Origen.log.error "(STDERR): #{line}"
|
629
|
+
elsif OrigenSim.verbose?
|
630
|
+
# We're not failing on stderr, or the string in stderr is an exception.
|
631
|
+
# Print the string as regular output if verbose is set, otherwise just ignore.
|
632
|
+
Origen.log.info line
|
633
|
+
end
|
634
|
+
end
|
487
635
|
end
|
488
636
|
|
489
637
|
# Returns the current simulation error count
|
490
638
|
def error_count
|
491
|
-
peek(
|
639
|
+
peek("#{testbench_top}.debug.errors").to_i
|
492
640
|
end
|
493
641
|
|
494
642
|
# Returns the current value of the given net, or nil if the given path does not
|
@@ -546,7 +694,6 @@ module OrigenSim
|
|
546
694
|
|
547
695
|
v = peek(path)
|
548
696
|
return nil unless v
|
549
|
-
|
550
697
|
# Setting a range of bits
|
551
698
|
if lsb
|
552
699
|
upper = v >> (msb + 1)
|
@@ -588,15 +735,16 @@ module OrigenSim
|
|
588
735
|
Origen.listeners_for(:simulation_shutdown).each(&:simulation_shutdown)
|
589
736
|
ended = Time.now
|
590
737
|
end_simulation
|
591
|
-
# Give the simulator
|
592
|
-
sleep 1 while running?
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
FileUtils.rm_f(pid_file) if File.exist?(pid_file) && !running?
|
598
|
-
@socket.close if @socket
|
738
|
+
# Give the simulator time to shut down
|
739
|
+
sleep 0.1 while running?
|
740
|
+
socket.close if socket
|
741
|
+
stderr.close if stderr
|
742
|
+
stdout.close if stdout
|
743
|
+
heartbeat.close if heartbeat
|
599
744
|
File.unlink(socket_id) if File.exist?(socket_id)
|
745
|
+
File.unlink(socket_id(:stderr)) if File.exist?(socket_id(:stderr))
|
746
|
+
File.unlink(socket_id(:stdout)) if File.exist?(socket_id(:stdout))
|
747
|
+
File.unlink(socket_id(:heartbeat)) if File.exist?(socket_id(:heartbeat))
|
600
748
|
end
|
601
749
|
|
602
750
|
def on_origen_shutdown
|
@@ -605,9 +753,11 @@ module OrigenSim
|
|
605
753
|
Origen.log.debug 'Shutting down simulator...'
|
606
754
|
unless @failed_to_start
|
607
755
|
c = error_count
|
608
|
-
if c > 0
|
756
|
+
if c > 0 || @simulator_logged_errors || @stderr_logged_errors
|
609
757
|
@failed = true
|
610
|
-
Origen.log.error "The simulation failed with #{c} errors!"
|
758
|
+
Origen.log.error "The simulation failed with #{c} errors!" if c > 0
|
759
|
+
Origen.log.error 'The simulation log reported errors!' if @simulator_logged_errors
|
760
|
+
Origen.log.error 'The simulation stderr reported errors!' if @stderr_logged_errors
|
611
761
|
elsif !@simulation_completed_cleanly
|
612
762
|
@failed = true
|
613
763
|
Origen.log.error 'The simulation exited early!'
|
@@ -630,12 +780,10 @@ module OrigenSim
|
|
630
780
|
puts
|
631
781
|
end
|
632
782
|
end
|
633
|
-
ensure
|
634
|
-
Process.kill(15, pid) if @enabled && running?
|
635
783
|
end
|
636
784
|
|
637
|
-
def socket_id
|
638
|
-
@
|
785
|
+
def socket_id(type = nil)
|
786
|
+
@socket_ids[type] ||= "/tmp/#{socket_number}#{type}.sock"
|
639
787
|
end
|
640
788
|
|
641
789
|
def socket_number
|
@@ -654,7 +802,7 @@ module OrigenSim
|
|
654
802
|
# release our process and then exit
|
655
803
|
unless @connection_established
|
656
804
|
@connection_timed_out = true
|
657
|
-
UNIXSocket.new(socket_id).puts(
|
805
|
+
UNIXSocket.new(socket_id).puts("Time out\n")
|
658
806
|
end
|
659
807
|
end
|
660
808
|
yield
|
data/lib/origen_sim/tester.rb
CHANGED
@@ -5,8 +5,15 @@ module OrigenSim
|
|
5
5
|
|
6
6
|
TEST_PROGRAM_GENERATOR = OrigenSim::Generator
|
7
7
|
|
8
|
-
def initialize(options = {})
|
9
|
-
|
8
|
+
def initialize(options = {}, &block)
|
9
|
+
# Use Origen's collector to allow options to be set either from the options hash, or from the block
|
10
|
+
if block_given?
|
11
|
+
opts = Origen::Utility.collector(hash: options, merge_method: :keep_hash, &block).to_hash
|
12
|
+
else
|
13
|
+
opts = options
|
14
|
+
end
|
15
|
+
|
16
|
+
simulator.configure(opts, &block)
|
10
17
|
super()
|
11
18
|
end
|
12
19
|
|
data/lib/origen_sim.rb
CHANGED
@@ -23,5 +23,82 @@ module OrigenSim
|
|
23
23
|
def self.simulator
|
24
24
|
@simulator
|
25
25
|
end
|
26
|
+
|
27
|
+
# Provide some shortcut methods to set the vendor
|
28
|
+
def self.generic(options = {}, &block)
|
29
|
+
Tester.new(options.merge(vendor: :generic), &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.cadence(options = {}, &block)
|
33
|
+
Tester.new(options.merge(vendor: :cadence), &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.synopsys(optoins = {}, &block)
|
37
|
+
Tester.new(options.merge(vendor: :synopsys), &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.icarus(options = {}, &block)
|
41
|
+
Tester.new(options.merge(vendor: :icarus), &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.verbose=(val)
|
45
|
+
@verbose = val
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.verbose?
|
49
|
+
!!(@verbose || Origen.debugger_enabled?)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.error_strings
|
53
|
+
@error_strings ||= ['ERROR']
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.error_strings=(val)
|
57
|
+
unless val.is_a?(Array)
|
58
|
+
fail 'OrigenSim.error_strings can only be set to an array of string values!'
|
59
|
+
end
|
60
|
+
@error_strings = val
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.error_string_exceptions
|
64
|
+
@error_string_exceptions ||= []
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.error_string_exceptions=(val)
|
68
|
+
unless val.is_a?(Array)
|
69
|
+
fail 'OrigenSim.error_string_exceptions can only be set to an array of string values!'
|
70
|
+
end
|
71
|
+
@error_string_exceptions = val
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.stderr_string_exceptions
|
75
|
+
@stderr_string_exceptions ||= []
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.stderr_string_exceptions=(val)
|
79
|
+
unless val.is_a?(Array)
|
80
|
+
fail 'OrigenSim.error_string_exceptions can only be set to an array of string values!'
|
81
|
+
end
|
82
|
+
@stderr_string_exceptions = val
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.log_strings
|
86
|
+
@log_strings ||= []
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.log_strings=(val)
|
90
|
+
unless val.is_a?(Array)
|
91
|
+
fail 'OrigenSim.log_strings can only be set to an array of string values!'
|
92
|
+
end
|
93
|
+
@log_strings = val
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.fail_on_stderr=(val)
|
97
|
+
@fail_on_stderr = val
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.fail_on_stderr
|
101
|
+
defined?(@fail_on_stderr) ? @fail_on_stderr : true
|
102
|
+
end
|
26
103
|
end
|
27
104
|
OrigenSim.__instantiate_simulator__
|
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.
|
4
|
+
version: 0.9.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-
|
11
|
+
date: 2018-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: origen
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.33.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.33.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: origen_testers
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,6 +78,7 @@ files:
|
|
78
78
|
- lib/origen_sim/commands/build.rb
|
79
79
|
- lib/origen_sim/commands/ci.rb
|
80
80
|
- lib/origen_sim/commands/co.rb
|
81
|
+
- lib/origen_sim/commands/pack.rb
|
81
82
|
- lib/origen_sim/flow.rb
|
82
83
|
- lib/origen_sim/generator.rb
|
83
84
|
- lib/origen_sim/origen/pins/pin.rb
|