origen_sim 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config/application.rb +3 -1
- data/config/shared_commands.rb +3 -0
- data/config/version.rb +1 -1
- data/lib/origen_sim/commands/build.rb +127 -109
- data/lib/origen_sim/heartbeat.rb +21 -0
- data/lib/origen_sim/origen/application/runner.rb +19 -0
- data/lib/origen_sim/simulation.rb +157 -0
- data/lib/origen_sim/simulator.rb +156 -162
- data/lib/origen_sim.rb +14 -1
- data/pattern/test.rb +5 -5
- data/pattern/test2.rb +1 -0
- data/program/p1.rb +2 -2
- data/program/p2.rb +1 -0
- data/templates/probe.tcl.erb +1 -1
- data/templates/rtl_v/origen.v.erb +1 -1
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b31bfc2f252031780f05373507dbbb75db36300
|
4
|
+
data.tar.gz: fb37cfeb67cde82e1f829630b36ea6752e581189
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f86cbee77db2cd17707e7c68aa96a70a18922772207e302b7abf6c416d9e28a2a0c2035339d28f3fde56214a6331a6e657a0be3b1b3945dfc5b1566d673d1e91
|
7
|
+
data.tar.gz: 865533e70e134f220837accecdbefa616f1df14f8cf185bc3584a923e3c5af4afe2d5a3b7662221de125b0b45c5eb975569bfe51da679dc442d10e4c5f38e0df
|
data/config/application.rb
CHANGED
@@ -57,7 +57,9 @@ class OrigenSimApplication < Origen::Application
|
|
57
57
|
|
58
58
|
# An example of how to set application specific LSF parameters
|
59
59
|
#config.lsf.project = "msg.te"
|
60
|
-
|
60
|
+
config.lsf.queue = ENV["ORIGEN_LSF_QUEUE"] if ENV["ORIGEN_LSF_QUEUE"]
|
61
|
+
config.lsf.resource = ENV["ORIGEN_LSF_RESOURCE"] if ENV["ORIGEN_LSF_RESOURCE"]
|
62
|
+
|
61
63
|
# An example of how to specify a prefix to add to all generated patterns
|
62
64
|
#config.pattern_prefix = "nvm"
|
63
65
|
|
data/config/shared_commands.rb
CHANGED
@@ -5,9 +5,12 @@ when 'generate'
|
|
5
5
|
$use_fast_probe_depth = false
|
6
6
|
@application_options << ["--fast", "Fast simulation, minimum probe depth"]
|
7
7
|
$use_fast_probe_depth = ARGV.include?('--fast')
|
8
|
+
|
8
9
|
@application_options << ["--sim_capture", "Update sim captures (ignored when not running a simulation)"]
|
9
10
|
Origen.app!.update_sim_captures = ARGV.include?('--sim_capture')
|
10
11
|
|
12
|
+
@application_options << ["--flow NAME", "Simulate multiple patterns back-back within a single simulation with the given name", ->(options, name) { OrigenSim.flow = name }]
|
13
|
+
|
11
14
|
when "sim:ci", "origen_sim:ci"
|
12
15
|
require "#{Origen.root!}/lib/origen_sim/commands/ci"
|
13
16
|
exit 0
|
data/config/version.rb
CHANGED
@@ -3,7 +3,7 @@ require 'origen_sim'
|
|
3
3
|
require_relative '../../../config/version'
|
4
4
|
require 'origen_verilog'
|
5
5
|
|
6
|
-
options = { source_dirs: [], testbench_name: 'origen' }
|
6
|
+
options = { source_dirs: [], testbench_name: 'origen', defines: [] }
|
7
7
|
|
8
8
|
# App options are options that the application can supply to extend this command
|
9
9
|
app_options = @application_options || []
|
@@ -22,6 +22,9 @@ Usage: origen sim:build TOP_LEVEL_VERILOG_FILE [options]
|
|
22
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|
|
23
23
|
options[:source_dirs] << path
|
24
24
|
end
|
25
|
+
opts.on('--define MACRO', 'Specify a compiler define') do |macro|
|
26
|
+
options[:defines] << macro
|
27
|
+
end
|
25
28
|
opts.on('-d', '--debugger', 'Enable the debugger') { options[:debugger] = true }
|
26
29
|
app_options.each do |app_option|
|
27
30
|
opts.on(*app_option) {}
|
@@ -32,21 +35,30 @@ end
|
|
32
35
|
|
33
36
|
opt_parser.parse! ARGV
|
34
37
|
|
38
|
+
def _exit_fail_
|
39
|
+
if $_testing_build_return_dut_
|
40
|
+
return nil
|
41
|
+
else
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
35
46
|
unless ARGV.size > 0
|
36
47
|
puts 'You must supply a path to the top-level RTL file'
|
37
|
-
|
48
|
+
_exit_fail_
|
38
49
|
end
|
39
|
-
|
50
|
+
files = ARGV.first
|
51
|
+
rtl_top = files.split(/\s+/).last
|
40
52
|
unless File.exist?(rtl_top)
|
41
53
|
puts "File does not exist: #{rtl_top}"
|
42
|
-
|
54
|
+
_exit_fail_
|
43
55
|
end
|
44
56
|
|
45
|
-
ast = OrigenVerilog.parse_file(
|
57
|
+
ast = OrigenVerilog.parse_file(files, options)
|
46
58
|
|
47
59
|
unless ast
|
48
60
|
puts 'Sorry, but the given top-level RTL file failed to parse'
|
49
|
-
|
61
|
+
_exit_fail_
|
50
62
|
end
|
51
63
|
|
52
64
|
candidates = ast.top_level_modules
|
@@ -54,7 +66,7 @@ candidates = ast.modules if candidates.empty?
|
|
54
66
|
|
55
67
|
if candidates.size == 0
|
56
68
|
puts "Sorry, couldn't find any Verilog module declarations in that file"
|
57
|
-
|
69
|
+
_exit_fail_
|
58
70
|
elsif candidates.size > 1
|
59
71
|
if options[:top_level_name]
|
60
72
|
mod = candidates.find { |c| c.name == options[:top_level_name] }
|
@@ -64,7 +76,7 @@ elsif candidates.size > 1
|
|
64
76
|
candidates.each do |c|
|
65
77
|
puts " #{c.name}"
|
66
78
|
end
|
67
|
-
|
79
|
+
_exit_fail_
|
68
80
|
end
|
69
81
|
else
|
70
82
|
mod = candidates.first
|
@@ -74,104 +86,110 @@ rtl_top_module = mod.name
|
|
74
86
|
|
75
87
|
mod.to_top_level # Creates dut
|
76
88
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
puts
|
101
|
-
puts
|
102
|
-
puts
|
103
|
-
puts
|
104
|
-
puts
|
105
|
-
puts
|
106
|
-
puts
|
107
|
-
puts
|
108
|
-
puts
|
109
|
-
puts
|
110
|
-
puts
|
111
|
-
puts
|
112
|
-
puts
|
113
|
-
puts
|
114
|
-
puts '
|
115
|
-
puts
|
116
|
-
puts
|
117
|
-
puts
|
118
|
-
puts ' -
|
119
|
-
puts
|
120
|
-
puts '
|
121
|
-
puts
|
122
|
-
puts
|
123
|
-
puts
|
124
|
-
puts
|
125
|
-
puts
|
126
|
-
puts
|
127
|
-
puts
|
128
|
-
puts
|
129
|
-
puts '
|
130
|
-
puts
|
131
|
-
puts
|
132
|
-
puts
|
133
|
-
puts
|
134
|
-
puts
|
135
|
-
puts
|
136
|
-
puts
|
137
|
-
puts '
|
138
|
-
puts
|
139
|
-
puts "
|
140
|
-
puts
|
141
|
-
puts
|
142
|
-
puts ' -
|
143
|
-
puts '
|
144
|
-
puts
|
145
|
-
puts '
|
146
|
-
puts
|
147
|
-
puts
|
148
|
-
puts
|
149
|
-
puts
|
150
|
-
puts
|
151
|
-
puts
|
152
|
-
puts '
|
153
|
-
puts
|
154
|
-
puts '
|
155
|
-
puts
|
156
|
-
puts '
|
157
|
-
puts
|
158
|
-
puts
|
159
|
-
puts
|
160
|
-
puts
|
161
|
-
puts
|
162
|
-
puts
|
163
|
-
puts
|
164
|
-
puts
|
165
|
-
puts '
|
166
|
-
puts
|
167
|
-
puts
|
168
|
-
puts
|
169
|
-
puts
|
170
|
-
puts
|
171
|
-
puts
|
172
|
-
puts
|
173
|
-
puts
|
174
|
-
puts
|
175
|
-
puts '
|
176
|
-
puts
|
177
|
-
puts
|
89
|
+
if $_testing_build_return_dut_
|
90
|
+
dut
|
91
|
+
|
92
|
+
else
|
93
|
+
|
94
|
+
output_directory = options[:output] || Origen.config.output_directory
|
95
|
+
|
96
|
+
Origen.app.runner.launch action: :compile,
|
97
|
+
files: "#{Origen.root!}/templates/rtl_v/origen.v.erb",
|
98
|
+
output: output_directory,
|
99
|
+
check_for_changes: false,
|
100
|
+
quiet: true,
|
101
|
+
options: { vendor: :cadence, top: dut.name, incl: options[:incl_files] }
|
102
|
+
|
103
|
+
Origen.app.runner.launch action: :compile,
|
104
|
+
files: "#{Origen.root!}/ext",
|
105
|
+
output: output_directory,
|
106
|
+
check_for_changes: false,
|
107
|
+
quiet: true,
|
108
|
+
options: options
|
109
|
+
|
110
|
+
dut.export(rtl_top_module, dir: "#{output_directory}", namespace: nil)
|
111
|
+
|
112
|
+
puts
|
113
|
+
puts
|
114
|
+
puts 'Testbench and VPI extension created!'
|
115
|
+
puts
|
116
|
+
puts 'This file can be imported into an Origen top-level DUT model to define the pins:'
|
117
|
+
puts
|
118
|
+
puts " #{output_directory}/#{rtl_top_module}.rb"
|
119
|
+
puts
|
120
|
+
puts 'See below for what to do now to create an Origen-enabled simulation object for your particular simulator:'
|
121
|
+
puts
|
122
|
+
puts '-----------------------------------------------------------'
|
123
|
+
puts 'Cadence Incisive (irun)'
|
124
|
+
puts '-----------------------------------------------------------'
|
125
|
+
puts
|
126
|
+
puts 'Add the following to your build script (AND REMOVE ANY OTHER TESTBENCH!):'
|
127
|
+
puts
|
128
|
+
puts " #{output_directory}/origen.v \\"
|
129
|
+
puts " #{output_directory}/*.c \\"
|
130
|
+
puts ' -ccargs "-std=c99" \\'
|
131
|
+
puts ' -top origen \\'
|
132
|
+
puts ' -elaborate \\'
|
133
|
+
puts ' -snapshot origen \\'
|
134
|
+
puts ' -access +rw \\'
|
135
|
+
puts ' -timescale 1ns/1ns'
|
136
|
+
puts
|
137
|
+
puts 'Here is an example which may work for the file you just parsed (add additional -incdir options at the end if required):'
|
138
|
+
puts
|
139
|
+
puts " #{ENV['ORIGEN_SIM_IRUN'] || 'irun'} #{rtl_top} #{output_directory}/origen.v #{output_directory}/*.c -ccargs \"-std=c99\" -top origen -elaborate -snapshot origen -access +rw -timescale 1ns/1ns -incdir #{Pathname.new(rtl_top).dirname}"
|
140
|
+
puts
|
141
|
+
puts 'Copy the following directory (produced by irun) to simulation/<target>/cadence/. within your Origen application:'
|
142
|
+
puts
|
143
|
+
puts ' INCA_libs'
|
144
|
+
puts
|
145
|
+
puts '-----------------------------------------------------------'
|
146
|
+
puts 'Synopsys VCS'
|
147
|
+
puts '-----------------------------------------------------------'
|
148
|
+
puts
|
149
|
+
puts 'Add the following to your build script (AND REMOVE ANY OTHER TESTBENCH!):'
|
150
|
+
puts
|
151
|
+
puts " #{output_directory}/origen.v \\"
|
152
|
+
puts " #{output_directory}/brdige.c \\"
|
153
|
+
puts " #{output_directory}/client.c \\"
|
154
|
+
puts ' -CFLAGS "-std=c99" \\'
|
155
|
+
puts ' +vpi \\'
|
156
|
+
puts " -use_vpiobj #{output_directory}/origen.c \\"
|
157
|
+
puts ' +define+ORIGEN_VPD=1 \\'
|
158
|
+
puts ' -debug_access+all \\'
|
159
|
+
puts ' -PP \\'
|
160
|
+
puts ' -timescale=1ns/1ns'
|
161
|
+
puts
|
162
|
+
puts 'Here is an example which may work for the file you just parsed (add additional -incdir options at the end if required):'
|
163
|
+
puts
|
164
|
+
puts " #{ENV['ORIGEN_SIM_VCS'] || 'vcs'} #{rtl_top} #{output_directory}/origen.v #{output_directory}/bridge.c #{output_directory}/client.c -CFLAGS \"-std=c99\" +vpi -use_vpiobj #{output_directory}/origen.c -timescale=1ns/1ns +define+ORIGEN_VPD=1 +incdir+#{Pathname.new(rtl_top).dirname} -debug_access+all -PP"
|
165
|
+
puts
|
166
|
+
puts 'Copy the following files (produced by vcs) to simulation/<target>/synopsys/. within your Origen application:'
|
167
|
+
puts
|
168
|
+
puts ' simv'
|
169
|
+
puts ' simv.daidir'
|
170
|
+
puts
|
171
|
+
puts '-----------------------------------------------------------'
|
172
|
+
puts 'Icarus Verilog'
|
173
|
+
puts '-----------------------------------------------------------'
|
174
|
+
puts
|
175
|
+
puts 'Compile the VPI extension using the following command:'
|
176
|
+
puts
|
177
|
+
puts " cd #{output_directory} && #{ENV['ORIGEN_SIM_IVERILOG_VPI'] || 'iverilog-vpi'} *.c --name=origen && cd #{Pathname.pwd}"
|
178
|
+
puts
|
179
|
+
puts 'Add the following to your build script (AND REMOVE ANY OTHER TESTBENCH!):'
|
180
|
+
puts
|
181
|
+
puts " #{output_directory}/origen.v \\"
|
182
|
+
puts ' -o origen.vvp \\'
|
183
|
+
puts ' -DORIGEN_VCD'
|
184
|
+
puts
|
185
|
+
puts 'Here is an example which may work for the file you just parsed (add additional source dirs with more -I options at the end if required):'
|
186
|
+
puts
|
187
|
+
puts " #{ENV['ORIGEN_SIM_IVERILOG'] || 'iverilog'} #{rtl_top} #{output_directory}/origen.v -o origen.vvp -DORIGEN_VCD -I #{Pathname.new(rtl_top).dirname}"
|
188
|
+
puts
|
189
|
+
puts 'Copy the following files (produced by iverilog) to simulation/<target>/icarus/. within your Origen application:'
|
190
|
+
puts
|
191
|
+
puts " #{output_directory}/origen.vpi"
|
192
|
+
puts ' origen.vvp'
|
193
|
+
puts
|
194
|
+
puts
|
195
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'thread'
|
2
|
+
module OrigenSim
|
3
|
+
class Heartbeat < Thread
|
4
|
+
attr_reader :socket
|
5
|
+
|
6
|
+
def initialize(socket)
|
7
|
+
@socket = socket
|
8
|
+
@continue = true
|
9
|
+
super do
|
10
|
+
while @continue
|
11
|
+
socket.write("OK\n")
|
12
|
+
sleep 5
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def stop
|
18
|
+
@continue = false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'origen/application/runner'
|
2
|
+
module Origen
|
3
|
+
class Application
|
4
|
+
class Runner
|
5
|
+
# When multiple patterns are requested via the command line with the LSF option,
|
6
|
+
# Origen will split it into separate jobs for each pattern. However, if the --flow
|
7
|
+
# option is also supplied in that case, then the user will want all the patterns to
|
8
|
+
# execute as a single job on the LSF, this hack to Origen makes that happen.
|
9
|
+
alias_method :orig_expand_lists_and_directories, :expand_lists_and_directories
|
10
|
+
def expand_lists_and_directories(files, options = {})
|
11
|
+
if (options[:lsf] && OrigenSim.flow) && !Origen.running_remotely?
|
12
|
+
Array(Array(files).join(' '))
|
13
|
+
else
|
14
|
+
orig_expand_lists_and_directories(files, options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'io/wait'
|
3
|
+
require 'origen_sim/heartbeat'
|
4
|
+
module OrigenSim
|
5
|
+
# Responsible for managing each individual simulation that is run in an
|
6
|
+
# Origen thread e.g. If multiple patterns are run in separate simulations, then one
|
7
|
+
# instance of this class will exist for each one.
|
8
|
+
#
|
9
|
+
# It is primarily responsible for all communications with the simulation and capturing
|
10
|
+
# log output and errors.
|
11
|
+
class Simulation
|
12
|
+
attr_reader :view_wave_command, :id
|
13
|
+
|
14
|
+
attr_accessor :logged_errors, :error_count, :failed_to_start, :completed_cleanly
|
15
|
+
attr_accessor :pid, :stderr_logged_errors
|
16
|
+
# Returns the communication socket used for sending commands to the Origen VPI running
|
17
|
+
# in the simulation process
|
18
|
+
attr_reader :socket
|
19
|
+
|
20
|
+
def initialize(id, view_wave_command)
|
21
|
+
@id = id
|
22
|
+
@view_wave_command = view_wave_command
|
23
|
+
@completed_cleanly = false
|
24
|
+
@failed_to_start = false
|
25
|
+
@logged_errors = false
|
26
|
+
@stderr_logged_errors = false
|
27
|
+
@error_count = 0
|
28
|
+
@socket_ids = {}
|
29
|
+
|
30
|
+
@server = UNIXServer.new(socket_id) # Socket used to send Origen -> Verilog commands
|
31
|
+
@server_stdout = UNIXServer.new(socket_id(:stdout))
|
32
|
+
@server_stderr = UNIXServer.new(socket_id(:stderr))
|
33
|
+
@server_heartbeat = UNIXServer.new(socket_id(:heartbeat))
|
34
|
+
end
|
35
|
+
|
36
|
+
def failed?(in_progress = false)
|
37
|
+
failed = stderr_logged_errors || logged_errors || failed_to_start || error_count > 0
|
38
|
+
if in_progress
|
39
|
+
failed
|
40
|
+
else
|
41
|
+
failed || !completed_cleanly
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def log_results(in_progress = false)
|
46
|
+
if failed?(in_progress)
|
47
|
+
if failed_to_start
|
48
|
+
Origen.log.error 'The simulation failed to start!'
|
49
|
+
else
|
50
|
+
if in_progress
|
51
|
+
Origen.log.error "The simulation has #{error_count} error#{error_count > 1 ? 's' : ''}!" if error_count > 0
|
52
|
+
else
|
53
|
+
Origen.log.error "The simulation failed with #{error_count} errors!" if error_count > 0
|
54
|
+
end
|
55
|
+
Origen.log.error 'The simulation log reported errors!' if logged_errors
|
56
|
+
Origen.log.error 'The simulation stderr reported errors!' if stderr_logged_errors
|
57
|
+
Origen.log.error 'The simulation exited early!' unless completed_cleanly || in_progress
|
58
|
+
end
|
59
|
+
else
|
60
|
+
if in_progress
|
61
|
+
Origen.log.success 'The simulation is passing!'
|
62
|
+
else
|
63
|
+
Origen.log.success 'The simulation passed!'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Provide a heartbeat to let the parallel Ruby process in charge of the simulator
|
69
|
+
# know that the master Origen process is still alive. If the Origen process crashes and leaves
|
70
|
+
# the simulator running, the child process will automatically reap it after a couple of missed
|
71
|
+
# heartbeats.
|
72
|
+
def start_heartbeat
|
73
|
+
@heartbeat = @server_heartbeat.accept
|
74
|
+
@pid = @heartbeat.gets.chomp.to_i
|
75
|
+
@heartbeat_thread = Heartbeat.new(@heartbeat)
|
76
|
+
end
|
77
|
+
|
78
|
+
def stop_heartbeat
|
79
|
+
@heartbeat_thread.stop
|
80
|
+
end
|
81
|
+
|
82
|
+
# Open the communication channels with the simulator
|
83
|
+
def open
|
84
|
+
start_heartbeat
|
85
|
+
@stdout = @server_stdout.accept
|
86
|
+
@stderr = @server_stderr.accept
|
87
|
+
@socket = @server.accept
|
88
|
+
@opened = true
|
89
|
+
end
|
90
|
+
|
91
|
+
# Close all communication channels with the simulator
|
92
|
+
def close
|
93
|
+
return unless @opened
|
94
|
+
stop_heartbeat
|
95
|
+
@heartbeat.close
|
96
|
+
@socket.close
|
97
|
+
@stderr.close
|
98
|
+
@stdout.close
|
99
|
+
File.unlink(socket_id(:heartbeat)) if File.exist?(socket_id(:heartbeat))
|
100
|
+
File.unlink(socket_id) if File.exist?(socket_id)
|
101
|
+
File.unlink(socket_id(:stderr)) if File.exist?(socket_id(:stderr))
|
102
|
+
File.unlink(socket_id(:stdout)) if File.exist?(socket_id(:stdout))
|
103
|
+
end
|
104
|
+
|
105
|
+
def read_sim_output
|
106
|
+
while @stdout.ready?
|
107
|
+
line = @stdout.gets.chomp
|
108
|
+
if OrigenSim.error_strings.any? { |s| line =~ /#{s}/ } &&
|
109
|
+
!OrigenSim.error_string_exceptions.any? { |s| line =~ /#{s}/ }
|
110
|
+
@logged_errors = true
|
111
|
+
Origen.log.error "(STDOUT): #{line}"
|
112
|
+
else
|
113
|
+
if OrigenSim.verbose? ||
|
114
|
+
OrigenSim.log_strings.any? { |s| line =~ /#{s}/ }
|
115
|
+
Origen.log.info line
|
116
|
+
else
|
117
|
+
Origen.log.debug line
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
while @stderr.ready?
|
122
|
+
line = @stderr.gets.chomp
|
123
|
+
if OrigenSim.fail_on_stderr && !line.empty? &&
|
124
|
+
!OrigenSim.stderr_string_exceptions.any? { |s| line =~ /#{s}/ }
|
125
|
+
# We're failing on stderr, so print its results and log as errors if its not an exception.
|
126
|
+
@stderr_logged_errors = true
|
127
|
+
Origen.log.error "(STDERR): #{line}"
|
128
|
+
elsif OrigenSim.verbose?
|
129
|
+
# We're not failing on stderr, or the string in stderr is an exception.
|
130
|
+
# Print the string as regular output if verbose is set, otherwise just ignore.
|
131
|
+
Origen.log.info line
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns true if the simulation is running
|
137
|
+
def running?
|
138
|
+
return false unless pid
|
139
|
+
begin
|
140
|
+
Process.getpgid(pid)
|
141
|
+
true
|
142
|
+
rescue Errno::ESRCH
|
143
|
+
false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def socket_id(type = nil)
|
148
|
+
@socket_ids[type] ||= "/tmp/#{socket_number}#{type}.sock"
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def socket_number
|
154
|
+
@socket_number ||= (Process.pid.to_s + Time.now.to_f.to_s).sub('.', '')
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
data/lib/origen_sim/simulator.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'io/wait'
|
1
|
+
require 'origen_sim/simulation'
|
3
2
|
module OrigenSim
|
4
3
|
# Responsible for managing and communicating with the simulator
|
5
4
|
# process, a single instance of this class is instantiated as
|
@@ -9,13 +8,17 @@ module OrigenSim
|
|
9
8
|
|
10
9
|
VENDORS = [:icarus, :cadence, :synopsys, :generic]
|
11
10
|
|
12
|
-
attr_reader :
|
11
|
+
attr_reader :configuration
|
13
12
|
alias_method :config, :configuration
|
14
|
-
#
|
15
|
-
attr_reader :
|
13
|
+
# The instance of OrigenSim::Simulation for the current simulation
|
14
|
+
attr_reader :simulation
|
15
|
+
# Returns an array containing all instances of OrigenSim::Simulation that were created
|
16
|
+
# in the order that they were created
|
17
|
+
attr_reader :simulations
|
16
18
|
|
17
19
|
def initialize
|
18
|
-
@
|
20
|
+
@simulations = []
|
21
|
+
@simulation_open = false
|
19
22
|
end
|
20
23
|
|
21
24
|
# When set to true the simulator will log all messages it receives, note that
|
@@ -140,7 +143,7 @@ module OrigenSim
|
|
140
143
|
end
|
141
144
|
end
|
142
145
|
|
143
|
-
def wave_dir
|
146
|
+
def wave_dir(subdir = nil)
|
144
147
|
@wave_dir ||= begin
|
145
148
|
d = "#{Origen.root}/waves/#{id}"
|
146
149
|
FileUtils.mkdir_p(d)
|
@@ -198,17 +201,17 @@ module OrigenSim
|
|
198
201
|
cmd += " -M#{compiled_dir} -morigen #{compiled_dir}/origen.vvp +socket+#{socket_id}"
|
199
202
|
|
200
203
|
when :cadence
|
201
|
-
input_file = "#{tmp_dir}/#{
|
204
|
+
input_file = "#{tmp_dir}/#{wave_file_basename}.tcl"
|
202
205
|
if !File.exist?(input_file) || config_changed?
|
203
206
|
Origen.app.runner.launch action: :compile,
|
204
207
|
files: "#{Origen.root!}/templates/probe.tcl.erb",
|
205
208
|
output: tmp_dir,
|
206
209
|
check_for_changes: false,
|
207
210
|
quiet: true,
|
208
|
-
options: { dir: wave_dir, force: config[:force], setup: config[:setup], depth: :all },
|
209
|
-
output_file_name: "#{
|
211
|
+
options: { dir: wave_dir, wave_file: wave_file_basename, force: config[:force], setup: config[:setup], depth: :all },
|
212
|
+
output_file_name: "#{wave_file_basename}.tcl"
|
210
213
|
end
|
211
|
-
input_file_fast = "#{tmp_dir}/#{
|
214
|
+
input_file_fast = "#{tmp_dir}/#{wave_file_basename}_fast.tcl"
|
212
215
|
if !File.exist?(input_file_fast) || config_changed?
|
213
216
|
fast_probe_depth = config[:fast_probe_depth] || 1
|
214
217
|
Origen.app.runner.launch action: :compile,
|
@@ -216,8 +219,8 @@ module OrigenSim
|
|
216
219
|
output: tmp_dir,
|
217
220
|
check_for_changes: false,
|
218
221
|
quiet: true,
|
219
|
-
options: { dir: wave_dir, force: config[:force], setup: config[:setup], depth: fast_probe_depth },
|
220
|
-
output_file_name: "#{
|
222
|
+
options: { dir: wave_dir, wave_file: wave_file_basename, force: config[:force], setup: config[:setup], depth: fast_probe_depth },
|
223
|
+
output_file_name: "#{wave_file_basename}_fast.tcl"
|
221
224
|
end
|
222
225
|
save_config_signature
|
223
226
|
wave_dir # Ensure this exists since it won't be referenced above if the input file is already generated
|
@@ -228,7 +231,7 @@ module OrigenSim
|
|
228
231
|
cmd += " -nclibdirpath #{compiled_dir}"
|
229
232
|
|
230
233
|
when :synopsys
|
231
|
-
cmd = "#{compiled_dir}/simv +socket+#{socket_id} -vpd_file
|
234
|
+
cmd = "#{compiled_dir}/simv +socket+#{socket_id} -vpd_file #{wave_file_basename}.vpd"
|
232
235
|
|
233
236
|
when :generic
|
234
237
|
# Generic tester requires that a generic_run_command option/block be provided.
|
@@ -269,6 +272,18 @@ module OrigenSim
|
|
269
272
|
cmd
|
270
273
|
end
|
271
274
|
|
275
|
+
def wave_file_basename
|
276
|
+
if OrigenSim.flow
|
277
|
+
OrigenSim.flow.to_s
|
278
|
+
else
|
279
|
+
if Origen.app.current_job
|
280
|
+
@last_wafe_file_basename = Pathname.new(Origen.app.current_job.output_file).basename('.*').to_s
|
281
|
+
else
|
282
|
+
@last_wafe_file_basename
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
272
287
|
def view_wave_command
|
273
288
|
cmd = nil
|
274
289
|
case config[:vendor]
|
@@ -277,7 +292,7 @@ module OrigenSim
|
|
277
292
|
cmd = "cd #{edir} && "
|
278
293
|
cmd += configuration[:gtkwave] || 'gtkwave'
|
279
294
|
dir = Pathname.new(wave_dir).relative_path_from(edir.expand_path)
|
280
|
-
cmd += " #{dir}/
|
295
|
+
cmd += " #{dir}/#{wave_file_basename}/dump.vcd "
|
281
296
|
f = Pathname.new(wave_config_file).relative_path_from(edir.expand_path)
|
282
297
|
cmd += " --save #{f} &"
|
283
298
|
|
@@ -286,7 +301,7 @@ module OrigenSim
|
|
286
301
|
cmd = "cd #{edir} && "
|
287
302
|
cmd += configuration[:simvision] || 'simvision'
|
288
303
|
dir = Pathname.new(wave_dir).relative_path_from(edir.expand_path)
|
289
|
-
cmd += " #{dir}/#{
|
304
|
+
cmd += " #{dir}/#{wave_file_basename}/#{wave_file_basename}.dsn #{dir}/#{wave_file_basename}/#{wave_file_basename}.trn"
|
290
305
|
f = Pathname.new(wave_config_file).relative_path_from(edir.expand_path)
|
291
306
|
cmd += " -input #{f} &"
|
292
307
|
|
@@ -295,7 +310,7 @@ module OrigenSim
|
|
295
310
|
cmd = "cd #{edir} && "
|
296
311
|
cmd += configuration[:dve] || 'dve'
|
297
312
|
dir = Pathname.new(wave_dir).relative_path_from(edir.expand_path)
|
298
|
-
cmd += " -vpd #{dir}
|
313
|
+
cmd += " -vpd #{dir}/#{wave_file_basename}.vpd"
|
299
314
|
f = Pathname.new(wave_config_file).relative_path_from(edir.expand_path)
|
300
315
|
cmd += " -session #{f}"
|
301
316
|
cmd += ' &'
|
@@ -320,31 +335,29 @@ module OrigenSim
|
|
320
335
|
|
321
336
|
def run_dir
|
322
337
|
case config[:vendor]
|
323
|
-
when :icarus
|
338
|
+
when :icarus
|
339
|
+
d = File.join(wave_dir, wave_file_basename)
|
340
|
+
FileUtils.mkdir_p(d)
|
341
|
+
d
|
342
|
+
when :synopsys
|
324
343
|
wave_dir
|
325
344
|
else
|
326
345
|
tmp_dir
|
327
346
|
end
|
328
347
|
end
|
329
348
|
|
349
|
+
def simulation_open?
|
350
|
+
@simulation_open
|
351
|
+
end
|
352
|
+
|
330
353
|
# Starts up the simulator process
|
331
354
|
def start
|
355
|
+
@simulation_open = true
|
356
|
+
@simulation = Simulation.new(wave_file_basename, view_wave_command)
|
357
|
+
simulations << @simulation
|
358
|
+
|
332
359
|
fetch_simulation_objects
|
333
360
|
|
334
|
-
# Socket used for Origen -> Verilog commands
|
335
|
-
server = UNIXServer.new(socket_id)
|
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)
|
348
361
|
cmd = run_cmd + ' & echo \$!'
|
349
362
|
|
350
363
|
launch_simulator = %(
|
@@ -355,9 +368,19 @@ module OrigenSim
|
|
355
368
|
|
356
369
|
pid = nil
|
357
370
|
|
358
|
-
|
359
|
-
|
360
|
-
|
371
|
+
def kill_simulation(pid)
|
372
|
+
begin
|
373
|
+
# If the process already finished, then we will see an Errno exception.
|
374
|
+
# It does not harm anything, but looks ugly, so catch it here and ignore.
|
375
|
+
Process.kill('KILL', pid)
|
376
|
+
rescue Errno::ESRCH => e
|
377
|
+
end
|
378
|
+
exit!
|
379
|
+
end
|
380
|
+
|
381
|
+
stdout_socket = UNIXSocket.new('#{simulation.socket_id(:stdout)}')
|
382
|
+
stderr_socket = UNIXSocket.new('#{simulation.socket_id(:stderr)}')
|
383
|
+
heartbeat = UNIXSocket.new('#{simulation.socket_id(:heartbeat)}')
|
361
384
|
|
362
385
|
begin
|
363
386
|
|
@@ -372,6 +395,14 @@ module OrigenSim
|
|
372
395
|
missed_heartbeats = 0
|
373
396
|
loop do
|
374
397
|
sleep 5
|
398
|
+
|
399
|
+
# If the socket read hangs, count that as a reason to shutdown
|
400
|
+
socket_read = false
|
401
|
+
Thread.new do
|
402
|
+
sleep 1
|
403
|
+
kill_simulation(pid) unless socket_read
|
404
|
+
end
|
405
|
+
|
375
406
|
if heartbeat.ready?
|
376
407
|
while heartbeat.ready? do
|
377
408
|
heartbeat.gets
|
@@ -380,9 +411,9 @@ module OrigenSim
|
|
380
411
|
else
|
381
412
|
missed_heartbeats += 1
|
382
413
|
end
|
414
|
+
socket_read = true
|
383
415
|
if missed_heartbeats > 1
|
384
|
-
|
385
|
-
exit!(1)
|
416
|
+
kill_simulation(pid)
|
386
417
|
end
|
387
418
|
end
|
388
419
|
end
|
@@ -404,14 +435,7 @@ module OrigenSim
|
|
404
435
|
|
405
436
|
ensure
|
406
437
|
# Make sure this process never finishes and leaves the simulator running
|
407
|
-
|
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
|
414
|
-
end
|
438
|
+
kill_simulation(pid) if pid
|
415
439
|
end
|
416
440
|
)
|
417
441
|
|
@@ -419,34 +443,19 @@ module OrigenSim
|
|
419
443
|
Process.detach(simulator_parent_process)
|
420
444
|
|
421
445
|
timeout_connection(config[:startup_timeout] || 60) do
|
422
|
-
|
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
|
446
|
+
simulation.open # This will block until the simulation process responds
|
432
447
|
|
433
|
-
@
|
434
|
-
@stderr = server_stderr.accept
|
435
|
-
@socket = server.accept
|
436
|
-
@connection_established = true
|
448
|
+
@connection_established = true # Cancels timeout_connection
|
437
449
|
if @connection_timed_out
|
438
|
-
|
439
|
-
|
440
|
-
@failed = true
|
441
|
-
exit
|
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
|
442
452
|
end
|
443
453
|
end
|
444
454
|
data = get
|
445
455
|
unless data.strip == 'READY!'
|
446
|
-
|
447
|
-
|
456
|
+
simulation.failed_to_start = true
|
457
|
+
exit # Assume it is not worth trying another pattern in this case, some kind of environment/config issue
|
448
458
|
end
|
449
|
-
@enabled = true
|
450
459
|
# Tick the simulation on, this seems to be required since any VPI puts operations before
|
451
460
|
# the simulation has started are not applied.
|
452
461
|
# Note that this is not setting a tester timeset, so the application will still have to
|
@@ -456,64 +465,64 @@ module OrigenSim
|
|
456
465
|
Origen.listeners_for(:simulation_startup).each(&:simulation_startup)
|
457
466
|
end
|
458
467
|
|
459
|
-
# Returns true if the simulator process is running
|
460
|
-
def running?
|
461
|
-
return false unless pid
|
462
|
-
begin
|
463
|
-
Process.getpgid(pid)
|
464
|
-
true
|
465
|
-
rescue Errno::ESRCH
|
466
|
-
false
|
467
|
-
end
|
468
|
-
end
|
469
|
-
|
470
468
|
# Send the given message string to the simulator
|
471
469
|
def put(msg)
|
472
|
-
socket.write(msg + "\n")
|
470
|
+
simulation.socket.write(msg + "\n")
|
473
471
|
end
|
474
472
|
|
475
473
|
# Get a message from the simulator, will block until one
|
476
474
|
# is received
|
477
475
|
def get
|
478
|
-
socket.readline
|
476
|
+
simulation.socket.readline
|
479
477
|
end
|
480
478
|
|
481
|
-
#
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
479
|
+
# At the start of a test program flow generation/simulation
|
480
|
+
def on_flow_start(options)
|
481
|
+
if simulation_tester? && options[:top_level]
|
482
|
+
OrigenSim.flow = Origen.interface.flow.name
|
483
|
+
start
|
484
|
+
@pattern_count = 0
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
# At the end of a test program flow generation/simulation
|
489
|
+
def on_flow_end(options)
|
490
|
+
if simulation_tester? && options[:top_level]
|
491
|
+
stop
|
492
|
+
end
|
487
493
|
end
|
488
494
|
|
489
495
|
# Called before every pattern is generated, but we only use it the
|
490
496
|
# first time it is called to kick off the simulator process if the
|
491
497
|
# current tester is an OrigenSim::Tester
|
492
498
|
def before_pattern(name)
|
493
|
-
@simulation_completed_cleanly = false
|
494
499
|
if simulation_tester?
|
495
|
-
|
496
|
-
# When running
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
500
|
+
if OrigenSim.flow || !simulation
|
501
|
+
# When running patterns back-to-back, only want to launch the simulator the first time
|
502
|
+
start unless simulation
|
503
|
+
else
|
504
|
+
stop
|
505
|
+
start
|
501
506
|
end
|
502
507
|
# Set the current pattern name in the simulation
|
503
508
|
put("a^#{name.sub(/\..*/, '')}")
|
504
509
|
@pattern_count ||= 0
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
else
|
510
|
-
Origen.log.success 'There are no simulation errors yet!'
|
511
|
-
end
|
510
|
+
# If running a flow, give the user some feedback about pass/fail status after
|
511
|
+
# each individual pattern has completed
|
512
|
+
if @pattern_count > 0 && OrigenSim.flow
|
513
|
+
simulation.log_results(true)
|
512
514
|
end
|
513
515
|
@pattern_count += 1
|
514
516
|
end
|
515
517
|
end
|
516
518
|
|
519
|
+
# This will be called at the end of every pattern, make
|
520
|
+
# sure the simulator is not running behind before potentially
|
521
|
+
# moving onto another pattern
|
522
|
+
def pattern_generated(path)
|
523
|
+
sync_up if simulation_tester?
|
524
|
+
end
|
525
|
+
|
517
526
|
def write_comment(comment)
|
518
527
|
# Not sure what the limiting factor here is, the comment memory in the test bench should
|
519
528
|
# be able to handle 1024 / 8 length strings, but any bigger than this hangs the simulation
|
@@ -590,7 +599,7 @@ module OrigenSim
|
|
590
599
|
|
591
600
|
def cycle(number_of_cycles)
|
592
601
|
put("3^#{number_of_cycles}")
|
593
|
-
read_sim_output
|
602
|
+
simulation.read_sim_output
|
594
603
|
end
|
595
604
|
|
596
605
|
# Blocks the Origen process until the simulator indicates that it has
|
@@ -601,37 +610,12 @@ module OrigenSim
|
|
601
610
|
unless data.strip == 'OK!'
|
602
611
|
fail 'Origen and the simulator are out of sync!'
|
603
612
|
end
|
604
|
-
read_sim_output
|
613
|
+
simulation.read_sim_output
|
605
614
|
end
|
606
615
|
|
607
|
-
def
|
608
|
-
|
609
|
-
|
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
|
616
|
+
def error(message)
|
617
|
+
simulation.logged_errors = true
|
618
|
+
Origen.log.error message
|
635
619
|
end
|
636
620
|
|
637
621
|
# Returns the current simulation error count
|
@@ -732,62 +716,71 @@ module OrigenSim
|
|
732
716
|
|
733
717
|
# Stop the simulator
|
734
718
|
def stop
|
719
|
+
@simulation_open = false
|
720
|
+
simulation.read_sim_output
|
721
|
+
simulation.error_count = error_count
|
735
722
|
Origen.listeners_for(:simulation_shutdown).each(&:simulation_shutdown)
|
736
723
|
ended = Time.now
|
737
724
|
end_simulation
|
738
725
|
# Give the simulator time to shut down
|
739
|
-
sleep 0.1 while running?
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
heartbeat.close if heartbeat
|
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))
|
726
|
+
sleep 0.1 while simulation.running?
|
727
|
+
simulation.close
|
728
|
+
simulation.completed_cleanly = true
|
729
|
+
simulation.log_results unless Origen.current_command == 'interactive'
|
748
730
|
end
|
749
731
|
|
750
732
|
def on_origen_shutdown
|
751
|
-
|
733
|
+
unless simulations.empty?
|
734
|
+
failed = false
|
735
|
+
# Stop the current simulation, this is done with the rescue wrapper so that the rest
|
736
|
+
# of the shutdown continues if we got in here via a CTRL-C, in which case the simulator
|
737
|
+
# is probably already dead
|
738
|
+
begin
|
739
|
+
stop if simulation_open?
|
740
|
+
rescue
|
741
|
+
simulation.completed_cleanly = false
|
742
|
+
end
|
752
743
|
unless @interactive_mode
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
Origen.log.error "
|
759
|
-
|
760
|
-
Origen.log.error 'The simulation stderr reported errors!' if @stderr_logged_errors
|
761
|
-
elsif !@simulation_completed_cleanly
|
762
|
-
@failed = true
|
763
|
-
Origen.log.error 'The simulation exited early!'
|
744
|
+
if simulations.size == 1
|
745
|
+
failed = simulation.failed?
|
746
|
+
else
|
747
|
+
failed_simulation_count = simulations.count(&:failed?)
|
748
|
+
if failed_simulation_count > 0
|
749
|
+
Origen.log.error "#{failed_simulation_count} of #{simulations.size} simulations failed!"
|
750
|
+
failed = true
|
764
751
|
end
|
765
752
|
end
|
766
|
-
end
|
767
|
-
stop
|
768
|
-
unless @interactive_mode
|
769
753
|
if failed
|
770
754
|
Origen.app.stats.report_fail
|
771
755
|
else
|
772
756
|
Origen.app.stats.report_pass
|
773
757
|
end
|
774
758
|
end
|
775
|
-
|
776
|
-
|
759
|
+
puts
|
760
|
+
if simulations.size == 1
|
777
761
|
puts 'To view the simulation run the following command:'
|
778
762
|
puts
|
779
|
-
puts " #{view_wave_command}"
|
763
|
+
puts " #{simulation.view_wave_command}"
|
764
|
+
else
|
765
|
+
puts 'To view the simulations run the following commands:'
|
780
766
|
puts
|
767
|
+
simulations.each do |simulation|
|
768
|
+
if simulation.failed?
|
769
|
+
puts " #{simulation.view_wave_command}".red
|
770
|
+
else
|
771
|
+
puts " #{simulation.view_wave_command}"
|
772
|
+
end
|
773
|
+
end
|
774
|
+
end
|
775
|
+
puts
|
776
|
+
unless @interactive_mode
|
777
|
+
failed ? exit(1) : exit(0)
|
781
778
|
end
|
782
779
|
end
|
783
780
|
end
|
784
781
|
|
785
|
-
def socket_id
|
786
|
-
|
787
|
-
end
|
788
|
-
|
789
|
-
def socket_number
|
790
|
-
@socket_number ||= (Process.pid.to_s + Time.now.to_f.to_s).sub('.', '')
|
782
|
+
def socket_id
|
783
|
+
simulation.socket_id
|
791
784
|
end
|
792
785
|
|
793
786
|
def simulation_tester?
|
@@ -796,6 +789,7 @@ module OrigenSim
|
|
796
789
|
|
797
790
|
def timeout_connection(wait_in_s)
|
798
791
|
@connection_timed_out = false
|
792
|
+
@connection_established = false
|
799
793
|
t = Thread.new do
|
800
794
|
sleep wait_in_s
|
801
795
|
# If the Verilog process has not established a connection yet, then make one to
|
data/lib/origen_sim.rb
CHANGED
@@ -4,6 +4,7 @@ require 'origen_testers'
|
|
4
4
|
require 'origen_sim/origen_testers/api'
|
5
5
|
require 'origen_sim/origen/pins/pin'
|
6
6
|
require 'origen_sim/origen/top_level'
|
7
|
+
require 'origen_sim/origen/application/runner'
|
7
8
|
module OrigenSim
|
8
9
|
# THIS FILE SHOULD ONLY BE USED TO LOAD RUNTIME DEPENDENCIES
|
9
10
|
# If this plugin has any development dependencies (e.g. dummy DUT or other models that are only used
|
@@ -46,7 +47,15 @@ module OrigenSim
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def self.verbose?
|
49
|
-
!!(@verbose || Origen.debugger_enabled?)
|
50
|
+
!!(@verbose || Origen.debugger_enabled? || Origen.running_remotely?)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.flow=(val)
|
54
|
+
@flow = val
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.flow
|
58
|
+
@flow
|
50
59
|
end
|
51
60
|
|
52
61
|
def self.error_strings
|
@@ -100,5 +109,9 @@ module OrigenSim
|
|
100
109
|
def self.fail_on_stderr
|
101
110
|
defined?(@fail_on_stderr) ? @fail_on_stderr : true
|
102
111
|
end
|
112
|
+
|
113
|
+
def self.error(message)
|
114
|
+
simulator.error(message)
|
115
|
+
end
|
103
116
|
end
|
104
117
|
OrigenSim.__instantiate_simulator__
|
data/pattern/test.rb
CHANGED
@@ -45,12 +45,12 @@ Pattern.create do
|
|
45
45
|
|
46
46
|
if tester.sim?
|
47
47
|
sim = tester.simulator
|
48
|
-
capture_value = sim.peek("origen.pins.tdo.memory").to_i
|
48
|
+
capture_value = sim.peek("origen.pins.tdo.memory").to_i[31..0]
|
49
49
|
unless capture_value == 0x11662244 # 0x2244_6688 reversed
|
50
50
|
if capture_value
|
51
|
-
|
51
|
+
OrigenSim.error "Captured #{capture_value.to_hex} instead of 0x11662244!"
|
52
52
|
else
|
53
|
-
|
53
|
+
OrigenSim.error "Nothing captured instead of 0x11662244!"
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -58,7 +58,7 @@ Pattern.create do
|
|
58
58
|
dut.cmd.write(0) # Make Origen forget the actual value
|
59
59
|
dut.cmd.sync
|
60
60
|
unless dut.cmd.data == 0x2244_6688
|
61
|
-
|
61
|
+
OrigenSim.error "CMD register did not sync from simulation"
|
62
62
|
end
|
63
63
|
|
64
64
|
ss "Test sync of a register via a parallel interface"
|
@@ -68,7 +68,7 @@ Pattern.create do
|
|
68
68
|
dut.pins(:dout).dont_care
|
69
69
|
dut.parallel_read.sync
|
70
70
|
unless dut.parallel_read.data == 0x7707_7077
|
71
|
-
|
71
|
+
OrigenSim.error "PARALLEL_READ register did not sync from simulation"
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
data/pattern/test2.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pattern/test.rb
|
data/program/p1.rb
CHANGED
data/program/p2.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
program/p1.rb
|
data/templates/probe.tcl.erb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
database -open waves -into <%= options[:dir] %> -default -event
|
1
|
+
database -open waves -into <%= options[:dir] %>/<%= options[:wave_file] %> -default -event
|
2
2
|
probe -create -shm origen -depth <%= options[:depth] %> -database waves
|
3
3
|
#probe -create -assertions -transaction origen -depth all -database waves
|
4
4
|
|
@@ -157,7 +157,7 @@ module origen;
|
|
157
157
|
//$display("********************************");
|
158
158
|
//$display("Creating origen.vcd...");
|
159
159
|
//$display("********************************");
|
160
|
-
|
160
|
+
//$dumpfile("origen.vcd");
|
161
161
|
$dumpvars(0,origen);
|
162
162
|
end
|
163
163
|
`endif
|
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.10.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-
|
11
|
+
date: 2018-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: origen
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.
|
47
|
+
version: '0.4'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.
|
54
|
+
version: '0.4'
|
55
55
|
description:
|
56
56
|
email:
|
57
57
|
- stephen.f.mcginty@gmail.com
|
@@ -81,15 +81,20 @@ files:
|
|
81
81
|
- lib/origen_sim/commands/pack.rb
|
82
82
|
- lib/origen_sim/flow.rb
|
83
83
|
- lib/origen_sim/generator.rb
|
84
|
+
- lib/origen_sim/heartbeat.rb
|
85
|
+
- lib/origen_sim/origen/application/runner.rb
|
84
86
|
- lib/origen_sim/origen/pins/pin.rb
|
85
87
|
- lib/origen_sim/origen/top_level.rb
|
86
88
|
- lib/origen_sim/origen_testers/api.rb
|
89
|
+
- lib/origen_sim/simulation.rb
|
87
90
|
- lib/origen_sim/simulator.rb
|
88
91
|
- lib/origen_sim/tester.rb
|
89
92
|
- lib/origen_sim_dev/dut.rb
|
90
93
|
- lib/tasks/origen_sim.rake
|
91
94
|
- pattern/test.rb
|
95
|
+
- pattern/test2.rb
|
92
96
|
- program/p1.rb
|
97
|
+
- program/p2.rb
|
93
98
|
- templates/empty.gtkw
|
94
99
|
- templates/empty.svcf
|
95
100
|
- templates/empty.tcl
|
@@ -118,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
123
|
version: 1.8.11
|
119
124
|
requirements: []
|
120
125
|
rubyforge_project:
|
121
|
-
rubygems_version: 2.6.
|
126
|
+
rubygems_version: 2.6.14.1
|
122
127
|
signing_key:
|
123
128
|
specification_version: 4
|
124
129
|
summary: Plugin that provides a testbench environment to simulate Origen test patterns
|