blifutils 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,251 @@
1
+ ##
2
+ # Copyright (C) 2017 Théotime bollengier <theotime.bollengier@gmail.com>
3
+ #
4
+ # This file is part of Blifutils.
5
+ #
6
+ # Blifutils is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Blifutils is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Blifutils. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+
20
+ require 'rltk/parser'
21
+ require 'blifutils/lexer'
22
+ require 'blifutils/ast'
23
+
24
+
25
+ module BlifUtils
26
+
27
+ module BlifUtils::Language
28
+
29
+ class Parser < RLTK::Parser
30
+
31
+ production(:toplevel, 'model_list') do |arr|
32
+ BlifUtils::AST::TranslationUnit.new(arr)
33
+ end
34
+
35
+ list(:model_list, [:model, :file_reference])
36
+
37
+ nonempty_list(:identifier_list, :IDENTIFIER)
38
+
39
+ production(:model, 'MODEL .IDENTIFIER .model_header .commands END') do |name, header, commands|
40
+ BlifUtils::AST::Model.new(name, header, commands)
41
+ end
42
+
43
+ list(:model_header, :model_header_element)
44
+
45
+ production(:model_header_element) do
46
+ clause('INPUTS .identifier_list') do |arr|
47
+ BlifUtils::AST::ModelHeaderElementInputs.new(arr)
48
+ end
49
+ clause('OUTPUTS .identifier_list') do |arr|
50
+ BlifUtils::AST::ModelHeaderElementOutputs.new(arr)
51
+ end
52
+ clause('CLOCK .identifier_list') do |arr|
53
+ BlifUtils::AST::ModelHeaderElementClock.new(arr)
54
+ end
55
+ end
56
+
57
+ list(:commands, :command)
58
+
59
+ production(:command) do
60
+ clause('NAMES .identifier_list .cover_list') do |idl, cl|
61
+ icl = cl.collect do |s|
62
+ broken = s.split(/\s+/)
63
+ if broken.length == 1 then
64
+ [[], s.to_i]
65
+ else
66
+ [broken.first.split('').collect{|char|
67
+ case char
68
+ when '0' then 0
69
+ when '1' then 1
70
+ else 2
71
+ end
72
+ }, broken.last.to_i]
73
+ end
74
+ end
75
+ BlifUtils::AST::LogicGate.new(idl, icl)
76
+ end
77
+ clause('LATCH .generic_latch') { |gl| gl }
78
+ clause('SUBCKT .IDENTIFIER .formal_actual_list') do |name, fal|
79
+ BlifUtils::AST::ModelReference.new(name, fal)
80
+ end
81
+ clause('SEARCH .IDENTIFIER') { |fn| BlifUtils::AST::SubfileReference.new(fn) }
82
+ clause('BLACKBOX') { |_| BlifUtils::AST::BlackBox.new }
83
+ end
84
+
85
+ production(:generic_latch) do
86
+ clause('IDENTIFIER IDENTIFIER LATCHTYPE IDENTIFIER LATCHINITVAL') do |input, output, type, control, init|
87
+ BlifUtils::AST::GenericLatch.new(input, output, ctrlType: type, ctrlSig: ((control =~ /^NIL$/) ? nil : control), initValue: init)
88
+ end
89
+ clause('IDENTIFIER IDENTIFIER LATCHTYPE IDENTIFIER') do |input, output, type, control|
90
+ BlifUtils::AST::GenericLatch.new(input, output, ctrlType: type, ctrlSig: ((control =~ /^NIL$/) ? nil : control))
91
+ end
92
+ clause('IDENTIFIER IDENTIFIER LATCHINITVAL') do |input, output, init|
93
+ BlifUtils::AST::GenericLatch.new(input, output, initValue: init)
94
+ end
95
+ clause('IDENTIFIER IDENTIFIER') do |input, output|
96
+ BlifUtils::AST::GenericLatch.new(input, output)
97
+ end
98
+ end
99
+
100
+ list(:cover_list, :COVER)
101
+
102
+ nonempty_list(:formal_actual_list, :formal_actual)
103
+
104
+ production(:formal_actual, '.IDENTIFIER EQUAL .IDENTIFIER') { |formal, actual| [formal, actual] }
105
+
106
+ production(:file_reference, 'SEARCH .IDENTIFIER') { |fn| BlifUtils::AST::SubfileReference.new(fn) }
107
+ finalize()
108
+
109
+ end # BlifUtils::Language::Parser
110
+
111
+ end # BlifUtils::Language
112
+
113
+
114
+ class Parser
115
+
116
+ def self.parse (fileName, quiet: false)
117
+ processedFileNames = []
118
+ ast = self.parse_recursive(File.expand_path(fileName), processedFileNames, quiet)
119
+ return ast
120
+ end
121
+
122
+
123
+ def self.parse_string (str, quiet: false)
124
+ lexems = BlifUtils::Language::Lexer::lex(str)
125
+
126
+ begin
127
+ ast = BlifUtils::Language::Parser::parse(lexems)
128
+ rescue RLTK::NotInLanguage => e
129
+ print_parse_error(e.current, 'String not in grammar.')
130
+ rescue RLTK::BadToken => e
131
+ print_parse_error(e.faultyToken, "Unexpected token: \"#{e.faultyToken.type.to_s}\". Token not present in grammar definition.")
132
+ end
133
+
134
+ # Delete file references from the AST
135
+ ast.modelList.delete_if do |elem|
136
+ if elem.kind_of?(BlifUtils::AST::SubfileReference) then
137
+ STDERR.puts "WARNING: Ignoring \".search #{elem.fileName}\"" unless quiet
138
+ true
139
+ else
140
+ false
141
+ end
142
+ end
143
+
144
+ ast.modelList.each do |model|
145
+ model.commands.delete_if do |com|
146
+ if com.kind_of?(BlifUtils::AST::SubfileReference) then
147
+ STDERR.puts "WARNING: Ignoring \".search #{com.fileName}\"" unless quiet
148
+ true
149
+ else
150
+ false
151
+ end
152
+ end
153
+ end
154
+
155
+ return ast
156
+ end
157
+
158
+
159
+ private
160
+
161
+
162
+ def self.print_parse_error (token, errorString)
163
+ unless token.position.nil? then
164
+ fileName = token.position.file_name
165
+ line = token.position.line_number
166
+ column = token.position.line_offset
167
+
168
+ STDERR.puts "ERROR: Parse error at line #{line}, column #{column+1}, from file \"#{fileName}\":\n#{errorString}"
169
+ str = File.read(fileName).lines.to_a[line-1].gsub(/\t/,' ')
170
+ STDERR.puts (line.to_s + ': ') + str
171
+ abort ' '*(line.to_s.length + 2) + ('~'*column + '^')
172
+ else
173
+ STDERR.puts "Parse error:"
174
+ abort errorString
175
+ end
176
+ end
177
+
178
+
179
+ def self.parse_file (fileName, quiet = false)
180
+ puts "Parsing file \"#{fileName}\"..." unless quiet
181
+ lexems = BlifUtils::Language::Lexer::lex_file(fileName)
182
+
183
+ begin
184
+ ast = BlifUtils::Language::Parser::parse(lexems)
185
+ rescue RLTK::NotInLanguage => e
186
+ print_parse_error(e.current, 'String not in grammar.')
187
+ rescue RLTK::BadToken => e
188
+ print_parse_error(e.faultyToken, "Unexpected token: \"#{e.faultyToken.type.to_s}\". Token not present in grammar definition.")
189
+ end
190
+
191
+ return ast
192
+ end
193
+
194
+
195
+ def self.parse_recursive (fileName, processedFileNames, quiet = false)
196
+ return BlifUtils::AST::TranslationUnit.new if processedFileNames.include?(fileName)
197
+ processedFileNames << fileName
198
+
199
+ # Parse the file
200
+ ast = self.parse_file(fileName, quiet)
201
+
202
+ # Gather new file to parse
203
+ newFileToParseList = []
204
+ ast.modelList.each do |element|
205
+ if element.kind_of?(BlifUtils::AST::SubfileReference) then # file reference outside a model
206
+ newFileToParseList << element.fileName
207
+ else # it is a Model
208
+ element.commands.select{|elm| elm.kind_of?(BlifUtils::AST::SubfileReference)}.each do |com|
209
+ newFileToParseList << com.fileName
210
+ end
211
+ end
212
+ end
213
+
214
+ # Delete file references from the AST
215
+ ast.modelList.delete_if{|elem| elem.kind_of?(BlifUtils::AST::SubfileReference)}
216
+ ast.modelList.each do |model|
217
+ model.commands.delete_if{|com| com.kind_of?(BlifUtils::AST::SubfileReference)}
218
+ end
219
+
220
+ # Get absolute path of new file to parse
221
+ dirname = File.dirname(fileName)
222
+ newFileToParseList.collect!{|fn| File.expand_path(fn, dirname)}
223
+
224
+ # Parse new files
225
+ newFileToParseList.each do |newFileName|
226
+ newAst = self.parse_recursive(newFileName, processedFileNames, quiet)
227
+ newAst.modelList.each do |newModel|
228
+ if ast.modelList.collect{|model| model.name}.include?(newModel.name) then
229
+ abort "ERROR: Model \"#{newModel.name}\" is redefined"
230
+ end
231
+ ast.modelList << newModel
232
+ end
233
+ end
234
+
235
+ return ast
236
+ end
237
+
238
+ end # BlifUtils::Parser
239
+
240
+ end # BlifUtils
241
+
242
+
243
+
244
+
245
+ if __FILE__ == $0 then
246
+
247
+ abort "Usage: #{__FILE__} <file_to_parse>" unless ARGV.length == 1
248
+
249
+ puts BlifUtils::Parser::parse(ARGV[0]).pretty_print
250
+ end
251
+
@@ -0,0 +1,342 @@
1
+ ##
2
+ # Copyright (C) 2017 Théotime bollengier <theotime.bollengier@gmail.com>
3
+ #
4
+ # This file is part of Blifutils.
5
+ #
6
+ # Blifutils is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Blifutils is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with Blifutils. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+
20
+ require 'blifutils/netlist'
21
+ require 'blifutils/layering'
22
+
23
+
24
+ module BlifUtils
25
+
26
+ class Netlist
27
+
28
+ class LogicGate
29
+
30
+ def get_simulation_table
31
+ table = get_LookUpTable()
32
+ tableLength = table.length
33
+
34
+ uint32table = []
35
+ pos = 0
36
+ begin
37
+ tableCont = 0
38
+ (0 ... 32).each do |j|
39
+ tagada = pos + j
40
+ break if tagada >= tableLength
41
+ if table[tagada] == 1 then
42
+ tableCont |= (1 << j)
43
+ end
44
+ end
45
+ pos += 32
46
+ uint32table << tableCont
47
+ end while pos < tableLength
48
+
49
+ return uint32table.collect{|num| num.to_s}.join(', ')
50
+ end
51
+
52
+ end # BlifUtils::Netlist::LogicGate
53
+
54
+
55
+ def create_simulation_file_for_model (modelName = nil, quiet: false)
56
+ modelName = first_model.name if modelName.nil?
57
+ dedel = get_model_by_name(modelName)
58
+ if dedel.nil?
59
+ abort "ERROR: Model \"#{modelName}\" not found."
60
+ end
61
+ if dedel.is_self_contained? then
62
+ model = dedel
63
+ else
64
+ model = flatten(modelName, false, quiet: quiet)
65
+ end
66
+
67
+ className = (model.name + '_simulation_class').gsub('_',' ').split.collect{|word| word.capitalize}.join
68
+ gateArray = model.simulation_components_to_schedule_stack(withOutputGraphviz: false, quiet: quiet) # This array does not contain constants
69
+ latchArray = model.components.select{|comp| comp.isLatch?}
70
+ nbGates = gateArray.length
71
+ nbLatches = latchArray.length
72
+ nbNets = model.nets.length
73
+
74
+ # Find inputs #
75
+ simInputs = {} # {name -> [[net, index], ... ], ... }
76
+ model.inputs.each do |iIO|
77
+ iname = iIO.name
78
+ match = iname.match(/(.*?)((\[(\d+)\])|(_(\d+)_))/)
79
+ if match.nil? then
80
+ simInputs[iname] = [] if simInputs[iname].nil?
81
+ simInputs[iname] << [iIO.net, 0]
82
+ else
83
+ unless match[4].nil? then
84
+ indNum = match[4].to_i
85
+ end
86
+ unless match[6].nil? then
87
+ indNum = match[6].to_i
88
+ end
89
+ simInputs[match[1]] = [] if simInputs[match[1]].nil?
90
+ simInputs[match[1]] << [iIO.net, indNum]
91
+ end
92
+ end
93
+ simVectorInputs = [] # [[name, [net0, net1, ... ]], ... ]
94
+ simInputs.each do |vectName, net_index_array|
95
+ net_index_array.sort!{|net_indexA, net_indexB| net_indexA[1] <=> net_indexB[1]}
96
+ simVectorInputs << [vectName, net_index_array.collect{|net_index| net_index[0]}]
97
+ end
98
+
99
+ # Find outputs #
100
+ simOutputs = {} # {name -> [[net, index], ... ], ... }
101
+ model.outputs.each do |iIO|
102
+ oname = iIO.name
103
+ match = oname.match(/(.*?)((\[(\d+)\])|(_(\d+)_))/)
104
+ if match.nil? then
105
+ simOutputs[oname] = [] if simOutputs[oname].nil?
106
+ simOutputs[oname] << [iIO.net, 0]
107
+ else
108
+ unless match[4].nil? then
109
+ indNum = match[4].to_i
110
+ end
111
+ unless match[6].nil? then
112
+ indNum = match[6].to_i
113
+ end
114
+ simOutputs[match[1]] = [] if simOutputs[match[1]].nil?
115
+ simOutputs[match[1]] << [iIO.net, indNum]
116
+ end
117
+ end
118
+ simVectorOutputs = [] # [[name, [net0, net1, ... ]], ... ]
119
+ simOutputs.each do |vectName, net_index_array|
120
+ net_index_array.sort!{|net_indexA, net_indexB| net_indexA[1] <=> net_indexB[1]}
121
+ simVectorOutputs << [vectName, net_index_array.collect{|net_index| net_index[0]}]
122
+ end
123
+
124
+
125
+ str = "/#{'*'*78}/\n\n\n"
126
+
127
+ str += "class #{className} : public Model\n{\n"
128
+ str += "\tprivate:\n\n"
129
+ str += "\t\tstatic const unsigned int nbNets = #{nbNets};\n"
130
+ str += "\t\tstatic const unsigned int nbLatches = #{nbLatches};\n"
131
+ str += "\t\tstatic const unsigned int nbGates = #{nbGates};\n\n"
132
+ str += "\t\tNet *nets[nbNets];\n"
133
+ str += "\t\tLatch *latches[nbLatches];\n"
134
+ str += "\t\tGate *gates[nbGates];\n\n"
135
+ str += "\t\tbool gateChanged[nbGates];\n\n"
136
+ str += "\tpublic:\n\n"
137
+ str += "\t\t#{className}();\n"
138
+ str += "\t\t~#{className}();\n\n"
139
+ simInputs.each do |key, val|
140
+ val.each do |net_index|
141
+ ind = model.nets.index(net_index[0])
142
+ next if ind.nil?
143
+ str += "\t\tNet *INPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end};\n"
144
+ end
145
+ end
146
+ str += "\n"
147
+ simOutputs.each do |key, val|
148
+ val.each do |net_index|
149
+ str += "\t\tNet *OUTPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end};\n"
150
+ end
151
+ end
152
+ unless simVectorInputs.empty? then
153
+ str += "\n"
154
+ simVectorInputs.each do |simVectInput|
155
+ next if simVectInput[1].collect{|net| model.nets.index(net)}.include?(nil)
156
+ str += "\t\tBitVector *INPUT_VECTOR_#{simVectInput[0]};\n"
157
+ end
158
+ end
159
+ unless simVectorOutputs.empty? then
160
+ str += "\n"
161
+ simVectorOutputs.each do |simVectOutput|
162
+ str += "\t\tBitVector *OUTPUT_VECTOR_#{simVectOutput[0]};\n"
163
+ end
164
+ end
165
+ str += "\n\tprivate:\n\n\t\tvoid setConstants();\n"
166
+ str += "};\n\n"
167
+
168
+ str += "#{className}::#{className}() :\n"
169
+ str += "\tModel(nbNets, nbLatches, nbGates)\n"
170
+ str += "{\n"
171
+ model.nets.each_with_index do |net, i|
172
+ fanouts = []
173
+ net.fanouts.each do |fanout|
174
+ index = gateArray.index(fanout.target)
175
+ fanouts << index unless index.nil?
176
+ end
177
+ if fanouts.empty? then
178
+ str += "\tnets[#{i}] = new Net(NULL, 0, gateChanged);\n"
179
+ else
180
+ str += "\tnets[#{i}] = new Net(new int[#{fanouts.length}] {#{fanouts.collect{|ind| ind.to_s}.join(', ')}}, #{fanouts.length}, gateChanged);\n"
181
+ end
182
+ end
183
+ str += "\n"
184
+ latchArray.each_with_index do |latch, i|
185
+ str += "\tlatches[#{i}] = new Latch(nets[#{model.nets.index(latch.input)}], nets[#{model.nets.index(latch.output)}], #{latch.initValue != 1 ? '0' : '1'});\n"
186
+ end
187
+ str += "\n"
188
+ gateArray.each_with_index do |gate, i|
189
+ str += "\tgates[#{i}] = new Gate(new Net*[#{gate.inputs.length}]{#{gate.inputs.collect{|net| "nets[#{model.nets.index(net)}]"}.join(', ')}}, #{gate.inputs.length}, nets[#{model.nets.index(gate.output)}], new uint32_t[#{((2**gate.inputs.length)/32.0).ceil}]{#{gate.get_simulation_table}});\n"
190
+ end
191
+ str += "\n"
192
+ str += "\tfor (unsigned int i(0); i < nbGates; i++) {\n\t\tgateChanged[i] = false;\n\t}\n"
193
+ str += "\n"
194
+ simInputs.each do |key, val|
195
+ val.each do |net_index|
196
+ ind = model.nets.index(net_index[0])
197
+ next if ind.nil?
198
+ str += "\tINPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end} = nets[#{ind}];\n"
199
+ end
200
+ end
201
+ str += "\n"
202
+ simOutputs.each do |key, val|
203
+ val.each do |net_index|
204
+ str += "\tOUTPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end} = nets[#{model.nets.index(net_index[0])}];\n"
205
+ end
206
+ end
207
+ unless simVectorInputs.empty? then
208
+ str += "\n"
209
+ simVectorInputs.each do |simVectInput|
210
+ next if simVectInput[1].collect{|net| model.nets.index(net)}.include?(nil)
211
+ str += "\tINPUT_VECTOR_#{simVectInput[0]} = new BitVector(new Net*[#{simVectInput[1].length}]{#{simVectInput[1].collect{|net| "nets[#{model.nets.index(net)}]"}.join(', ')}}, #{simVectInput[1].length});\n"
212
+ end
213
+ end
214
+ unless simVectorOutputs.empty? then
215
+ str += "\n"
216
+ simVectorOutputs.each do |simVectOutput|
217
+ str += "\tOUTPUT_VECTOR_#{simVectOutput[0]} = new BitVector(new Net*[#{simVectOutput[1].length}]{#{simVectOutput[1].collect{|net| "nets[#{model.nets.index(net)}]"}.join(', ')}}, #{simVectOutput[1].length});\n"
218
+ end
219
+ end
220
+ str += "\n"
221
+ str += "\tModel::setNets(nets);\n"
222
+ str += "\tModel::setLatches(latches);\n"
223
+ str += "\tModel::setGates(gates);\n"
224
+ str += "\tModel::setChanges(gateChanged);\n"
225
+ str += "}\n\n\n"
226
+
227
+ str += "#{className}::~#{className}()\n"
228
+ str += "{\n"
229
+ str += "\tunsigned int i;\n\n"
230
+ if nbNets > 0 then
231
+ str += "\tfor (i = 0; i < nbNets; i++) {\n"
232
+ str += "\t\tdelete nets[i];\n"
233
+ str += "\t}\n\n"
234
+ end
235
+ if nbLatches > 0 then
236
+ str += "\tfor (i = 0; i < nbLatches; i++) {\n"
237
+ str += "\t\tdelete latches[i];\n"
238
+ str += "\t}\n\n"
239
+ end
240
+ if nbGates > 0 then
241
+ str += "\tfor (i = 0; i < nbGates; i++) {\n"
242
+ str += "\t\tdelete gates[i];\n"
243
+ str += "\t}\n"
244
+ end
245
+ unless simVectorInputs.empty? then
246
+ str += "\n"
247
+ simVectorInputs.each do |simVectInput|
248
+ next if simVectInput[1].collect{|net| model.nets.index(net)}.include?(nil)
249
+ str += "\tdelete INPUT_VECTOR_#{simVectInput[0]};\n"
250
+ end
251
+ end
252
+ unless simVectorOutputs.empty? then
253
+ str += "\n"
254
+ simVectorOutputs.each do |simVectOutput|
255
+ str += "\tdelete OUTPUT_VECTOR_#{simVectOutput[0]};\n"
256
+ end
257
+ end
258
+ str += "}\n\n\n"
259
+ str += "void #{className}::setConstants()\n{\n"
260
+ model.components.select{|comp| comp.isGate? and comp.is_constant?}.each do |cstGate|
261
+ if cstGate.singleOutputCoverList.empty? or cstGate.singleOutputCoverList[0][1] == 0 then
262
+ str += "\tnets[#{model.nets.index(cstGate.output)}]->setValue(0);\n"
263
+ else
264
+ str += "\tnets[#{model.nets.index(cstGate.output)}]->setValue(1);\n"
265
+ end
266
+ if cstGate.singleOutputCoverList.length > 1 and cstGate.singleOutputCoverList.collect{|ina_o| ina_o[1]}.uniq.length > 1 then
267
+ abort "ERROR: Bad constant definition in gate \"#{cstGate.output.name}\""
268
+ end
269
+ end
270
+ str += "}\n\n"
271
+
272
+
273
+ outFileName = model.name + '_cpp_sim.cc'
274
+ File.write(outFileName, File.read(File.join(File.dirname(File.expand_path(__FILE__)), '..', '..', 'share', 'blimulator_cpp_classes.cc')) + str)
275
+ puts "Written C++ simulation model in file \"#{outFileName}\"" unless quiet
276
+
277
+ compileLine = "g++ -c -W -Wall -O3 -std=c++11 #{outFileName} -o #{File.basename(outFileName, '.cc')}.o"
278
+ puts "Compiling model...\n#{compileLine}" unless quiet
279
+ case system(compileLine)
280
+ when nil then
281
+ abort "ERROR: No g++ compiler found"
282
+ when false then
283
+ abort "An error occured during compilation"
284
+ end
285
+
286
+
287
+ ## Header ##
288
+ hstr = "class #{className} : public Model\n{\n"
289
+ hstr += "\tprivate:\n\n"
290
+ hstr += "\t\tstatic const unsigned int nbNets = #{nbNets};\n"
291
+ hstr += "\t\tstatic const unsigned int nbLatches = #{nbLatches};\n"
292
+ hstr += "\t\tstatic const unsigned int nbGates = #{nbGates};\n\n"
293
+ hstr += "\t\tNet *nets[nbNets];\n"
294
+ hstr += "\t\tLatch *latches[nbLatches];\n"
295
+ hstr += "\t\tGate *gates[nbGates];\n\n"
296
+ hstr += "\t\tbool gateChanged[nbGates];\n\n"
297
+ hstr += "\tpublic:\n\n"
298
+ hstr += "\t\t#{className}();\n"
299
+ hstr += "\t\t~#{className}();\n\n"
300
+ simInputs.each do |key, val|
301
+ val.each do |net_index|
302
+ ind = model.nets.index(net_index[0])
303
+ next if ind.nil?
304
+ hstr += "\t\tNet *INPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end};\n"
305
+ end
306
+ end
307
+ hstr += "\n"
308
+ simOutputs.each do |key, val|
309
+ val.each do |net_index|
310
+ hstr += "\t\tNet *OUTPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end};\n"
311
+ end
312
+ end
313
+ unless simVectorInputs.empty? then
314
+ hstr += "\n"
315
+ simVectorInputs.each do |simVectInput|
316
+ next if simVectInput[1].collect{|net| model.nets.index(net)}.include?(nil)
317
+ hstr += "\t\tBitVector *INPUT_VECTOR_#{simVectInput[0]};\n"
318
+ end
319
+ end
320
+ unless simVectorOutputs.empty? then
321
+ hstr += "\n"
322
+ simVectorOutputs.each do |simVectOutput|
323
+ hstr += "\t\tBitVector *OUTPUT_VECTOR_#{simVectOutput[0]};\n"
324
+ end
325
+ end
326
+ hstr += "\n\tprivate:\n\n\t\tvoid setConstants();\n"
327
+ hstr += "};\n\n#endif /* #{model.name.upcase}_SIMULATION_HEADER_H */\n"
328
+
329
+ hhstr = "#ifndef #{model.name.upcase}_SIMULATION_HEADER_H\n#define #{model.name.upcase}_SIMULATION_HEADER_H\n\n"
330
+ outHeadername = model.name + '_cpp_header.hh'
331
+ File.write(outHeadername, hhstr + File.read(File.join(File.dirname(File.expand_path(__FILE__)), '..', '..', 'share', 'blimulator_cpp_classes.hh')) + hstr)
332
+
333
+ puts "Written C++ model simulation header in file \"#{outHeadername}\"" unless quiet
334
+ puts "Now you can write your testbench in a C++ file as 'testbench.cc' including '#include \"#{outHeadername}\"', then run:" unless quiet
335
+ puts "g++ -W -Wall -O3 #{File.basename(outFileName, '.cc')}.o testbench.cc" unless quiet
336
+ end
337
+
338
+
339
+ end # BlifUtils::Netlist
340
+
341
+ end # BlifUtils
342
+