class BlifUtils::Netlist
Public Class Methods
new()
click to toggle source
# File lib/blifutils/netlist.rb, line 586 def initialize @models = [] end
Public Instance Methods
add_model(model)
click to toggle source
# 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)
click to toggle source
# 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
analyze()
click to toggle source
# 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
clear()
click to toggle source
# File lib/blifutils/netlist.rb, line 697 def clear @models = [] self end
create_simulation_file_for_model(modelName = nil, quiet: false)
click to toggle source
# 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)
click to toggle source
# 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_model()
click to toggle source
# File lib/blifutils/netlist.rb, line 596 def first_model return @models[0] end
flatten(modelName = nil, withOutputBuffers = true, quiet: false)
click to toggle source
# 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)
click to toggle source
# File lib/blifutils/netlist.rb, line 648 def get_model_by_name (name) return @models.select{|mod| mod.name == name}[0] end
include?(model)
click to toggle source
# 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
length()
click to toggle source
# File lib/blifutils/netlist.rb, line 601 def length return @models.length end
model_names()
click to toggle source
# File lib/blifutils/netlist.rb, line 606 def model_names return @models.collect{|mod| mod.name} end
models()
click to toggle source
# File lib/blifutils/netlist.rb, line 591 def models return @models end
remove_model(model)
click to toggle source
# 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_models()
click to toggle source
# 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_blif()
click to toggle source
# File lib/blifutils/netlist.rb, line 672 def to_blif return @models.collect{|mod| mod.to_blif}.join("\n") end
update_clocks()
click to toggle source
# File lib/blifutils/netlist.rb, line 703 def update_clocks @models.each do |model| update_clocks_for_model_recursive(model) end self end
Private Instance Methods
find_used_models_recursive(used_models, model)
click to toggle source
# File lib/blifutils/netlist.rb, line 763 def find_used_models_recursive (used_models, model) return if used_models.include?(model.name) used_models << model.name model.components.select{|comp| comp.isSubcircuit?}.collect{|subc| subc.modelName}.uniq.each do |modname| find_used_models_recursive(used_models, get_model_by_name(modname)) end end
flatten_model_recursive(modelName, parentModelList, quiet: false)
click to toggle source
# File lib/blifutils/netlist.rb, line 772 def flatten_model_recursive (modelName, parentModelList, quiet: false) puts "Flattening model \"#{modelName}\"" unless quiet # Retreive the model to be flattened originalModToFlatten = get_model_by_name(modelName) if originalModToFlatten.nil? then errStr = "ERROR: The model collection does not contains a model named \"#{modelName}\"." unless parentModelList.empty? then instancierFileName = get_model_by_name(parentModelList[-1][0]).originFileName errStr += "\n Model \"#{modelName}\" is referenced in model \"#{parentModelList[-1]}\"" end abort errStr end if originalModToFlatten.isBlackBox then abort "ERROR: Cannot flatten black box \"#{originalModToFlatten.name}\"" end # Check that there is no recursive instanciation of the same model (would get infinite loop) if parentModelList.include?(modelName) then errStr = "ERROR: Recursive reference of model \"#{modelName}\".\n Reference stack:\n" parentModelList.each{|pmn| errStr += " #{pmn}\n"} abort errStr end # Clone it to get a new object copy to work with currentModel = originalModToFlatten.clone # Loop on each sub circuits in the current model currentModel.components.select{|comp| comp.isSubcircuit?}.each do |subckt| next if get_model_by_name(subckt.modelName).isBlackBox # Get a flatten clone of the referenced model instanciatedModel = flatten_model_recursive(subckt.modelName, parentModelList + [currentModel.name], quiet: quiet) # Merge the inputs # instanciatedModel.inputs.each do |fio| # Find the IO aio whose formal corresponds to fio # actualIOindex = subckt.inputFormalAcutalList.index{|iaio| iaio.name == fio.name} if actualIOindex.nil? then abort "ERROR: In model \"#{currentModel.name}\": in reference to model \"#{instanciatedModel.name}\": input \"#{fio.name}\" is not driven." end aio = subckt.inputFormalAcutalList[actualIOindex] # aio.net -> fio.net newBuffer = BlifUtils::Netlist::LogicGate.new([aio.net], fio.net, [[[1], 1]]) aFanoutIndexToDelete = aio.net.fanouts.index{|fanout| fanout.target == subckt and fanout.index == actualIOindex} ##################################################################################### raise "Cannot find actual fanout to delete for input" if aFanoutIndexToDelete.nil? aio.net.fanouts[aFanoutIndexToDelete].target = newBuffer aio.net.fanouts[aFanoutIndexToDelete].index = 0 fio.net.driver = newBuffer fio.net.isInput = false currentModel.components << newBuffer ##################################################################################### #unless aFanoutIndexToDelete.nil? then # aio.net.fanouts[aFanoutIndexToDelete].target = newBuffer # aio.net.fanouts[aFanoutIndexToDelete].index = 0 # fio.net.driver = newBuffer # fio.net.isInput = false # currentModel.components << newBuffer #end ##################################################################################### end # Merge the outputs # instanciatedModel.outputs.each_with_index do |fio, oind| # Find the IO aio whose formal corresponds to fio # actualIOindex = subckt.outputFormalAcutalList.index{|iaio| iaio.name == fio.name} if actualIOindex.nil? then abort "ERROR: In model \"#{currentModel.name}\": in reference to model \"#{instanciatedModel.name}\": output \"#{fio.name}\" has no fanout." end aio = subckt.outputFormalAcutalList[actualIOindex] # fio.net -> aio.net newBuffer = BlifUtils::Netlist::LogicGate.new([fio.net], aio.net, [[[1], 1]]) fFanoutIndexToDelete = fio.net.fanouts.index{|fanout| fanout.target == :output and fanout.index == oind} raise "Cannot find actual fanout to delete for output" if fFanoutIndexToDelete.nil? fio.net.fanouts[fFanoutIndexToDelete].target = newBuffer fio.net.fanouts[fFanoutIndexToDelete].index = 0 aio.net.driver = newBuffer fio.net.isOutput = false currentModel.components << newBuffer end currentModel.components.delete(subckt) currentModel.components += instanciatedModel.components currentModel.nets += instanciatedModel.nets end return currentModel end
update_clocks_for_model_recursive(model)
click to toggle source
# File lib/blifutils/netlist.rb, line 714 def update_clocks_for_model_recursive (model) childrenClocks = [] model.components.select{|comp| comp.isSubcircuit?}.each do |subckt| referencedModel = get_model_by_name(subckt.modelName) if referencedModel.nil? then STDERR.puts "WARNING: update_clocks(): Model \"#{subckt.modelName}\" referenced from model \"#{model.name}\" is not is the model collection,\n cannot determine if it uses any clock." next end if referencedModel.isBlackBox then STDERR.puts "WARNING: update_clocks(): Model \"#{subckt.modelName}\" referenced from model \"#{model.name}\" is a black box,\n cannot determine if it uses any clock." next end update_clocks_for_model_recursive(referencedModel) childrenClocks += referencedModel.clocks end childrenClocks.uniq! childrenClocks.each do |clkname| model.clocks << clkname unless model.clocks.include?(clkname) end model.clocks.each do |clkname| next if model.inputs.collect{|io| io.name}.include?(clkname) newClkNet = BlifUtils::Netlist::Net.new(clkname, nil, [], true, false) newClkIo = BlifUtils::Netlist::IO.new(clkname, newClkNet) model.inputs.unshift(newClkIo) end model.components.select{|comp| comp.isSubcircuit?}.each do |subckt| referencedModel = get_model_by_name(subckt.modelName) next if referencedModel.nil? or referencedModel.isBlackBox referencedModel.clocks.each do |clkname| unless (subckt.inputFormalAcutalList.collect{|io| io.name} + subckt.outputFormalAcutalList.collect{|io| io.name}).include?(clkname) then actualClkNet = model.inputs.find{|io| io.name == clkname}.net actualClkNet.fanouts << BlifUtils::Netlist::Fanout.new(subckt, 0) newIo = BlifUtils::Netlist::IO.new(clkname, actualClkNet) subckt.inputFormalAcutalList.each_with_index do |io, i| net = io.net fanout = net.fanouts.find{|fnt| fnt.target == subckt and fnt.index == i} raise "Trouve pas le fanout de l'IO net:#{io.net.name} name:#{io.name} de la reference:#{subckt.modelName} depuis:#{model.name}" if fanout.nil? fanout.index += 1 end subckt.inputFormalAcutalList.unshift(newIo) end end end end