Class: BlifUtils::Netlist

Inherits:
Object
  • Object
show all
Defined in:
lib/blifutils/netlist.rb,
lib/blifutils/layering.rb,
lib/blifutils/blif_to_vhdl.rb,
lib/blifutils/level_analyzer.rb,
lib/blifutils/simulator_generator.rb

Defined Under Namespace

Classes: Component, Fanout, IO, Latch, LogicGate, Model, Net, SubCircuit

Instance Method Summary collapse

Constructor Details

#initializeNetlist

Returns a new instance of Netlist.



586
587
588
# File 'lib/blifutils/netlist.rb', line 586

def initialize
	@models = []
end

Instance Method Details

#add_model(model) ⇒ Object



611
612
613
614
615
616
617
# File 'lib/blifutils/netlist.rb', line 611

def add_model (model)
	if include?(model.name) then
		abort "ERROR: Model \"#{model.name}\" is already defined in the model collection"
	end
	@models << model
	self
end

#add_model_to_front(model) ⇒ Object



620
621
622
623
624
625
626
# File 'lib/blifutils/netlist.rb', line 620

def add_model_to_front (model)
	if include?(model.name) then
		abort "ERROR: Model \"#{model.name}\" is already defined in the model collection".ligth_red
	end
	@models.unshift(model)
	self
end

#analyzeObject



653
654
655
656
657
# File 'lib/blifutils/netlist.rb', line 653

def analyze
	str = "Model collection contains #{length} models\n"
	@models.each{|model| str += model.analyze}
	return str
end

#clearObject



697
698
699
700
# File 'lib/blifutils/netlist.rb', line 697

def clear
	@models = []
	self
end

#create_simulation_file_for_model(modelName = nil, quiet: false) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/blifutils/simulator_generator.rb', line 55

