fhlow 1.91.0 → 1.91.1
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.
- data/bin/fhlow +58 -10
- data/lib/module_config/complexitem.rb +57 -0
- data/lib/module_config/config.rb +5 -3
- data/lib/module_config/item.rb +0 -4
- data/lib/module_config/items/complex.rb +44 -0
- data/lib/module_config/items/complexfreqencies.rb +59 -0
- data/lib/module_config/items/complexlibrary.rb +46 -0
- data/lib/module_config/items/complexpackage.rb +47 -0
- data/lib/module_config/items/complexpins.rb +59 -0
- data/lib/module_config/items/complexunit.rb +53 -0
- data/lib/module_config/items/simple.rb +29 -0
- data/lib/module_config/items/simplearchitecture.rb +34 -0
- data/lib/module_config/items/simplebindir.rb +31 -0
- data/lib/module_config/items/simplebool.rb +24 -0
- data/lib/module_config/items/simplepostlayoutsdf.rb +24 -0
- data/lib/module_config/items/simplesimulaterun.rb +25 -0
- data/lib/module_config/items/simpleverbose.rb +33 -0
- data/lib/module_config/section.rb +16 -4
- data/lib/module_config/simpleitem.rb +37 -0
- data/lib/module_config/test.flw +33 -12
- data/lib/module_config/test.rb +54 -4
- data/lib/module_config/unittests/config_test.rb +15 -12
- data/lib/module_fhlow/leaf.rb +28 -24
- data/lib/module_fhlow/leafs/Library.rb +60 -0
- data/lib/module_fhlow/leafs/Package.rb +4 -1
- data/lib/module_fhlow/leafs/Unit.rb +9 -1
- data/lib/module_fhlow/node.rb +4 -5
- data/lib/module_fhlow/plugin.rb +11 -0
- data/lib/module_fhlow/pluginpool.rb +17 -5
- data/lib/module_fhlow/rootnode.rb +4 -3
- data/lib/plugins/Modelsim.flw +18 -0
- data/lib/plugins/Modelsim.rb +331 -0
- data/lib/plugins/Quartus.flw +5 -0
- data/lib/plugins/Quartus.rb +237 -0
- data/tests/testsuite.rb +0 -0
- metadata +84 -79
- data/lib/module_config/configitems/complex.rb +0 -71
- data/lib/module_config/configitems/complexpackage.rb +0 -67
- data/lib/module_config/configitems/complexunit.rb +0 -76
- data/lib/module_config/configitems/simple.rb +0 -56
- data/lib/module_config/configitems/simplearchitecture.rb +0 -52
- data/lib/module_config/configitems/simplepackage.rb +0 -47
- data/lib/module_config/configitems/simpleunit.rb +0 -53
- data/lib/module_config/configs.test +0 -24
- data/lib/module_config/tmp +0 -3
- data/lib/module_config/unittests/coverage/-home-simon-tmp-fhlow_v2-flw-core-lib-module_config-configexception_rb.html +0 -647
- data/lib/module_config/unittests/coverage/-home-simon-tmp-fhlow_v2-flw-core-lib-module_config-configitems-complex_rb.html +0 -700
- data/lib/module_config/unittests/coverage/-home-simon-tmp-fhlow_v2-flw-core-lib-module_config-configitems-complexpackage_rb.html +0 -694
- data/lib/module_config/unittests/coverage/-home-simon-tmp-fhlow_v2-flw-core-lib-module_config-configitems-complexunit_rb.html +0 -704
- data/lib/module_config/unittests/coverage/-home-simon-tmp-fhlow_v2-flw-core-lib-module_config-configitems-simple_rb.html +0 -685
- data/lib/module_config/unittests/coverage/-home-simon-tmp-fhlow_v2-flw-core-lib-module_config-configitems-simplepackage_rb.html +0 -676
- data/lib/module_config/unittests/coverage/-home-simon-tmp-fhlow_v2-flw-core-lib-module_config-configitems-simpleunit_rb.html +0 -682
- data/lib/module_config/unittests/coverage/-home-simon-tmp-fhlow_v2-flw-core-lib-module_config-item_rb.html +0 -663
- data/lib/module_config/unittests/coverage/-home-simon-tmp-fhlow_v2-flw-core-lib-module_config-itemfactory_rb.html +0 -687
- data/lib/module_config/unittests/coverage/-home-simon-tmp-fhlow_v2-flw-core-lib-module_config-myconfig_rb.html +0 -687
- data/lib/module_config/unittests/coverage/-home-simon-tmp-fhlow_v2-flw-core-lib-module_config-section_rb.html +0 -692
- data/lib/module_config/unittests/coverage/index.html +0 -689
- data/lib/module_fhlow/leaf.rb~ +0 -202
- data/lib/module_fhlow/test.rb +0 -15
@@ -25,7 +25,7 @@ Dir.glob(detectFhlowRootDir+"flw/core/lib/module_*") { |entry| $:.unshift(entry)
|
|
25
25
|
#######################################################################################
|
26
26
|
|
27
27
|
require 'test/unit'
|
28
|
-
require '
|
28
|
+
require 'config'
|
29
29
|
require 'configitems/simple'
|
30
30
|
require 'configitems/simpleunit'
|
31
31
|
require 'configitems/simplepackage'
|
@@ -81,9 +81,6 @@ class TC_config_test < Test::Unit::TestCase
|
|
81
81
|
|
82
82
|
assert_equal(s1.value, s.value)
|
83
83
|
|
84
|
-
assert_equal(/^\s*(\w+)\s*=\s*([\w,.;\s]+)\s*$/, Config::Simple.getRegex())
|
85
|
-
|
86
|
-
|
87
84
|
str = "ComplexUnits = {
|
88
85
|
1,2,3(bla);
|
89
86
|
4,5,6(bhv)
|
@@ -370,11 +367,13 @@ class TC_config_test < Test::Unit::TestCase
|
|
370
367
|
s2 = nil
|
371
368
|
|
372
369
|
assert_nothing_raised() do
|
373
|
-
s = Config::ComplexPackage.new("ComplexPackageThing = { No;
|
370
|
+
s = Config::ComplexPackage.new("ComplexPackageThing = { No; th, ing }")
|
374
371
|
s1 = Config::ComplexPackage.new("ComplexPackageThing = { Other; Value }")
|
375
372
|
s2 = Config::ComplexPackage.new("12Package34 = { 1; 2; 3; 4 }")
|
376
373
|
end
|
377
374
|
|
375
|
+
assert_equal([["No"], ["th","ing"]], s.value)
|
376
|
+
|
378
377
|
assert_raise(Config::ConfigMergeException) do
|
379
378
|
s.merge(s2)
|
380
379
|
end
|
@@ -383,11 +382,9 @@ class TC_config_test < Test::Unit::TestCase
|
|
383
382
|
s.merge(s1)
|
384
383
|
end
|
385
384
|
|
386
|
-
assert_equal(["Other", "Value", "No", "
|
385
|
+
assert_equal([["Other"], ["Value"], ["No"], ["th", "ing"]], s.value)
|
387
386
|
|
388
|
-
assert_equal(/(\w*Package\w*)\s*=(\s*|[\n]*)\{((\s*[^\(\)]*[;][\s\n]*)*(\s*[^\(\)]*[;]*[\s\n]*))\}/, Config::ComplexPackage.getRegex())
|
389
387
|
|
390
|
-
|
391
388
|
str = "ComplexUnits = {
|
392
389
|
1,2,3(bla);
|
393
390
|
4,5,6(bhv)
|
@@ -463,14 +460,20 @@ class TC_config_test < Test::Unit::TestCase
|
|
463
460
|
s.merge(s1)
|
464
461
|
end
|
465
462
|
|
466
|
-
assert_equal([ {"archs"=>["bhv", "bla", "123"], "deppath"=>"Other, Value"},
|
467
|
-
{"archs"=>["arch"], "deppath"=>"No"},
|
468
|
-
{"archs"=>["itecture"], "deppath"=>"thing"}],
|
463
|
+
assert_equal([ {"archs"=>["bhv", "bla", "123"], "deppath"=>["Other", "Value"]},
|
464
|
+
{"archs"=>["arch"], "deppath"=>["No"]},
|
465
|
+
{"archs"=>["itecture"], "deppath"=>["thing"]}],
|
469
466
|
s.value)
|
470
467
|
|
471
|
-
|
468
|
+
puts
|
469
|
+
p s.value
|
470
|
+
puts
|
472
471
|
|
472
|
+
s.merge(Config::ComplexUnit.new("ComplexUnitThing = { No(aasrch); thing(itecture) }"))
|
473
473
|
|
474
|
+
p s.value
|
475
|
+
puts
|
476
|
+
|
474
477
|
str = "ComplexUnits = {
|
475
478
|
1,2,3(bla);
|
476
479
|
4,5,6(bhv)
|
data/lib/module_fhlow/leaf.rb
CHANGED
@@ -82,12 +82,19 @@ module Fhlow
|
|
82
82
|
if @conf["Dependencies"].nil?
|
83
83
|
raise FhlowException.new(getPath, "Couldn't find section [Dependencies] in any config.flw file responsible for this leaf.")
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
# iterate through all items of the [Dependencies] section
|
87
87
|
@conf["Dependencies"].each do |item| # item -> one item of the [Dependencies] section
|
88
88
|
fetchOneDependency(item)
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
|
+
|
92
|
+
# there needs to be a target section the config file
|
93
|
+
if @conf["Target"+@conf["Target"]["Target"]].nil?
|
94
|
+
raise FhlowException.new(getPath, "Couldn't find section [Target#{@conf["Target"]["Target"]}] in any config.flw file responsible for this leaf.")
|
95
|
+
end
|
96
|
+
fetchOneDependency(@conf["Target"+@conf["Target"]["Target"]].getItem("SimulationLibraries"))
|
97
|
+
|
91
98
|
dummy = ""
|
92
99
|
@dependencies.each{ |deptype, leafs| dummy += "#{deptype} -> "; leafs.each { |leaf| dummy += "#{leaf.prefix}#{leaf.name} "}; dummy += "; " }
|
93
100
|
@log.debug(@prefix+@name, "direct dependencies: #{dummy}")
|
@@ -121,7 +128,7 @@ module Fhlow
|
|
121
128
|
@dependencies[_item.name].push(leaf) unless @dependencies[_item.name].include?(leaf)
|
122
129
|
end
|
123
130
|
|
124
|
-
elsif _item.instance_of?(Config::ComplexPackage)
|
131
|
+
elsif _item.instance_of?(Config::ComplexPackage) or _item.instance_of?(Config::ComplexLibrary)
|
125
132
|
_item.value.each do |value|
|
126
133
|
begin
|
127
134
|
leaf = @parent.getLeaf(value, value.length-1)
|
@@ -130,7 +137,9 @@ module Fhlow
|
|
130
137
|
# fetch the exception and add the name of this leaf so the errormessage is more accurate
|
131
138
|
raise FhlowObjectNotFoundException.new(@prefix+@name), "#{e.caller}: #{e.message}"
|
132
139
|
end
|
133
|
-
|
140
|
+
|
141
|
+
|
142
|
+
|
134
143
|
# init the container if it is nil
|
135
144
|
@dependencies[_item.name] = Array.new if @dependencies[_item.name].nil?
|
136
145
|
|
@@ -142,13 +151,6 @@ module Fhlow
|
|
142
151
|
|
143
152
|
|
144
153
|
|
145
|
-
=begin def fetchOneDependency(_name, _value)
|
146
|
-
# this funktion needs to be implemented in an derived class!
|
147
|
-
raise FhlowException.new(self.class), "fetchOneDependency() is not implemented for "+self.class.to_s
|
148
|
-
end
|
149
|
-
=end
|
150
|
-
|
151
|
-
|
152
154
|
# This function returns an Array of filenames in respect of the dependency tree and needs to be implemented
|
153
155
|
# by subclasses.
|
154
156
|
# +_deptype+:: Type of the requested dependencies (could be Units, BhvUnits, Packages and so on)
|
@@ -170,19 +172,9 @@ module Fhlow
|
|
170
172
|
# +_prefix+:: This prefix will be added to the output of ths function.
|
171
173
|
# +_depth+:: The depth of the recursion.
|
172
174
|
# +_caller+:: The reference to the caller.
|
173
|
-
# == TODO
|
174
|
-
# in die konkreten leafs auslagern
|
175
175
|
def printMe(_prefix=" ", _depth=0, _caller=nil)
|
176
|
-
|
177
|
-
|
178
|
-
str = ""
|
179
|
-
@pen.puts _prefix, @pen.magenta, @prefix, @name, @pen.clear,
|
180
|
-
@architectures[_depth==0 ? self : _caller].nil? ?
|
181
|
-
"\n" :
|
182
|
-
"( "+(@architectures[_depth==0 ? self : _caller].each { |key, value| str += "#{@pen.blue}#{key}#{@pen.clear} -> #{value.join(", ")}; " }; str+=")")
|
183
|
-
else
|
184
|
-
@pen.print _prefix, @pen.yellow, @prefix, @name, @pen.clear, "\n"
|
185
|
-
end
|
176
|
+
|
177
|
+
self.print(_prefix, _depth, _caller)
|
186
178
|
|
187
179
|
@dependencies.each do |deptype, leafs|
|
188
180
|
leafs.each { |leaf| leaf.printMe(_prefix+" ", _depth+1, self) }
|
@@ -191,7 +183,19 @@ module Fhlow
|
|
191
183
|
@pen.print "\n" if _depth == 0
|
192
184
|
|
193
185
|
end
|
194
|
-
|
186
|
+
|
187
|
+
def getTarget(_itemname)
|
188
|
+
if _itemname == "Name"
|
189
|
+
"Target#{@conf["Target"]["Target"]}"
|
190
|
+
else
|
191
|
+
@conf["Target#{@conf["Target"]["Target"]}"][_itemname]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
private
|
196
|
+
def print(_prefix=" ", _depth=0, _caller=nil)
|
197
|
+
raise FhlowException.new(self.class), "print() is not implemented for "+self.class.to_s
|
198
|
+
end
|
195
199
|
end
|
196
200
|
|
197
201
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'leaf'
|
2
|
+
require 'leaffactory'
|
3
|
+
|
4
|
+
module Fhlow
|
5
|
+
|
6
|
+
# This is a concrete implementation of the abstract class Leaf. A Library represents one Leaf
|
7
|
+
# with the prefix "lib".
|
8
|
+
class Library < Leaf
|
9
|
+
|
10
|
+
# Calls the constructor of Leaf.
|
11
|
+
# +_name+:: The Name of the Leaf.
|
12
|
+
# +_parent+:: The reference to the parent.
|
13
|
+
# +_conf+:: The configuration information from higher levels.
|
14
|
+
# +_log+:: The reference to the Log object.
|
15
|
+
# +_pen+:: The reference to a Pen object.
|
16
|
+
def initialize(_name, _parent, _log, _pen)
|
17
|
+
super("lib", _name, _parent, _log, _pen)
|
18
|
+
end
|
19
|
+
|
20
|
+
# This function returns an Array of filenames in respect of the dependency tree.
|
21
|
+
# +_deptype+:: Type of the requested dependencies (could be Units, BhvUnits, Librarys and so on)
|
22
|
+
# +_istoplevel+:: Is used to indicate the first entrance to this function.
|
23
|
+
# +_caller+:: Reference to the caller of the function. This is needed to request architectures.
|
24
|
+
# +_files+:: The Array of the files which will be filled with the requested filenames and returned in the end.
|
25
|
+
def getFiles(_deptype, _istoplevel=true, _caller=nil, _files=Array.new)
|
26
|
+
@dependencies[_deptype].each { |dep| dep.getFiles(_deptype, false, self, _files)} unless @dependencies[_deptype].nil?
|
27
|
+
|
28
|
+
# only act if Libraries are needed
|
29
|
+
case _deptype
|
30
|
+
when "SimulationLibraries", "Libraries"
|
31
|
+
_files.push( { @name => @conf["Self"]["Files"].collect { |file| getPath+"src/"+file } } )
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def print(_prefix=" ", _depth=0, _caller=nil)
|
36
|
+
# TODO: find a way to print only [Dependencies] -> Libraries without [Target*] -> SimulationLibraries
|
37
|
+
#@pen.print _prefix, @pen.yellow, @prefix, @name, @pen.clear, "\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
# This is a concrete implementation of the _abstract_ class LeafFactory .
|
43
|
+
# A LibraryFactory creates objects of Unit.
|
44
|
+
class LibraryFactory < LeafFactory
|
45
|
+
|
46
|
+
# Return the prefix used by Units.
|
47
|
+
def LibraryFactory.getPrefix()
|
48
|
+
return "lib"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Creates objects of Unit.
|
52
|
+
# +*_args+:: Array of argumens passed to the constructor of Unit. See Unit.initialize for more details.
|
53
|
+
def create(*_args)
|
54
|
+
return Library.new(*_args)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
@@ -23,7 +23,7 @@ module Fhlow
|
|
23
23
|
# +_caller+:: Reference to the caller of the function. This is needed to request architectures.
|
24
24
|
# +_files+:: The Array of the files which will be filled with the requested filenames and returned in the end.
|
25
25
|
def getFiles(_deptype, _istoplevel=true, _caller=nil, _files=Array.new)
|
26
|
-
@dependencies.
|
26
|
+
@dependencies[_deptype].each { |dep| dep.getFiles(_deptype, false, self, _files)} unless @dependencies[_deptype].nil?
|
27
27
|
|
28
28
|
# only act if Packages are needed
|
29
29
|
if _deptype == "Packages"
|
@@ -31,6 +31,9 @@ module Fhlow
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
+
def print(_prefix=" ", _depth=0, _caller=nil)
|
35
|
+
@pen.print _prefix, @pen.lightyellow, @prefix, @name, @pen.clear, "\n"
|
36
|
+
end
|
34
37
|
|
35
38
|
end
|
36
39
|
|
@@ -66,7 +66,7 @@ module Fhlow
|
|
66
66
|
# * file not found exception::
|
67
67
|
# * -e -ea -eac -ac handling::
|
68
68
|
def getFiles(_deptype, _istoplevel=true, _caller=nil, _files=Array.new)
|
69
|
-
@dependencies.
|
69
|
+
@dependencies[_deptype].each { |dep| dep.getFiles(_deptype, false, self, _files)} unless @dependencies[_deptype].nil?
|
70
70
|
|
71
71
|
# only act if the Unit is able to handle the _deptype
|
72
72
|
case _deptype
|
@@ -125,6 +125,14 @@ module Fhlow
|
|
125
125
|
@architectures[_owner][_deptype] = @architectures[_owner][_deptype].uniq
|
126
126
|
end
|
127
127
|
|
128
|
+
|
129
|
+
def print(_prefix=" ", _depth=0, _caller=nil)
|
130
|
+
str = ""
|
131
|
+
@pen.puts _prefix, @pen.magenta, @prefix, @name, @pen.clear,
|
132
|
+
@architectures[_depth==0 ? self : _caller].nil? ?
|
133
|
+
"\n" :
|
134
|
+
"( "+(@architectures[_depth==0 ? self : _caller].each { |key, value| str += "#{@pen.blue}#{key}#{@pen.clear} -> #{value.join(", ")}; " }; str+=")")
|
135
|
+
end
|
128
136
|
|
129
137
|
|
130
138
|
|
data/lib/module_fhlow/node.rb
CHANGED
@@ -50,7 +50,7 @@ module Fhlow
|
|
50
50
|
# +_nodelevel+:: The level of the Node inside the fhlow structure.
|
51
51
|
# +_log+:: Reference to a Log object.
|
52
52
|
# +_pen+:: Reference to a Pen obejct (output to console).
|
53
|
-
def initialize(_prefix, _name, _parent, _nodelevel, _log, _pen)
|
53
|
+
def initialize(_prefix, _name, _parent, _nodelevel, _log, _pen, _defaultconf=_parent.conf)
|
54
54
|
@prefix = _prefix
|
55
55
|
@name = _name
|
56
56
|
|
@@ -65,12 +65,12 @@ module Fhlow
|
|
65
65
|
@parent = _parent
|
66
66
|
@log = _log
|
67
67
|
@pen = _pen
|
68
|
-
|
68
|
+
|
69
69
|
if File.exist?(@parent.getPath+@prefix+@name+"/config.flw")
|
70
70
|
# read the config file
|
71
71
|
@conf = Config::Config.new(@parent.getPath+@prefix+@name+"/config.flw")
|
72
72
|
# inherit the configurations from previous levels
|
73
|
-
@conf.merge(
|
73
|
+
@conf.merge(_defaultconf)
|
74
74
|
@log.debug(@prefix+@name, "Sucessfully merged inherited configs from #{@parent.prefix+@parent.name}.")
|
75
75
|
else
|
76
76
|
@log.warning(self, "config.flw does not exists in #{@prefix}#{@name}.")
|
@@ -83,7 +83,6 @@ module Fhlow
|
|
83
83
|
|
84
84
|
@log.info(@prefix+@name, "initializing node...")
|
85
85
|
|
86
|
-
|
87
86
|
if @nodelevel < @conf["fhlow"]["NodePrefixes"].length
|
88
87
|
|
89
88
|
# add the nodes
|
@@ -181,7 +180,7 @@ module Fhlow
|
|
181
180
|
else
|
182
181
|
possibilities = Array.new
|
183
182
|
@leafs.each_key { |leafname| possibilities.push(leafname) if leafname =~ /.*#{_objectfootprint[0]}/ }
|
184
|
-
raise FhlowObjectNotFoundException.new(@prefix+@name), "There are multible possibilities for leaf #{_objectfootprint[0]}: "+
|
183
|
+
raise FhlowObjectNotFoundException.new(@prefix+@name), "There are multible possibilities for leaf #{_objectfootprint[0]}: "+possibilities.join(", ") if possibilities.length > 1
|
185
184
|
raise FhlowObjectNotFoundException.new(@prefix+@name), "No such node <"+(possibilities.empty? ? _objectfootprint[0].to_s : possibilities[0].to_s)+">!" unless @leafs[possibilities[0]]
|
186
185
|
return @leafs[possibilities[0]] # finally the object can be returned
|
187
186
|
end
|
data/lib/module_fhlow/plugin.rb
CHANGED
@@ -18,6 +18,9 @@ module Fhlow
|
|
18
18
|
@actualLeaf = _actualLeaf
|
19
19
|
@cmd = CmdParse::Command.new(self.class.to_s, true, true)
|
20
20
|
@cmd.pen = @pen
|
21
|
+
@target = "Target"+@actualLeaf.conf["Target"]["Target"]
|
22
|
+
@varDir = @actualLeaf.getPath+"var/#{self.class.to_s}/"
|
23
|
+
@shareDir = @actualLeaf.getPath+"var/share/"
|
21
24
|
end
|
22
25
|
|
23
26
|
# Describes the Plugins main command. The name of the main command
|
@@ -48,6 +51,14 @@ module Fhlow
|
|
48
51
|
@cmd.add_command(subcmd)
|
49
52
|
end
|
50
53
|
|
54
|
+
def runInVarDir(&_block)
|
55
|
+
Dir.chdir(@varDir, &_block)
|
56
|
+
end
|
57
|
+
|
58
|
+
def runInShareDir(&_block)
|
59
|
+
Dir.chdir(@shareDir, &_block)
|
60
|
+
end
|
61
|
+
|
51
62
|
end
|
52
63
|
|
53
64
|
end
|
@@ -27,7 +27,7 @@ module Fhlow
|
|
27
27
|
|
28
28
|
# A Pluginpool is a container that loads, initializes and stores references to
|
29
29
|
# the loaded plugins.
|
30
|
-
class
|
30
|
+
class PluginPool
|
31
31
|
|
32
32
|
# Loads and initializes the loaded plugins.
|
33
33
|
# +_plugindir+:: The direcotry where the plugins can be found.
|
@@ -41,15 +41,14 @@ module Fhlow
|
|
41
41
|
@plugindir = _plugindir
|
42
42
|
@actualLeaf = _actualLeaf
|
43
43
|
|
44
|
-
|
45
|
-
Dir.glob(@plugindir+"*.rb").each do |plugin|
|
44
|
+
Dir.glob(@plugindir + "*.rb").each do |plugin|
|
46
45
|
|
47
46
|
pluginname = File.basename(plugin, ".rb").capitalize
|
48
|
-
|
47
|
+
|
49
48
|
require plugin
|
50
49
|
|
51
50
|
@pool.push(Kernel.const_get(pluginname).new(@actualLeaf, @pen, @log))
|
52
|
-
@log.info(self, "loaded plugin "+plugin)
|
51
|
+
@log.info(self.class, "loaded plugin "+plugin)
|
53
52
|
end
|
54
53
|
|
55
54
|
end
|
@@ -75,6 +74,19 @@ module Fhlow
|
|
75
74
|
@pool.each(&_block)
|
76
75
|
end
|
77
76
|
|
77
|
+
def PluginPool.each_configfile(_plugindir, &_block)
|
78
|
+
Dir.glob(_plugindir+"*.rb").each do |plugin|
|
79
|
+
|
80
|
+
pluginname = File.basename(plugin, ".rb").capitalize
|
81
|
+
|
82
|
+
if File.exist?(_plugindir+pluginname+".flw")
|
83
|
+
_block.call(_plugindir+pluginname+".flw")
|
84
|
+
else
|
85
|
+
raise Fhlow::FhlowException.new(pluginname), "Does not provide its default configuration file: "+ @plugindir + pluginname +".flw"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
78
90
|
end
|
79
91
|
|
80
92
|
end
|
@@ -37,17 +37,17 @@ module Fhlow
|
|
37
37
|
#
|
38
38
|
def initialize(_defaultconf, _log, _pen, _path=RootNode.detectFhlowRootDir)
|
39
39
|
|
40
|
+
@path = _path
|
41
|
+
|
40
42
|
# don't do anything if _path is nil
|
41
43
|
raise FhlowException.new(self.class), "Couldn't detect the fhlow root directory!" if _path.nil?
|
42
44
|
raise FhlowException.new(self.class), "You have to provide a default configuration object!" if !_defaultconf.instance_of?(Config::Config)
|
43
45
|
|
44
|
-
@path = _path
|
45
|
-
@conf = _defaultconf
|
46
46
|
|
47
47
|
# load all the leaf classes
|
48
48
|
LeafFactory.load(@path+"/flw/core/lib/module_fhlow/leafs/")
|
49
49
|
|
50
|
-
super("", "
|
50
|
+
super("", "", self, 0, _log, _pen, _defaultconf)
|
51
51
|
|
52
52
|
@nodes.each_value { |node| node.fetchDependencies() }
|
53
53
|
|
@@ -87,6 +87,7 @@ module Fhlow
|
|
87
87
|
# the string provided by 'Dir.pwd'.
|
88
88
|
# +_dir+:: The directory that will be used to find the fhlow root directory.
|
89
89
|
def RootNode.detectFhlowRootDir(_dir=Dir.pwd)
|
90
|
+
raise FhlowException.new(self.class), "Couldn't detect the fhlow root directory!" if _dir==""
|
90
91
|
if Dir.entries(_dir).include?("flw")
|
91
92
|
return _dir+"/"
|
92
93
|
else
|
@@ -0,0 +1,18 @@
|
|
1
|
+
[Modelsim]
|
2
|
+
# BinDir = /opt/eda/questasim/bin/
|
3
|
+
# LicenseFile = 7418@thor:8224@thor:27000@thor:1816@thor:7450@thor
|
4
|
+
BinDir =
|
5
|
+
LicenseFile =
|
6
|
+
|
7
|
+
CompileQuiet = false
|
8
|
+
CompileOptions = -93
|
9
|
+
CompileBuildAll = false
|
10
|
+
|
11
|
+
SimulateRun = 100 ns
|
12
|
+
SimulateConsole = false
|
13
|
+
SimulateOptions =
|
14
|
+
|
15
|
+
PostLayoutSimSDF = min
|
16
|
+
PostLayoutSimTbLabel = DUT
|
17
|
+
|
18
|
+
|
@@ -0,0 +1,331 @@
|
|
1
|
+
#----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Copyright (C) 2007 Simon Lasselsberger
|
4
|
+
# simon.lasselsberger@fh-hagenberg.at
|
5
|
+
#
|
6
|
+
# This file is part of the _fhlow_ scripting environment.
|
7
|
+
#
|
8
|
+
# The _fhlow_ scripting environment is free software; you can redistribute
|
9
|
+
# it and/or modify it under the terms of the GNU General Public License
|
10
|
+
# as published by the Free Software Foundation; either version 2 of the
|
11
|
+
# License, or (at your option) any later version.
|
12
|
+
#
|
13
|
+
# _fhlow_ is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with _fhlow_; if not, write to the Free Software
|
20
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
21
|
+
#
|
22
|
+
#----------------------------------------------------------------------------
|
23
|
+
|
24
|
+
require 'plugin'
|
25
|
+
require 'fileutils'
|
26
|
+
require 'fhlowexception'
|
27
|
+
|
28
|
+
class Modelsim < Fhlow::Plugin
|
29
|
+
|
30
|
+
def initialize(_actualLeaf, _pen, _log)
|
31
|
+
super(_actualLeaf, _pen, _log)
|
32
|
+
|
33
|
+
@vcom_options = []
|
34
|
+
@vsim_options = []
|
35
|
+
|
36
|
+
# default settings
|
37
|
+
@vcom_options = @actualLeaf.conf["Modelsim"]["CompileOptions"].split(/\s/)
|
38
|
+
if @actualLeaf.conf["Modelsim"]["CompileQuiet"] == true
|
39
|
+
@vcom_options.push("-quiet") unless @vcom_options.include?("-quiet")
|
40
|
+
end
|
41
|
+
|
42
|
+
@vsim_simtime = @actualLeaf.conf["Modelsim"]["SimulateRun"]
|
43
|
+
@vsim_options.push(@actualLeaf.conf["Modelsim"]["SimulateOptions"])
|
44
|
+
@vsim_options.push("-c") if @actualLeaf.conf["Modelsim"]["SimulateConsole"]=="true"
|
45
|
+
@buildall = @actualLeaf.conf["Modelsim"]["CompileBuildAll"] == "true"
|
46
|
+
|
47
|
+
@vsim_sdf = @actualLeaf.conf["Modelsim"]["PostLayoutSimSDF"]
|
48
|
+
@vsim_tblabel = @actualLeaf.conf["Modelsim"]["PostLayoutSimTbLabel"]
|
49
|
+
|
50
|
+
# this functioncall is optional
|
51
|
+
describeCmd("Plugin vor Modelsim.",
|
52
|
+
"Supported versions: Modelsim 6.1 b")
|
53
|
+
|
54
|
+
|
55
|
+
# --- compile ---
|
56
|
+
# create an options object
|
57
|
+
compileoptions = CmdParse::OptionParserWrapper.new do |opt|
|
58
|
+
opt.separator "<compile-options>:"
|
59
|
+
opt.on("-q", "--quiet", "Make vcom quiet.") { @vcom_options.push("-quiet") unless @vcom_options.include?("-quiet") }
|
60
|
+
opt.on("-o", "--options VAL", "Options that will be passed to vcom") { |val| @vcom_options.push(val) }
|
61
|
+
opt.on("-b", "--buildall", "Rebuilds all sources and libraries.") { @buildall = true }
|
62
|
+
end
|
63
|
+
|
64
|
+
# register the subcommand
|
65
|
+
registerSubCmd(
|
66
|
+
"compile", # name of the subcmd
|
67
|
+
"Compiles the configured sources.", # short description (optional)
|
68
|
+
"Compiles the configured sources.", # description (optional)
|
69
|
+
compileoptions # the option object (optional)
|
70
|
+
) { compile() } # the action which should be run when this subcmd is invoked
|
71
|
+
|
72
|
+
# --- simulate ---
|
73
|
+
# create an options object
|
74
|
+
simulationoptions = CmdParse::OptionParserWrapper.new do |opt|
|
75
|
+
opt.separator "<simlation-options>:"
|
76
|
+
opt.on("-r", "--run TIME", "Simulation time. Format: \"<value> [ms|us|ns|ps]\"") do |time|
|
77
|
+
if time =~ /\d+[ ](ms|us|ns|ps)/
|
78
|
+
@vsim_simtime = time
|
79
|
+
else
|
80
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "Simulation time has wrong format: #{time}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
opt.on("-c", "--console", "Run simulation in console. Do not start GUI.") { @vsim_options.push("-c") }
|
84
|
+
opt.on("-o", "--options VAL", "Options that will be passed to vsim.") { |val| @vsim_options.push(val) }
|
85
|
+
opt.on("-q", "--quiet", "Make vcom quiet.") { @vcom_options.push("-quiet") unless @vcom_options.include?("-quiet") }
|
86
|
+
opt.on("-b", "--buildall", "Rebuilds all sources and libraries.") { @buildall = true }
|
87
|
+
end
|
88
|
+
|
89
|
+
# register the subcommand
|
90
|
+
registerSubCmd(
|
91
|
+
"simulate", # name of the subcmd
|
92
|
+
"Simulates the design.", # short description (optional)
|
93
|
+
"Simulates the design.", # description (optional)
|
94
|
+
simulationoptions # the option object (optional)
|
95
|
+
) { simulate() } # the action which should be run when this subcmd is invoked
|
96
|
+
|
97
|
+
# --- post layout simulation ---
|
98
|
+
# create an options object
|
99
|
+
plsimoptions = CmdParse::OptionParserWrapper.new do |opt|
|
100
|
+
opt.separator "<plsim-options>:"
|
101
|
+
opt.on("-r", "--run TIME", "Simulation time. Format: \"<value> [ms|us|ns|ps]\"") do |time|
|
102
|
+
if time =~ /\d+[ ](ms|us|ns|ps)/
|
103
|
+
@vsim_simtime = time
|
104
|
+
else
|
105
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "Simulation time has wrong format: #{time}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
opt.on("-c", "--console", "Run simulation in console. Do not start GUI.") { @vsim_options.push("-c") }
|
109
|
+
opt.on("-o", "--options VAL", "Options that will be passed to vsim.") { |val| @vsim_options.push(val) }
|
110
|
+
opt.on("-b", "--buildall", "Rebuilds all sources and libraries.") { @buildall = true }
|
111
|
+
end
|
112
|
+
|
113
|
+
# register the subcommand
|
114
|
+
registerSubCmd(
|
115
|
+
"plsim", # name of the subcmd
|
116
|
+
"Runs post layout simulation of the synthesized design.", # short description (optional)
|
117
|
+
"Runs post layout simulation of the synthesized design.", # description (optional)
|
118
|
+
plsimoptions # the option object (optional)
|
119
|
+
) { plsim() } # the action which should be run when this subcmd is invoked
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
def compile()
|
128
|
+
initWork()
|
129
|
+
|
130
|
+
@pen.puts
|
131
|
+
@actualLeaf.printMe
|
132
|
+
width = 87
|
133
|
+
|
134
|
+
@pen.seperator
|
135
|
+
|
136
|
+
begin
|
137
|
+
@pen.print ",", "-"*width,"+\n"
|
138
|
+
@pen.print "|", " Compilation".ljust(width), "|\n"
|
139
|
+
@pen.print "+", "-"*width,"+\n"
|
140
|
+
|
141
|
+
unless @actualLeaf.getFiles("Libraries").empty?
|
142
|
+
@pen.puts "| Libraries:"
|
143
|
+
@actualLeaf.getFiles("Libraries").each do |libhash|
|
144
|
+
libhash.each do |libname, files|
|
145
|
+
if @buildall or !File.directory?(@varDir+libname)
|
146
|
+
@pen.puts "| Library: #{libname}"
|
147
|
+
runInVarDir { `#{@actualLeaf.conf["Modelsim"]["BinDir"]}vlib #{@varDir}#{libname}` }
|
148
|
+
runInVarDir { `#{@actualLeaf.conf["Modelsim"]["BinDir"]}vmap #{libname} #{@varDir}#{libname}` }
|
149
|
+
|
150
|
+
files.each do |f|
|
151
|
+
msg = callVcom(f)
|
152
|
+
printFile(f, $? == 0, @pen.yellow)
|
153
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors while compiling #{f}!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
154
|
+
end
|
155
|
+
else
|
156
|
+
@pen.puts "| Library: #{libname} exists, skipping (use --buildall to rebuild)"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
@pen.print "+", "-"*width,"+\n"
|
161
|
+
end
|
162
|
+
|
163
|
+
@pen.puts "| Packages:"
|
164
|
+
@actualLeaf.getFiles("Packages").each do |f|
|
165
|
+
msg = callVcom(f)
|
166
|
+
printFile(f, $? == 0, @pen.lightyellow)
|
167
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors while compiling #{f}!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
@pen.print "+", "-"*width,"+\n"
|
172
|
+
@pen.puts "| Units:"
|
173
|
+
@actualLeaf.getFiles("Units").each do |f|
|
174
|
+
msg = callVcom(f)
|
175
|
+
printFile(f, $? == 0, @pen.magenta)
|
176
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors while compiling #{f}!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
177
|
+
end
|
178
|
+
|
179
|
+
@pen.print "+", "-"*width,"+\n"
|
180
|
+
@pen.puts "| BhvUnits:"
|
181
|
+
@actualLeaf.getFiles("BhvUnits").each do |f|
|
182
|
+
msg = callVcom(f)
|
183
|
+
printFile(f, $? == 0, @pen.magenta)
|
184
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors while compiling #{f}!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
185
|
+
end
|
186
|
+
|
187
|
+
@pen.print "+", "-"*width,"+\n"
|
188
|
+
@pen.puts "| tbUnits:"
|
189
|
+
@actualLeaf.getFiles("tbUnits").each do |f|
|
190
|
+
msg = callVcom(f)
|
191
|
+
printFile(f, $? == 0, @pen.magenta)
|
192
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors while compiling #{f}!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
193
|
+
end
|
194
|
+
|
195
|
+
ensure
|
196
|
+
@pen.print "`", "-"*width,"+\n"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
|
202
|
+
|
203
|
+
def simulate()
|
204
|
+
compile
|
205
|
+
@pen.seperator
|
206
|
+
ENV["LM_LICENSE_FILE"] = @actualLeaf.conf["Modelsim"]["LicenseFile"]
|
207
|
+
@log.debug("Modelsim", "Setting environment variable LM_LICENSE_FILE to #{@actualLeaf.conf["Modelsim"]["LicenseFile"]}")
|
208
|
+
@pen.puts "Running Modelsim:"
|
209
|
+
instruction = "#{@actualLeaf.conf["Modelsim"]["BinDir"]}vsim work.tb#{@actualLeaf.name} "
|
210
|
+
instruction += "#{@vsim_options.join(" ")} "
|
211
|
+
instruction += "-do \"source #{@actualLeaf.getPath}src/wave.do; run #{@vsim_simtime}; #{ @vsim_options.include?("-c") ? 'exit' : ''}\" "
|
212
|
+
instruction += "2>&1"
|
213
|
+
msg = ""; runInVarDir { msg = `#{instruction}` }
|
214
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors during simulation!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
215
|
+
@pen.puts msg
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
def plsim()
|
220
|
+
width = 87
|
221
|
+
@pen.print ",", "-"*width,"+\n"
|
222
|
+
@pen.print "|", " Compilation".ljust(width), "|\n"
|
223
|
+
@pen.print "+", "-"*width,"+\n"
|
224
|
+
|
225
|
+
begin
|
226
|
+
@pen.puts "| SimulationLibraries of #{@actualLeaf.getTarget("Name")}:"
|
227
|
+
@actualLeaf.getFiles("SimulationLibraries").each do |libhash|
|
228
|
+
libhash.each do |libname, files|
|
229
|
+
if @buildall or !File.directory?(@varDir+libname)
|
230
|
+
@pen.puts "| Library: #{libname}"
|
231
|
+
runInVarDir { `#{@actualLeaf.conf["Modelsim"]["BinDir"]}vlib #{@varDir}#{libname}` }
|
232
|
+
runInVarDir { `#{@actualLeaf.conf["Modelsim"]["BinDir"]}vmap #{libname} #{@varDir}#{libname}` }
|
233
|
+
|
234
|
+
files.each do |f|
|
235
|
+
msg = callVcom(f, libname)
|
236
|
+
printFile(f, $? == 0, @pen.yellow)
|
237
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors while compiling #{f}!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
238
|
+
end
|
239
|
+
else
|
240
|
+
@pen.puts "| Library: #{libname} exists, skipping (use --buildall to rebuild)"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
@pen.print "+", "-"*width,"+\n"
|
246
|
+
|
247
|
+
@pen.puts "| Netlist:"
|
248
|
+
f = @shareDir+"net#{@actualLeaf.name}-#{@actualLeaf.getArchitectures(@actualLeaf)["Units"][0]}-ea.vhd"
|
249
|
+
msg = callVcom(f)
|
250
|
+
printFile(f, $? == 0, @pen.magenta)
|
251
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors while compiling #{f}!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
252
|
+
|
253
|
+
@pen.print "+", "-"*width,"+\n"
|
254
|
+
@pen.puts "| Packages:"
|
255
|
+
@actualLeaf.getFiles("Packages").each do |f|
|
256
|
+
msg = callVcom(f)
|
257
|
+
printFile(f, $? == 0, @pen.yellow)
|
258
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors while compiling #{f}!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
@pen.print "+", "-"*width,"+\n"
|
263
|
+
@pen.puts "| BhvUnits:"
|
264
|
+
@actualLeaf.getFiles("BhvUnits").each do |f|
|
265
|
+
msg = callVcom(f)
|
266
|
+
printFile(f, $? == 0, @pen.magenta)
|
267
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors while compiling #{f}!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
268
|
+
end
|
269
|
+
|
270
|
+
@pen.print "+", "-"*width,"+\n"
|
271
|
+
@pen.puts "| tbUnits:"
|
272
|
+
@actualLeaf.getFiles("tbUnits").each do |f|
|
273
|
+
msg = callVcom(f)
|
274
|
+
printFile(f, $? == 0, @pen.magenta)
|
275
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors while compiling #{f}!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
ensure
|
280
|
+
@pen.print "`", "-"*width,"+\n"
|
281
|
+
end
|
282
|
+
|
283
|
+
@pen.seperator
|
284
|
+
@pen.puts "Running post layout simulation with Modelsim:"
|
285
|
+
|
286
|
+
ENV["LM_LICENSE_FILE"] = @actualLeaf.conf["Modelsim"]["LicenseFile"]
|
287
|
+
@log.debug("Modelsim", "Setting environment variable LM_LICENSE_FILE to #{@actualLeaf.conf["Modelsim"]["LicenseFile"]}")
|
288
|
+
|
289
|
+
instruction = "#{@actualLeaf.conf["Modelsim"]["BinDir"]}vsim work.tb#{@actualLeaf.name} "
|
290
|
+
instruction += "#{@vsim_options.join(" ")} "
|
291
|
+
instruction += "-do \"source #{@actualLeaf.getPath}src/wave.do; run #{@vsim_simtime}; #{ @vsim_options.include?("-c") ? 'exit' : ''}\" "
|
292
|
+
instruction += "-sdfmax /DUT=#{@shareDir}/#{@actualLeaf.name}.sdf -noglitch -t ps "
|
293
|
+
instruction += "2>&1"
|
294
|
+
|
295
|
+
msg = ""; runInVarDir { msg = `#{instruction}` }
|
296
|
+
raise Fhlow::FhlowPluginException.new("Modelsim"), "There were some errors during simulation!\n Message from Modelsim:\n-----\n#{msg}\n-----" if $? != 0
|
297
|
+
|
298
|
+
@pen.print msg
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
|
303
|
+
|
304
|
+
# --- some private helper functions ---
|
305
|
+
private
|
306
|
+
def printFile(_file, _ok, _color, _width=90)
|
307
|
+
if _ok == true or _ok == false
|
308
|
+
@pen.puts "| [ ", _ok ? @pen.lightgreen+"ok "+@pen.clear : @pen.lightred+"failed "+@pen.clear, " ] ", _color, _file, @pen.clear
|
309
|
+
else
|
310
|
+
@pen.puts "| [ ", _ok, " ] ", _color, _file, @pen.clear
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
|
315
|
+
def initWork(_dir=@varDir)
|
316
|
+
FileUtils.rm_r(_dir+"work") if File.directory?(_dir+"work")
|
317
|
+
FileUtils.makedirs(_dir)
|
318
|
+
runInVarDir { `#{@actualLeaf.conf["Modelsim"]["BinDir"]}vlib #{_dir}work` }
|
319
|
+
runInVarDir { `#{@actualLeaf.conf["Modelsim"]["BinDir"]}vmap work #{_dir}work` }
|
320
|
+
end
|
321
|
+
|
322
|
+
|
323
|
+
def callVcom(_file, _lib="work")
|
324
|
+
instruction = "#{@actualLeaf.conf["Modelsim"]["BinDir"]}vcom #{@vcom_options.join(" ")} -work #{@varDir}#{_lib} #{_file} "
|
325
|
+
instruction += "2>&1"
|
326
|
+
@log.debug("Modelsim", "Running vcom: #{instruction}")
|
327
|
+
runInVarDir { `#{instruction}` }
|
328
|
+
end
|
329
|
+
|
330
|
+
|
331
|
+
end
|