class BlifUtils::Netlist::Model
Attributes
clocks[RW]
components[RW]
inputs[R]
isBlackBox[R]
name[R]
nets[RW]
outputs[R]
Public Class Methods
new(name, inputs, outputs, components, nets, clocks, isBlackBox = false)
click to toggle source
# File lib/blifutils/netlist.rb, line 311 def initialize (name, inputs, outputs, components, nets, clocks, isBlackBox = false) @name = name @inputs = inputs @outputs = outputs @components = components @nets = nets @isBlackBox = isBlackBox @clocks = clocks end
Public Instance Methods
add_output_buffers()
click to toggle source
# File lib/blifutils/netlist.rb, line 530 def add_output_buffers @outputs.each_with_index do |oIO, i| newNet = BlifUtils::Netlist::Net.new(oIO.name, nil, [BlifUtils::Netlist::Fanout.new(:output, i)], false, true) newBuffer = BlifUtils::Netlist::LogicGate.new([oIO.net], newNet, [[[1], 1]]) newNet.driver = newBuffer fanoutIndexToDelete = oIO.net.fanouts.index{|fanout| fanout.target == :output and fanout.index == i} raise "Cannot find actual fanout to delete for output" if fanoutIndexToDelete.nil? oIO.net.fanouts[fanoutIndexToDelete].target = newBuffer oIO.net.fanouts[fanoutIndexToDelete].index = 0 oIO.net.isOutput = false oIO.net = newNet @components << newBuffer @nets << newNet end end
analyze()
click to toggle source
# File lib/blifutils/netlist.rb, line 358 def analyze bannerTitle = " #{@isBlackBox ? 'Black box' : 'Model'} \"#{@name}\" analysis " bannerSize = [40, bannerTitle.length].max str = '+' + ''.ljust(bannerSize,'-') + "+\n" str += '|' + bannerTitle.center(bannerSize) + "|\n" str += '+' + ''.ljust(bannerSize,'-') + "+\n" str += "#{@isBlackBox ? 'Black box' : 'Model'} \"#{@name}\"\n" str += " Inputs: #{@inputs.length}\n" str += " Outputs: #{@outputs.length}\n" return str if @isBlackBox str += " Nets: #{@nets.length}\n" str += " Edges: #{@nets.collect{|net| net.fanouts.length}.inject(:+)}\n" str += " Nodes: #{@components.length}\n" str += " Latches: #{@components.select{|comp| comp.isLatch?}.length}\n" gates = @components.select{|comp| comp.isGate?} nbGates = gates.length str += " Logic gates: #{nbGates}\n" subcircuits = @components.select{|comp| comp.isSubcircuit?} nbSubcircuits = subcircuits.length str += " Sub circuits: #{nbSubcircuits}\n" if nbGates > 0 then str += " Gates repartition:\n" repartition = Hash.new(0) gates.each{|gate| repartition[gate.inputs.length] += 1} Hash[repartition.sort].each do |key, val| str += " #{key.to_s.rjust(2)} input#{key > 1 ? 's:' : ': '} #{val.to_s.rjust(4)} #{(val*100/(nbGates.to_f)).round(1).to_s.rjust(5)}%\n" end nbBuffers = gates.select{|gate| gate.is_buffer?}.length nbConstants = gates.select{|gate| gate.is_constant?}.length str += " Buffers: #{nbBuffers}\n" if nbBuffers > 0 str += " Constants: #{nbConstants}\n" if nbConstants > 0 end if nbSubcircuits > 0 then str += " Sub circuits repartition:\n" repartition = Hash.new(0) subcircuits.each{|subckt| repartition[subckt.modelName] += 1} repartition.sort_by{|key, val| val}.each do |key_val| str += " #{key_val[0]}: #{key_val[1]}\n" end end return str end
analyze_to_hash()
click to toggle source
# File lib/blifutils/netlist.rb, line 406 def analyze_to_hash res = {} res[:name] = String.new(@name) res[:nb_inputs] = @inputs.length res[:nb_outputs] = @outputs.length res[:is_blackbox] = @isBlackBox return res if @isBlackBox res[:nb_nets] = @nets.length res[:nb_edges] = @nets.collect{|net| net.fanouts.length}.inject(:+) res[:nb_nodes] = @components.length res[:nb_latches] = @components.count{|comp| comp.isLatch?} gates = @components.select{|comp| comp.isGate?} res[:nb_gates] = gates.length res[:nb_subckt] = @components.count{|comp| comp.isSubcircuit?} if res[:nb_gates] > 0 then repartition = {} gates.collect{|g| g.inputs.length}.uniq.sort.each{|n| repartition[n] = 0} gates.each{|gate| repartition[gate.inputs.length] += 1} gh = {} gh[:gates_per_nb_inputs] = repartition gh[:nb_buffers] = gates.count{|gate| gate.is_buffer?} gh[:nb_constants] = gates.count{|gate| gate.is_constant?} res[:gates] = gh end if res[:nb_subckt] > 0 then repartition = Hash.new(0) subcircuits.each{|subckt| repartition[subckt.modelName] += 1} res[:subckts] = repartition end return res end
clone()
click to toggle source
# File lib/blifutils/netlist.rb, line 513 def clone ## stack level too deep (SystemStackError) if self is too big... =( return Marshal.load(Marshal.dump(self)) end
create_vhdl_file(topLevel = false)
click to toggle source
# File lib/blifutils/blif_to_vhdl.rb, line 46 def create_vhdl_file (topLevel = false) return if @isBlackBox fileName = @name + '.vhd' file = File.open(fileName, 'w') to_vhdl(toplevel: topLevel, stream: file) file.close STDERR.puts "File \"#{fileName}\" written." end
inspect()
click to toggle source
To prevent 36548 lines of output ##
# File lib/blifutils/netlist.rb, line 324 def inspect return "#<BlifUtils::Netlist::Model:#{object_id} @name=#{@name.inspect}>" end
is_blackbox?()
click to toggle source
# File lib/blifutils/netlist.rb, line 329 def is_blackbox? return not(not(@isBlackBox)) end
is_self_contained?()
click to toggle source
# File lib/blifutils/netlist.rb, line 443 def is_self_contained? return @components.index{|comp| comp.class == BlifUtils::Netlist::SubCircuit}.nil? end
level()
click to toggle source
Returns the logic level of the circuit, nil if the model includes subcircuits, or false if the model contains combinatorial loops
# File lib/blifutils/level_analyzer.rb, line 32 def level return nil unless self.is_self_contained? graph = BlifUtils::NetlistGraph::Graph::create_from_model(self) start_vertices = graph.vertices.select{|v| v.component.kind_of?(BlifUtils::Netlist::Latch) or v.component.output.isOutput}.uniq res = catch(:combinatorial_loop_found) do theMax = 0 visited_vertices = [] start_vertices.each do |start| follow_combinatorial_path(graph, start, visited_vertices) theMax = start.layer if start.layer > theMax end theMax end return false unless res return res end
level_analysis(withOutputGraphviz: false, quiet: false)
click to toggle source
# File lib/blifutils/level_analyzer.rb, line 83 def level_analysis (withOutputGraphviz: false, quiet: false) return unless is_self_contained? puts "Generating graph from model components..." unless quiet graphFull = BlifUtils::NetlistGraph::Graph.create_from_model(self) print "Extracting connected subgraphs... " unless quiet graphDAGs = graphFull.get_graph_without_input_output_reg_cst_modinst dags = graphDAGs.get_connected_subgraphs puts "#{dags.length} subgraph#{dags.length > 1 ? 's' : ''} found" print "Checking that there are no cycles in subgraphs...\n" unless quiet # Check that all subgraphs are acyclic dags.each_with_index do |dag, i| unless dag.is_acyclic? then str = "\nERROR: There is a combinatorial loop.\n This subgraph includes components:\n" dag.vertices.each do |vertice| str += " Component #{vertice.to_s}\n" end abort str end end puts "No combinatorial loops found" # Do graph layering unless quiet then print "Layering subgraphs...\n" unless withOutputGraphviz end maxDagSize = 0 maxDagLevel = 0 dags.each_with_index do |dag, i| dag.assign_layers_to_vertices dagSize = dag.vertices.length dagLevel = dag.vertices.collect{|vertice| vertice.layer}.reject{|l| l.nil?}.max maxDagSize = dagSize if dagSize != nil and maxDagSize < dagSize maxDagLevel = dagLevel if dagLevel != nil and maxDagLevel < dagLevel if withOutputGraphviz then File.write("#{@name}_graph_DAG_#{i}.gv", dag.to_graphviz) puts "Graph #{i.to_s.rjust(2)}: level #{dagLevel.to_s.rjust(2)}, size #{dagSize.to_s.rjust(2)}" end end if withOutputGraphviz then File.write("#{@name}_graph_subgraphs.gv", graphDAGs.to_graphviz) graphDAGs.vertices.each do |vertice| ind = graphFull.vertices.index{|vert| vert.component == vertice.component} graphFull.vertices[ind].layer = vertice.layer unless ind.nil? end File.write("#{@name}_graph_full.gv", graphFull.to_graphviz) end puts "Maximum number of layers: #{maxDagLevel}" puts "Maximum number of gate per subgraph: #{maxDagSize}" end
remove_buffers()
click to toggle source
# File lib/blifutils/netlist.rb, line 547 def remove_buffers buffers = @components.select{|comp| comp.isGate?}.select{|gate| gate.is_buffer?} buffers.each do |buffer| netA = buffer.inputs[0] netB = buffer.output netAbufferFanoutIndex = netA.fanouts.index{|fanout| fanout.target == buffer and fanout.index == 0} if netAbufferFanoutIndex.nil? then raise "Cannot find buffer fanout in net" end netA.fanouts.delete_at(netAbufferFanoutIndex) netB.fanouts.each do |fanout| if fanout.target.class == BlifUtils::Netlist::LogicGate then fanout.target.inputs[fanout.index] = netA elsif fanout.target.class == BlifUtils::Netlist::Latch then fanout.target.input = netA elsif fanout.target.class == BlifUtils::Netlist::SubCircuit then fanout.target.inputFormalAcutalList[fanout.index].net = netA elsif fanout.target == :output then @outputs[fanout.index].net = netA else raise "WTF?" end netA.fanouts << fanout end if netB.isOutput then netA.isOutput = true end @nets.delete(netB) @components.delete(buffer) end buffers = @components.select{|comp| comp.isGate?}.select{|gate| gate.is_buffer?} end
rename_nets()
click to toggle source
# File lib/blifutils/netlist.rb, line 519 def rename_nets i = 0 @nets.each do |net| unless net.isInput then net.name = "n#{i.to_s(16).upcase}" i += 1 end end end
set_undefined_latches_clock(clk)
click to toggle source
# File lib/blifutils/netlist.rb, line 342 def set_undefined_latches_clock (clk) @components.each do |c| next unless c.isLatch? and c.ctrlSig.nil? c.set_clock(clk) end end
set_undefined_latches_initial_value(value)
click to toggle source
# File lib/blifutils/netlist.rb, line 350 def set_undefined_latches_initial_value (value) @components.each do |c| next unless c.isLatch? and c.initValue.nil? c.set_initial_value(value) end end
set_undefined_latches_type(type)
click to toggle source
# File lib/blifutils/netlist.rb, line 334 def set_undefined_latches_type (type) @components.each do |c| next unless c.isLatch? and c.ctrlType.nil? c.set_type(type) end end
simulation_components_to_schedule_stack(withOutputGraphviz: false, quiet: false)
click to toggle source
# File lib/blifutils/layering.rb, line 349 def simulation_components_to_schedule_stack (withOutputGraphviz: false, quiet: false) unless is_self_contained? then raise "#{self.class.name}##{__method__.to_s}() requires that the model has no model reference in it. You must flatten the model before." end puts "Generating graph from model components..." unless quiet graphFull = BlifUtils::NetlistGraph::Graph.create_from_model(self) print "Extracting connected subgraphs... " unless quiet graphDAGs = graphFull.get_graph_without_input_output_reg_cst_modinst dags = graphDAGs.get_connected_subgraphs puts "#{dags.length} subgraph#{dags.length > 1 ? 's' : ''} found" unless quiet print "Checking that there are no cycles in subgraphs... " unless quiet # Check that all subgraphs are acyclic dags.each_with_index do |dag, i| unless dag.is_acyclic? then str = "\nERROR: There is a combinatorial loop.\n (See cycle in file \"#{@name}_graph_DAG_#{i}.gv\")\n This subgraph includes components:\n" dag.vertices.each do |vertice| str += " Component #{vertice.to_s}\n" end abort str end end puts "Ok" unless quiet # Do graph layering puts "Layering subgraphs..." unless quiet dags.each_with_index do |dag, i| dag.assign_layers_to_vertices File.write("#{@name}_graph_DAG_#{i}.gv", dag.to_graphviz) if withOutputGraphviz end File.write("#{@name}_graph_subgraphs.gv", graphDAGs.to_graphviz) if withOutputGraphviz graphDAGs.vertices.each do |vertice| ind = graphFull.vertices.index{|vert| vert.component == vertice.component} graphFull.vertices[ind].layer = vertice.layer unless ind.nil? end File.write("#{@name}_graph_full.gv", graphFull.to_graphviz) if withOutputGraphviz puts "Maximum number of layers: #{dags.collect{|dag| dag.vertices.collect{|vertice| vertice.layer}.reject{|l| l.nil?}.max}.reject{|m| m.nil?}.max}" unless quiet puts "Writing static schedule for component simulation..." unless quiet componentSchedulingStack = [] dags.each do |dag| dag.vertices.sort{|verta, vertb| vertb.layer <=> verta.layer}.each{|vert| componentSchedulingStack << vert.component} end unless componentSchedulingStack.index{|comp| comp.class != BlifUtils::Netlist::LogicGate}.nil? then raise "merde" end return componentSchedulingStack end
to_blif()
click to toggle source
# File lib/blifutils/netlist.rb, line 448 def to_blif str = ".model #{@name}\n" if @isBlackBox then tmpstr = ".inputs" unless @inputs.empty? then @inputs.collect{|io| io.name}.each do |iname| if tmpstr.length + iname.length + 3 > 80 then tmpstr += " \\\n" str += tmpstr tmpstr = '' end tmpstr += ' ' + iname end str += tmpstr + "\n" end tmpstr = ".outputs" unless @inputs.empty? then @outputs.collect{|io| io.name}.each do |iname| if tmpstr.length + iname.length + 3 > 80 then tmpstr += " \\\n" str += tmpstr tmpstr = '' end tmpstr += ' ' + iname end str += tmpstr + "\n" end str += ".blackbox\n.end\n" return str end tmpstr = ".inputs" unless @inputs.empty? then @inputs.collect{|io| io.net.name}.each do |iname| if tmpstr.length + iname.length + 3 > 80 then tmpstr += " \\\n" str += tmpstr tmpstr = '' end tmpstr += ' ' + iname end str += tmpstr + "\n" end tmpstr = ".outputs" unless @inputs.empty? then @outputs.collect{|io| io.net.name}.each do |iname| if tmpstr.length + iname.length + 3 > 80 then tmpstr += " \\\n" str += tmpstr tmpstr = '' end tmpstr += ' ' + iname end str += tmpstr + "\n" end #str += "\n" @components.select{|comp| comp.isSubcircuit?}.each{|subckt| str += subckt.to_blif} #str += "\n" @components.select{|comp| comp.isLatch?}.each{|latch| str += latch.to_blif} #str += "\n" @components.select{|comp| comp.isGate?}.each{|gate| str += gate.to_blif} str += ".end\n" return str end
to_vhdl(topLevel: false, stream: "")
click to toggle source
# File lib/blifutils/blif_to_vhdl.rb, line 58 def to_vhdl (topLevel: false, stream: "") iNames = @inputs.collect{|io| io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')} oNames = @outputs.collect{|io| io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')} just = [([0] + iNames.collect{|name| name.length}).max + 3, ([0] + oNames.collect{|name| name.length}).max + 4].max entityStr = iNames.collect{|name| "#{(name + '_in').ljust(just)} : in std_ulogic;"} + oNames.collect{|name| "#{(name + '_out').ljust(just)} : out std_ulogic;"} stream << "\nlibrary IEEE;\nuse IEEE.STD_LOGIC_1164.ALL;\n\n\nentity #{@name.upcase} is\n\tport ( " stream << entityStr.join("\n\t ").chop stream << ");\nend #{name.upcase};\n\n\n" stream << "architecture blif of #{name.upcase} is\n\n" just = @nets.collect{|net| net.name.length}.max @clocks.reject{|clkname| @nets.collect{|net| net.name}.include?(clkname)}.each do |name| stream << "\tsignal #{name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'').ljust(just)} : std_ulogic;\n" end @nets.each do |net| name = net.name stream << "\tsignal #{name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'').ljust(just)} : std_ulogic#{if net.driver.kind_of?(BlifUtils::Netlist::Latch) and net.driver.initValue <= 1 then " := '#{net.driver.initValue}'" end};\n" end stream << "\nbegin\n\n" @inputs.each do |io| stream << "\t#{io.net.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')} <= #{io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_in'};\n" end stream <<("\n") unless @inputs.empty? @outputs.each do |io| stream << "\t#{io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_out'} <= #{io.net.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')};\n" end stream <<("\n") unless @outputs.empty? stream <<("\n") latches = @components.select{|comp| comp.kind_of?(BlifUtils::Netlist::Latch)} unless latches.empty? then clks = latches.collect{|latch| latch.ctrlSig}.reject{|el| el.nil?}.collect{|ctrlsig| if ctrlsig.kind_of?(String) then ctrlsig else ctrlsig.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') end}.uniq clks.each do |clkname| stream << "\tprocess(#{clkname.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')})\n\tbegin\n\t\tif rising_edge(#{clkname.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')}) then\n" latches.select{|latch| latch.ctrlSig != nil and (latch.ctrlSig == clkname or latch.ctrlSig.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') == clkname)}.each do |latch| stream << "\t\t\t#{latch.output.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')} <= #{latch.input.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')};\n" end stream << "\t\tend if;\n\tend process;\n" end if clks.empty? then stream << "\n\tprocess(_clk)\n\tbegin\n\t\tif rising_edge(_clk) then\n" latches.select{|latch| latch.ctrlSig.nil?}.each do |latch| stream << "\n\t\t\t#{latch.output.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')} <= #{latch.input.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')};\n" end stream << "\t\tend if;\n\tend process;\n" end stream <<("\n") end gates = @components.select{|comp| comp.kind_of?(BlifUtils::Netlist::LogicGate)} gates.each do |gate| next if gate.is_constant? oname = gate.output.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') inames = gate.inputs.collect{|net| net.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')} stream << "\t#{oname} <= " polarity = gate.singleOutputCoverList.collect{|inputs_output| inputs_output[1]}.uniq if polarity.length != 1 or (polarity[0] != 0 and polarity[0] != 1) then abort "ERROR: Output cover list of gate \"#{oname}\" contains '1' and '0' as output!" end stream <<("not(") if polarity[0] == 0 socvlst = gate.singleOutputCoverList.collect { |cvlst| cvlstArr = [] cvlst[0].each_with_index { |val, i| if val == 1 then cvlstArr << inames[i] elsif val == 0 then cvlstArr << "not(#{inames[i]})" #else # cvlstArr << "'1'" end } '(' + cvlstArr.join(' and ') + ')' }.join(" or\n\t#{' '*oname.length} ") stream << socvlst stream <<(")") if polarity[0] == 0 stream <<(";\n") end stream <<("\n") unless gates.empty? constants = gates.select{|gate| gate.is_constant?} constants.each do |cstGate| oname = cstGate.output.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') if cstGate.singleOutputCoverList.empty? or cstGate.singleOutputCoverList[0][2] == 0 then stream << "\t#{oname} <= '0';\n" else stream << "\t#{oname} <= '1';\n" end end stream <<("\n") unless constants.empty? @components.select{|comp| comp.kind_of?(BlifUtils::Netlist::SubCircuit)}.each_with_index do |subckt, i| stream << "\tCMPINST#{i}: entity work.#{subckt.modelName.upcase}\n\tport map ( " iNames = subckt.inputFormalAcutalList.collect{|io| io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_in'} oNames = subckt.outputFormalAcutalList.collect{|io| io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_out'} just = ([0] + iNames.collect{|name| name.length} + oNames.collect{|name| name.length}).max portmapStr = subckt.inputFormalAcutalList.collect{|io| "#{(io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_in').ljust(just)} => #{io.net.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')},"} + subckt.outputFormalAcutalList.collect{|io| "#{(io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_out').ljust(just)} => #{io.net.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')},"} stream << portmapStr.join("\n\t ").chop stream << ");\n\n" end stream << "end blif;\n\n" return stream end
Private Instance Methods
follow_combinatorial_path(graph, vertice, visited_vertices)
click to toggle source
# File lib/blifutils/level_analyzer.rb, line 57 def follow_combinatorial_path (graph, vertice, visited_vertices) return unless vertice.layer.nil? throw :combinatorial_loop_found if visited_vertices.include?(vertice) visited_vertices << vertice if vertice.component.kind_of?(BlifUtils::Netlist::Latch) then my_layer = 0 else my_layer = 1 end the_max = 0 vertice.predecessors.each do |svert| next if (svert == :input or svert == :output or svert.component.kind_of?(BlifUtils::Netlist::Latch)) follow_combinatorial_path(graph, svert, visited_vertices) if svert.layer.nil? the_max = [the_max, svert.layer].max end vertice.layer = my_layer + the_max end