def create_simulation_file_for_model (modelName = nil, quiet: false)
	modelName = first_model.name if modelName.nil?
	dedel = get_model_by_name(modelName)
	if dedel.nil?
		abort "ERROR: Model \"#{modelName}\" not found."
	end
	if dedel.is_self_contained? then
		model = dedel
	else
		model = flatten(modelName, false, quiet: quiet)
	end

	className = (model.name + '_simulation_class').gsub('_',' ').split.collect{|word| word.capitalize}.join
	gateArray = model.simulation_components_to_schedule_stack(withOutputGraphviz: false, quiet: quiet) # This array does not contain constants
	latchArray = model.components.select{|comp| comp.isLatch?}
	nbGates = gateArray.length
	nbLatches = latchArray.length
	nbNets = model.nets.length

	# Find inputs #
	simInputs = {} # {name -> [[net, index], ... ], ... }
	model.inputs.each do |iIO|
		iname = iIO.name
		match = iname.match(/(.*?)((\[(\d+)\])|(_(\d+)_))/)
		if match.nil? then
			simInputs[iname] = [] if simInputs[iname].nil?
			simInputs[iname] << [iIO.net, 0]
		else
			unless match[4].nil? then
				indNum = match[4].to_i
			end
			unless match[6].nil? then
				indNum = match[6].to_i
			end
			simInputs[match[1]] = [] if simInputs[match[1]].nil?
			simInputs[match[1]] << [iIO.net, indNum]
		end
	end
	simVectorInputs = [] # [[name, [net0, net1, ... ]], ... ]
	simInputs.each do |vectName, net_index_array|
		net_index_array.sort!{|net_indexA, net_indexB| net_indexA[1] <=> net_indexB[1]}
		simVectorInputs << [vectName, net_index_array.collect{|net_index| net_index[0]}]
	end

	# Find outputs #
	simOutputs = {} # {name -> [[net, index], ... ], ... }
	model.outputs.each do |iIO|
		oname = iIO.name
		match = oname.match(/(.*?)((\[(\d+)\])|(_(\d+)_))/)
		if match.nil? then
			simOutputs[oname] = [] if simOutputs[oname].nil?
			simOutputs[oname] << [iIO.net, 0]
		else
			unless match[4].nil? then
				indNum = match[4].to_i
			end
			unless match[6].nil? then
				indNum = match[6].to_i
			end
			simOutputs[match[1]] = [] if simOutputs[match[1]].nil?
			simOutputs[match[1]] << [iIO.net, indNum]
		end
	end
	simVectorOutputs = [] # [[name, [net0, net1, ... ]], ... ]
	simOutputs.each do |vectName, net_index_array|
		net_index_array.sort!{|net_indexA, net_indexB| net_indexA[1] <=> net_indexB[1]}
		simVectorOutputs << [vectName, net_index_array.collect{|net_index| net_index[0]}]
	end


	str = "/#{'*'*78}/\n\n\n"

	str += "class #{className} : public Model\n{\n" 
	str += "\tprivate:\n\n" 
	str += "\t\tstatic const unsigned int nbNets    = #{nbNets};\n"
	str += "\t\tstatic const unsigned int nbLatches = #{nbLatches};\n"
	str += "\t\tstatic const unsigned int nbGates   = #{nbGates};\n\n"
	str += "\t\tNet   *nets[nbNets];\n"
	str += "\t\tLatch *latches[nbLatches];\n"
	str += "\t\tGate  *gates[nbGates];\n\n"
	str += "\t\tbool   gateChanged[nbGates];\n\n"
	str += "\tpublic:\n\n"
	str += "\t\t#{className}();\n"
	str += "\t\t~#{className}();\n\n"
	simInputs.each do |key, val|
		val.each do |net_index|
			ind = model.nets.index(net_index[0])
			next if ind.nil?
			str += "\t\tNet *INPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end};\n"
		end
	end
	str += "\n"
	simOutputs.each do |key, val|
		val.each do |net_index|
			str += "\t\tNet *OUTPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end};\n"
		end
	end
	unless simVectorInputs.empty? then
		str += "\n"
		simVectorInputs.each do |simVectInput|
			next if simVectInput[1].collect{|net| model.nets.index(net)}.include?(nil)
			str += "\t\tBitVector *INPUT_VECTOR_#{simVectInput[0]};\n"
		end
	end
	unless simVectorOutputs.empty? then
		str += "\n"
		simVectorOutputs.each do |simVectOutput|
			str += "\t\tBitVector *OUTPUT_VECTOR_#{simVectOutput[0]};\n"
		end
	end
	str += "\n\tprivate:\n\n\t\tvoid setConstants();\n"
	str += "};\n\n"

	str += "#{className}::#{className}() :\n"
	str += "\tModel(nbNets, nbLatches, nbGates)\n"
	str += "{\n"
	model.nets.each_with_index do |net, i|
		fanouts = []
		net.fanouts.each do |fanout| 
			index = gateArray.index(fanout.target)
			fanouts << index unless index.nil?
		end
		if fanouts.empty? then
			str += "\tnets[#{i}] = new Net(NULL, 0, gateChanged);\n"
		else
			str += "\tnets[#{i}] = new Net(new int[#{fanouts.length}] {#{fanouts.collect{|ind| ind.to_s}.join(', ')}}, #{fanouts.length}, gateChanged);\n"
		end
	end
	str += "\n"
	latchArray.each_with_index do |latch, i|
		str += "\tlatches[#{i}] = new Latch(nets[#{model.nets.index(latch.input)}], nets[#{model.nets.index(latch.output)}], #{latch.initValue != 1 ? '0' : '1'});\n"
	end
	str += "\n"
	gateArray.each_with_index do |gate, i|
		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"
	end
	str += "\n"
	str += "\tfor (unsigned int i(0); i < nbGates; i++) {\n\t\tgateChanged[i] = false;\n\t}\n"
	str += "\n"
	simInputs.each do |key, val|
		val.each do |net_index|
			ind = model.nets.index(net_index[0])
			next if ind.nil?
			str += "\tINPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end} = nets[#{ind}];\n"
		end
	end
	str += "\n"
	simOutputs.each do |key, val|
		val.each do |net_index|
			str += "\tOUTPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end} = nets[#{model.nets.index(net_index[0])}];\n"
		end
	end
	unless simVectorInputs.empty? then
		str += "\n"
		simVectorInputs.each do |simVectInput|
			next if simVectInput[1].collect{|net| model.nets.index(net)}.include?(nil)
			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"
		end
	end
	unless simVectorOutputs.empty? then
		str += "\n"
		simVectorOutputs.each do |simVectOutput|
			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"
		end
	end
	str += "\n"
	str += "\tModel::setNets(nets);\n"
	str += "\tModel::setLatches(latches);\n"
	str += "\tModel::setGates(gates);\n"
	str += "\tModel::setChanges(gateChanged);\n"
	str += "}\n\n\n"

	str += "#{className}::~#{className}()\n"
	str += "{\n"
	str += "\tunsigned int i;\n\n"
	if nbNets > 0 then
		str += "\tfor (i = 0; i < nbNets; i++) {\n"
		str += "\t\tdelete nets[i];\n"
		str += "\t}\n\n"
	end
	if nbLatches > 0 then
		str += "\tfor (i = 0; i < nbLatches; i++) {\n"
		str += "\t\tdelete latches[i];\n"
		str += "\t}\n\n"
	end
	if nbGates > 0 then
		str += "\tfor (i = 0; i < nbGates; i++) {\n"
		str += "\t\tdelete gates[i];\n"
		str += "\t}\n"
	end
	unless simVectorInputs.empty? then
		str += "\n"
		simVectorInputs.each do |simVectInput|
			next if simVectInput[1].collect{|net| model.nets.index(net)}.include?(nil)
			str += "\tdelete INPUT_VECTOR_#{simVectInput[0]};\n"
		end
	end
	unless simVectorOutputs.empty? then
		str += "\n"
		simVectorOutputs.each do |simVectOutput|
			str += "\tdelete OUTPUT_VECTOR_#{simVectOutput[0]};\n"
		end
	end
	str += "}\n\n\n"
	str += "void #{className}::setConstants()\n{\n"
	model.components.select{|comp| comp.isGate? and comp.is_constant?}.each do |cstGate|
		if cstGate.singleOutputCoverList.empty? or cstGate.singleOutputCoverList[0][1] == 0 then
			str += "\tnets[#{model.nets.index(cstGate.output)}]->setValue(0);\n"
		else
			str += "\tnets[#{model.nets.index(cstGate.output)}]->setValue(1);\n"
		end
		if cstGate.singleOutputCoverList.length > 1 and cstGate.singleOutputCoverList.collect{|ina_o| ina_o[1]}.uniq.length > 1 then
			abort "ERROR: Bad constant definition in gate \"#{cstGate.output.name}\""
		end
	end
	str += "}\n\n"


	outFileName = model.name + '_cpp_sim.cc'
	File.write(outFileName, File.read(File.join(File.dirname(File.expand_path(__FILE__)), '..', '..', 'share', 'blimulator_cpp_classes.cc')) + str)
	puts "Written C++ simulation model in file \"#{outFileName}\"" unless quiet

	compileLine = "g++ -c -W -Wall -O3 -std=c++11 #{outFileName} -o #{File.basename(outFileName, '.cc')}.o"
	puts "Compiling model...\n#{compileLine}" unless quiet
	case system(compileLine)
	when nil then
		abort "ERROR: No g++ compiler found"
	when false then
		abort "An error occured during compilation"
	end


	## Header ##
	hstr  = "class #{className} : public Model\n{\n" 
	hstr += "\tprivate:\n\n" 
	hstr += "\t\tstatic const unsigned int nbNets    = #{nbNets};\n"
	hstr += "\t\tstatic const unsigned int nbLatches = #{nbLatches};\n"
	hstr += "\t\tstatic const unsigned int nbGates   = #{nbGates};\n\n"
	hstr += "\t\tNet   *nets[nbNets];\n"
	hstr += "\t\tLatch *latches[nbLatches];\n"
	hstr += "\t\tGate  *gates[nbGates];\n\n"
	hstr += "\t\tbool   gateChanged[nbGates];\n\n"
	hstr += "\tpublic:\n\n"
	hstr += "\t\t#{className}();\n"
	hstr += "\t\t~#{className}();\n\n"
	simInputs.each do |key, val|
		val.each do |net_index|
			ind = model.nets.index(net_index[0])
			next if ind.nil?
			hstr += "\t\tNet *INPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end};\n"
		end
	end
	hstr += "\n"
	simOutputs.each do |key, val|
		val.each do |net_index|
			hstr += "\t\tNet *OUTPUT_NET_#{key}#{if val.length > 1 then "_#{net_index[1]}" end};\n"
		end
	end
	unless simVectorInputs.empty? then
		hstr += "\n"
		simVectorInputs.each do |simVectInput|
			next if simVectInput[1].collect{|net| model.nets.index(net)}.include?(nil)
			hstr += "\t\tBitVector *INPUT_VECTOR_#{simVectInput[0]};\n"
		end
	end
	unless simVectorOutputs.empty? then
		hstr += "\n"
		simVectorOutputs.each do |simVectOutput|
			hstr += "\t\tBitVector *OUTPUT_VECTOR_#{simVectOutput[0]};\n"
		end
	end
	hstr += "\n\tprivate:\n\n\t\tvoid setConstants();\n"
	hstr += "};\n\n#endif /* #{model.name.upcase}_SIMULATION_HEADER_H */\n"

	hhstr = "#ifndef #{model.name.upcase}_SIMULATION_HEADER_H\n#define #{model.name.upcase}_SIMULATION_HEADER_H\n\n"
	outHeadername = model.name + '_cpp_header.hh'
	File.write(outHeadername, hhstr + File.read(File.join(File.dirname(File.expand_path(__FILE__)), '..', '..', 'share', 'blimulator_cpp_classes.hh')) + hstr)

	puts "Written C++ model simulation header in file \"#{outHeadername}\"" unless quiet
	puts "Now you can write your testbench in a C++ file as 'testbench.cc' including '#include \"#{outHeadername}\"', then run:" unless quiet
	puts "g++ -W -Wall -O3 #{File.basename(outFileName, '.cc')}.o testbench.cc" unless quiet
end

#create_vhdl_files(topLevelModuleName = nil) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/blifutils/blif_to_vhdl.rb', line 27

def create_vhdl_files (topLevelModuleName = nil)
	if topLevelModuleName then
		tLModel = get_model_by_name(topLevelModuleName)
	else
		tLModel = first_model
	end

	abort "ERROR: create_vhdl_file(#{topLevelModuleName}): cannot find top level model" if tLModel.nil?

	update_clocks()

	models.each do |model| 
		model.create_vhdl_file(model == tLModel)
	end
end

#first_modelObject



596
597
598
# File 'lib/blifutils/netlist.rb', line 596

def first_model
	return @models[0]
end

#flatten(modelName = nil, withOutputBuffers = true, quiet: false) ⇒ Object



677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
# File 'lib/blifutils/netlist.rb', line 677

def flatten (modelName = nil, withOutputBuffers = true, quiet: false)
	modelName = first_model.name if modelName.nil?
	dedel = get_model_by_name(modelName)
	if dedel.nil?
		abort "ERROR: Model \"#{modelName}\" not found."
	end
	if dedel.is_self_contained? then
		return dedel.clone
	end
	####################################
	update_clocks()
	####################################
	flattenedModel = flatten_model_recursive(modelName, [], quiet: quiet)
	flattenedModel.remove_buffers
	flattenedModel.rename_nets
	flattenedModel.add_output_buffers if withOutputBuffers
	return flattenedModel
end

#get_model_by_name(name) ⇒ Object



648
649
650
# File 'lib/blifutils/netlist.rb', line 648

def get_model_by_name (name)
	return @models.select{|mod| mod.name == name}[0]
end

#include?(model) ⇒ Boolean

Returns:

  • (Boolean)


629
630
631
632
633
634
635
# File 'lib/blifutils/netlist.rb', line 629

def include? (model)
	if model.class == String then
		return model_names.include?(model)
	elsif model.class == BlifUtils::Netlist::Model then
		return @models.include?(model)
	end
end

#lengthObject



601
602
603
# File 'lib/blifutils/netlist.rb', line 601

def length
	return @models.length
end

#model_namesObject



606
607
608
# File 'lib/blifutils/netlist.rb', line 606

def model_names
	return @models.collect{|mod| mod.name}
end

#modelsObject



591
592
593
# File 'lib/blifutils/netlist.rb', line 591

def models
	return @models
end

#remove_model(model) ⇒ Object



638
639
640
641
642
643
644
645
# File 'lib/blifutils/netlist.rb', line 638

def remove_model (model)
	if model.class == String then
		@models.delete_if{|momo| momo.name == model}
	elsif model.class == BlifUtils::Netlist::Model then
		@models.delete(model)
	end
	self
end

#remove_unused_modelsObject



660
661
662
663
664
665
666
667
668
669
# File 'lib/blifutils/netlist.rb', line 660

def remove_unused_models
	used_models = []
	find_used_models_recursive(used_models, first_model)
	model_names.each do |modName|
		unless used_models.include?(modName) then
			remove_model(modName)
		end
	end
	self
end

#to_blifObject



672
673
674
# File 'lib/blifutils/netlist.rb', line 672

def to_blif
	return @models.collect{|mod| mod.to_blif}.join("\n")
end

#update_clocksObject



703
704
705
706
707
708
# File 'lib/blifutils/netlist.rb', line 703

def update_clocks
	@models.each do |model|
		update_clocks_for_model_recursive(model)
	end
	self
end