blifutils 0.0.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.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +377 -0
- data/bin/blifutils +184 -0
- data/examples/zpu/compile_zpu_program/Makefile +114 -0
- data/examples/zpu/compile_zpu_program/README.md +10 -0
- data/examples/zpu/compile_zpu_program/main.c +68 -0
- data/examples/zpu/simulate_zpu.rb +23 -0
- data/examples/zpu/testbench_zpu.cc +132 -0
- data/examples/zpu/zpu_helloworld.bin +0 -0
- data/examples/zpu/zpu_mem16.blif +3519 -0
- data/examples/zpu/zpu_mem16.piccolo +351 -0
- data/lib/blifutils.rb +31 -0
- data/lib/blifutils/ast.rb +185 -0
- data/lib/blifutils/blif_to_vhdl.rb +180 -0
- data/lib/blifutils/elaborator.rb +257 -0
- data/lib/blifutils/layering.rb +406 -0
- data/lib/blifutils/level_analyzer.rb +143 -0
- data/lib/blifutils/lexer.rb +133 -0
- data/lib/blifutils/netlist.rb +808 -0
- data/lib/blifutils/parser.rb +251 -0
- data/lib/blifutils/simulator_generator.rb +342 -0
- data/share/blimulator_cpp_classes.cc +446 -0
- data/share/blimulator_cpp_classes.hh +136 -0
- data/test/sqrt8.blif +40 -0
- data/test/sqrt8.piccolo +132 -0
- data/test/sqrt8_PC.blif +43 -0
- data/test/sqrt8_PC_counter.blif +61 -0
- data/test/sqrt8_PC_done.blif +49 -0
- data/test/sqrt8_PC_state.blif +68 -0
- data/test/sqrt8_PO.blif +43 -0
- data/test/sqrt8_PO_output.blif +67 -0
- data/test/sqrt8_PO_sqrtr.blif +66 -0
- data/test/sqrt8_PO_work.blif +227 -0
- data/test/test_blifutils.rb +79 -0
- data/test/testbench_sqrt8.cc +48 -0
- metadata +102 -0
@@ -0,0 +1,180 @@
|
|
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
|
+
|
22
|
+
|
23
|
+
module BlifUtils
|
24
|
+
|
25
|
+
class Netlist
|
26
|
+
|
27
|
+
def create_vhdl_files (topLevelModuleName = nil)
|
28
|
+
if topLevelModuleName then
|
29
|
+
tLModel = get_model_by_name(topLevelModuleName)
|
30
|
+
else
|
31
|
+
tLModel = first_model
|
32
|
+
end
|
33
|
+
|
34
|
+
abort "ERROR: create_vhdl_file(#{topLevelModuleName}): cannot find top level model" if tLModel.nil?
|
35
|
+
|
36
|
+
update_clocks()
|
37
|
+
|
38
|
+
models.each do |model|
|
39
|
+
model.create_vhdl_file(model == tLModel)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
class Model
|
45
|
+
|
46
|
+
def create_vhdl_file (topLevel = false)
|
47
|
+
return if @isBlackBox
|
48
|
+
fileName = @name + '.vhd'
|
49
|
+
file = File.open(fileName, 'w')
|
50
|
+
|
51
|
+
to_vhdl(toplevel: topLevel, stream: file)
|
52
|
+
|
53
|
+
file.close
|
54
|
+
STDERR.puts "File \"#{fileName}\" written."
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
def to_vhdl (topLevel: false, stream: "")
|
59
|
+
iNames = @inputs.collect{|io| io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')}
|
60
|
+
oNames = @outputs.collect{|io| io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')}
|
61
|
+
just = [([0] + iNames.collect{|name| name.length}).max + 3, ([0] + oNames.collect{|name| name.length}).max + 4].max
|
62
|
+
entityStr = iNames.collect{|name| "#{(name + '_in').ljust(just)} : in std_ulogic;"} +
|
63
|
+
oNames.collect{|name| "#{(name + '_out').ljust(just)} : out std_ulogic;"}
|
64
|
+
|
65
|
+
stream << "\nlibrary IEEE;\nuse IEEE.STD_LOGIC_1164.ALL;\n\n\nentity #{@name.upcase} is\n\tport ( "
|
66
|
+
stream << entityStr.join("\n\t ").chop
|
67
|
+
stream << ");\nend #{name.upcase};\n\n\n"
|
68
|
+
stream << "architecture blif of #{name.upcase} is\n\n"
|
69
|
+
|
70
|
+
just = @nets.collect{|net| net.name.length}.max
|
71
|
+
|
72
|
+
@clocks.reject{|clkname| @nets.collect{|net| net.name}.include?(clkname)}.each do |name|
|
73
|
+
stream << "\tsignal #{name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'').ljust(just)} : std_ulogic;\n"
|
74
|
+
end
|
75
|
+
@nets.each do |net|
|
76
|
+
name = net.name
|
77
|
+
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"
|
78
|
+
end
|
79
|
+
|
80
|
+
stream << "\nbegin\n\n"
|
81
|
+
|
82
|
+
@inputs.each do |io|
|
83
|
+
stream << "\t#{io.net.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')} <= #{io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_in'};\n"
|
84
|
+
end
|
85
|
+
stream <<("\n") unless @inputs.empty?
|
86
|
+
@outputs.each do |io|
|
87
|
+
stream << "\t#{io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_out'} <= #{io.net.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')};\n"
|
88
|
+
end
|
89
|
+
stream <<("\n") unless @outputs.empty?
|
90
|
+
|
91
|
+
stream <<("\n")
|
92
|
+
|
93
|
+
latches = @components.select{|comp| comp.kind_of?(BlifUtils::Netlist::Latch)}
|
94
|
+
unless latches.empty? then
|
95
|
+
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
|
96
|
+
|
97
|
+
clks.each do |clkname|
|
98
|
+
stream << "\tprocess(#{clkname.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')})\n\tbegin\n\t\tif rising_edge(#{clkname.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')}) then\n"
|
99
|
+
latches.select{|latch| latch.ctrlSig != nil and (latch.ctrlSig == clkname or latch.ctrlSig.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') == clkname)}.each do |latch|
|
100
|
+
stream << "\t\t\t#{latch.output.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')} <= #{latch.input.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')};\n"
|
101
|
+
end
|
102
|
+
stream << "\t\tend if;\n\tend process;\n"
|
103
|
+
end
|
104
|
+
|
105
|
+
if clks.empty? then
|
106
|
+
stream << "\n\tprocess(_clk)\n\tbegin\n\t\tif rising_edge(_clk) then\n"
|
107
|
+
latches.select{|latch| latch.ctrlSig.nil?}.each do |latch|
|
108
|
+
stream << "\n\t\t\t#{latch.output.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')} <= #{latch.input.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')};\n"
|
109
|
+
end
|
110
|
+
stream << "\t\tend if;\n\tend process;\n"
|
111
|
+
end
|
112
|
+
stream <<("\n")
|
113
|
+
end
|
114
|
+
|
115
|
+
gates = @components.select{|comp| comp.kind_of?(BlifUtils::Netlist::LogicGate)}
|
116
|
+
gates.each do |gate|
|
117
|
+
next if gate.is_constant?
|
118
|
+
oname = gate.output.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')
|
119
|
+
inames = gate.inputs.collect{|net| net.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')}
|
120
|
+
stream << "\t#{oname} <= "
|
121
|
+
polarity = gate.singleOutputCoverList.collect{|inputs_output| inputs_output[1]}.uniq
|
122
|
+
if polarity.length != 1 or (polarity[0] != 0 and polarity[0] != 1) then
|
123
|
+
abort "ERROR: Output cover list of gate \"#{oname}\" contains '1' and '0' as output!"
|
124
|
+
end
|
125
|
+
stream <<("not(") if polarity[0] == 0
|
126
|
+
socvlst = gate.singleOutputCoverList.collect { |cvlst|
|
127
|
+
cvlstArr = []
|
128
|
+
cvlst[0].each_with_index { |val, i|
|
129
|
+
if val == 1 then
|
130
|
+
cvlstArr << inames[i]
|
131
|
+
elsif val == 0 then
|
132
|
+
cvlstArr << "not(#{inames[i]})"
|
133
|
+
#else
|
134
|
+
# cvlstArr << "'1'"
|
135
|
+
end
|
136
|
+
}
|
137
|
+
'(' + cvlstArr.join(' and ') + ')'
|
138
|
+
}.join(" or\n\t#{' '*oname.length} ")
|
139
|
+
stream << socvlst
|
140
|
+
stream <<(")") if polarity[0] == 0
|
141
|
+
stream <<(";\n")
|
142
|
+
end
|
143
|
+
stream <<("\n") unless gates.empty?
|
144
|
+
|
145
|
+
constants = gates.select{|gate| gate.is_constant?}
|
146
|
+
constants.each do |cstGate|
|
147
|
+
oname = cstGate.output.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')
|
148
|
+
if cstGate.singleOutputCoverList.empty? or cstGate.singleOutputCoverList[0][2] == 0 then
|
149
|
+
stream << "\t#{oname} <= '0';\n"
|
150
|
+
else
|
151
|
+
stream << "\t#{oname} <= '1';\n"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
stream <<("\n") unless constants.empty?
|
155
|
+
|
156
|
+
@components.select{|comp| comp.kind_of?(BlifUtils::Netlist::SubCircuit)}.each_with_index do |subckt, i|
|
157
|
+
stream << "\tCMPINST#{i}: entity work.#{subckt.modelName.upcase}\n\tport map ( "
|
158
|
+
|
159
|
+
iNames = subckt.inputFormalAcutalList.collect{|io| io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_in'}
|
160
|
+
oNames = subckt.outputFormalAcutalList.collect{|io| io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_out'}
|
161
|
+
just = ([0] + iNames.collect{|name| name.length} + oNames.collect{|name| name.length}).max
|
162
|
+
|
163
|
+
portmapStr = subckt.inputFormalAcutalList.collect{|io| "#{(io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_in').ljust(just)} => #{io.net.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')},"} +
|
164
|
+
subckt.outputFormalAcutalList.collect{|io| "#{(io.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'') + '_out').ljust(just)} => #{io.net.name.gsub(/(\[|\])/, '_').gsub(/_$/,'').gsub(/^_/,'')},"}
|
165
|
+
|
166
|
+
stream << portmapStr.join("\n\t ").chop
|
167
|
+
stream << ");\n\n"
|
168
|
+
end
|
169
|
+
|
170
|
+
stream << "end blif;\n\n"
|
171
|
+
|
172
|
+
return stream
|
173
|
+
end
|
174
|
+
|
175
|
+
end # BlifUtils::Netlist::Model
|
176
|
+
|
177
|
+
end # BlifUtils::Netlist
|
178
|
+
|
179
|
+
end # BlifUtils
|
180
|
+
|
@@ -0,0 +1,257 @@
|
|
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/parser.rb'
|
21
|
+
require 'blifutils/ast.rb'
|
22
|
+
require 'blifutils/netlist.rb'
|
23
|
+
|
24
|
+
|
25
|
+
module BlifUtils
|
26
|
+
|
27
|
+
module Elaborator
|
28
|
+
|
29
|
+
def self.elaborate_netlist (ast, quiet: false)
|
30
|
+
modelDeclarations = gather_model_declarations(ast)
|
31
|
+
|
32
|
+
netlist = BlifUtils::Netlist.new
|
33
|
+
models = ast.modelList.collect do |modelAst|
|
34
|
+
puts "Elaborating model \"#{modelAst.name}\"..." unless quiet
|
35
|
+
netlist.add_model(elaborate_model(modelAst, modelDeclarations, quiet: quiet))
|
36
|
+
end
|
37
|
+
|
38
|
+
return netlist
|
39
|
+
end # BlifUtils::Elaborator::elaborate_netlist
|
40
|
+
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
|
45
|
+
class ModelDeclaration
|
46
|
+
attr_reader :name
|
47
|
+
attr_reader :inputs #[String, ... ]
|
48
|
+
attr_reader :outputs #[String, ... ]
|
49
|
+
|
50
|
+
def initialize (name, inputs, outputs)
|
51
|
+
@name = name
|
52
|
+
@inputs = inputs
|
53
|
+
@outputs = outputs
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
str = "Model \"#{@name}\"\n"
|
58
|
+
str += " Inputs: #{@inputs.join(', ')}\n"
|
59
|
+
str += " Outputs: #{@outputs.join(', ')}\n"
|
60
|
+
return str
|
61
|
+
end
|
62
|
+
end # BlifUtils::Elaborator::ModelDeclaration
|
63
|
+
|
64
|
+
|
65
|
+
def self.gather_model_declarations (ast)
|
66
|
+
modelDeclarations = ast.modelList.collect do |modelAst|
|
67
|
+
inputs = []
|
68
|
+
modelAst.header.select{|headerElement| headerElement.class == BlifUtils::AST::ModelHeaderElementInputs}.each do |headerInput|
|
69
|
+
headerInput.inputList.each do |inputStr|
|
70
|
+
inputs << inputStr
|
71
|
+
end
|
72
|
+
end
|
73
|
+
outputs = []
|
74
|
+
modelAst.header.select{|headerElement| headerElement.class == BlifUtils::AST::ModelHeaderElementOutputs}.each do |headerOutput|
|
75
|
+
headerOutput.outputList.each do |outputStr|
|
76
|
+
outputs << outputStr
|
77
|
+
end
|
78
|
+
end
|
79
|
+
BlifUtils::Elaborator::ModelDeclaration.new(modelAst.name, inputs, outputs)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Check that each model is defined only once #
|
83
|
+
(0 ... (modelDeclarations.length - 1)).each do |i|
|
84
|
+
md1name = modelDeclarations[i].name
|
85
|
+
((i+1) ... modelDeclarations.length).each do |j|
|
86
|
+
md2name = modelDeclarations[j].name
|
87
|
+
if md1name == md2name then
|
88
|
+
abort "ERROR: Model \"#{md1name}\" is defined more than once"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
return modelDeclarations
|
94
|
+
end # BlifUtils::Elaborator::gather_model_declarations
|
95
|
+
|
96
|
+
|
97
|
+
def self.elaborate_model (modelAst, modelDeclarations, quiet: false)
|
98
|
+
name = modelAst.name
|
99
|
+
inputs = []
|
100
|
+
outputs = []
|
101
|
+
components = []
|
102
|
+
nets = []
|
103
|
+
clocks = []
|
104
|
+
|
105
|
+
# Create inputs #
|
106
|
+
modelAst.header.select{|headerElement| headerElement.class == BlifUtils::AST::ModelHeaderElementInputs}.each do |headerInput|
|
107
|
+
headerInput.inputList.each do |inputStr|
|
108
|
+
if inputs.include?(inputStr) then
|
109
|
+
abort "ERROR: In model \"#{name}\": input \"#{inputStr}\" is declared more than once"
|
110
|
+
end
|
111
|
+
inputs << BlifUtils::Netlist::IO.new(inputStr, inputStr)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Create outputs #
|
116
|
+
modelAst.header.select{|headerElement| headerElement.class == BlifUtils::AST::ModelHeaderElementOutputs}.each do |headerOutput|
|
117
|
+
headerOutput.outputList.each do |outputStr|
|
118
|
+
if outputs.include?(outputStr) then
|
119
|
+
abort "ERROR: In model \"#{name}\": output \"#{outputStr}\" is declared more than once"
|
120
|
+
end
|
121
|
+
outputs << BlifUtils::Netlist::IO.new(outputStr, outputStr)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
unless modelAst.commands.index{|commandAst| commandAst.class == BlifUtils::AST::BlackBox}.nil? then
|
126
|
+
return BlifUtils::Netlist::Model.new(name, inputs, outputs, components, nets, clocks, true)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Create components #
|
130
|
+
modelAst.commands.each do |commandAst|
|
131
|
+
if commandAst.class == BlifUtils::AST::LogicGate then
|
132
|
+
components << BlifUtils::Netlist::LogicGate.new(commandAst.inputs, commandAst.output, commandAst.single_output_cover_list)
|
133
|
+
elsif commandAst.class == BlifUtils::AST::GenericLatch then
|
134
|
+
components << BlifUtils::Netlist::Latch.new(commandAst.input, commandAst.output, commandAst.initValue, commandAst.ctrlType, commandAst.ctrlSig)
|
135
|
+
elsif commandAst.class == BlifUtils::AST::ModelReference then
|
136
|
+
modelDeclarationIndex = modelDeclarations.index{|md| md.name == commandAst.modelName}
|
137
|
+
if modelDeclarationIndex.nil? then
|
138
|
+
abort "ERROR: In model \"#{name}\": model \"#{commandAst.modelName}\" is referenced but is not defined in the parsed blif files"
|
139
|
+
end
|
140
|
+
modelDeclaration = modelDeclarations[modelDeclarationIndex]
|
141
|
+
inputFormalAcutalList = []
|
142
|
+
outputFormalAcutalList = []
|
143
|
+
commandAst.formalAcutalList.each do |form_act|
|
144
|
+
newIO = BlifUtils::Netlist::IO.new(form_act[0], form_act[1])
|
145
|
+
if modelDeclaration.inputs.include?(newIO.name) then
|
146
|
+
inputFormalAcutalList << newIO
|
147
|
+
elsif modelDeclaration.outputs.include?(newIO.name) then
|
148
|
+
outputFormalAcutalList << newIO
|
149
|
+
else
|
150
|
+
abort "ERROR: In model \"#{name}\": model \"#{commandAst.modelName}\" is referenced with formal \"#{newIO.name}\" which is neither an input nor an output of this referenced model"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
components << BlifUtils::Netlist::SubCircuit.new(commandAst.modelName, inputFormalAcutalList, outputFormalAcutalList)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Create all nets from their drivers #
|
158
|
+
inputs.each do |iIO|
|
159
|
+
newNet = BlifUtils::Netlist::Net.new(iIO.net, :input, [], true, false)
|
160
|
+
nets << newNet
|
161
|
+
iIO.net = newNet
|
162
|
+
end
|
163
|
+
components.reject{|comp| comp.isSubcircuit?}.each do |component|
|
164
|
+
newNet = BlifUtils::Netlist::Net.new(component.output, component, [], false, false)
|
165
|
+
if nets.collect{|net| net.name}.include?(newNet.name) then
|
166
|
+
abort "ERROR: In model \"#{name}\": net \"#{newNet.name}\" has more than one driver"
|
167
|
+
end
|
168
|
+
nets << newNet
|
169
|
+
component.output = newNet
|
170
|
+
end
|
171
|
+
components.select{|comp| comp.isSubcircuit?}.each do |subcircuit|
|
172
|
+
subcircuit.outputFormalAcutalList.each do |outIO|
|
173
|
+
newNet = BlifUtils::Netlist::Net.new(outIO.net, subcircuit, [], false, false)
|
174
|
+
if nets.collect{|net| net.name}.include?(newNet.name) then
|
175
|
+
abort "ERROR: In model \"#{name}\": net \"#{newNet.name}\" has more than one driver"
|
176
|
+
end
|
177
|
+
nets << newNet
|
178
|
+
outIO.net = newNet
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Update nets fanouts #
|
183
|
+
outputs.each_with_index do |oIO, i|
|
184
|
+
index = nets.index{|net| net.name == oIO.name}
|
185
|
+
if index.nil? then
|
186
|
+
abort "ERROR: In model \"#{name}\": output \"#{oIO.name}\" has no driver"
|
187
|
+
end
|
188
|
+
nets[index].fanouts << BlifUtils::Netlist::Fanout.new(:output, i)
|
189
|
+
nets[index].isOutput = true
|
190
|
+
oIO.net = nets[index]
|
191
|
+
end
|
192
|
+
components.select{|comp| comp.isLatch?}.each do |latch|
|
193
|
+
index = nets.index{|net| net.name == latch.input}
|
194
|
+
if index.nil? then
|
195
|
+
abort "ERROR: In model \"#{name}\": input \"#{latch.input}\" from latch \"#{latch.output.name}\" has no driver"
|
196
|
+
end
|
197
|
+
nets[index].fanouts << BlifUtils::Netlist::Fanout.new(latch, 0)
|
198
|
+
latch.input = nets[index]
|
199
|
+
end
|
200
|
+
components.select{|comp| comp.isGate?}.each do |gate|
|
201
|
+
gate.inputs.each_with_index do |gin, i|
|
202
|
+
index = nets.index{|net| net.name == gin}
|
203
|
+
if index.nil? then
|
204
|
+
abort "ERROR: In model \"#{name}\": input \"#{gin}\" from gate \"#{gate.output.name}\" has no driver"
|
205
|
+
end
|
206
|
+
nets[index].fanouts << BlifUtils::Netlist::Fanout.new(gate, i)
|
207
|
+
gate.inputs[i] = nets[index]
|
208
|
+
end
|
209
|
+
end
|
210
|
+
components.select{|comp| comp.isSubcircuit?}.each do |subcircuit|
|
211
|
+
subcircuit.inputFormalAcutalList.each_with_index do |iIO, i|
|
212
|
+
index = nets.index{|net| net.name == iIO.net}
|
213
|
+
if index.nil? then
|
214
|
+
abort "ERROR: In model \"#{name}\": input \"#{iIO}\" (formal \"#{iIO.name}\" from reference model \"#{subcircuit.modelName}\" has no driver"
|
215
|
+
end
|
216
|
+
nets[index].fanouts << BlifUtils::Netlist::Fanout.new(subcircuit, i)
|
217
|
+
iIO.net = nets[index]
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
clocks = components.select{|comp| comp.isLatch?}.collect{|latch| latch.ctrlSig}.reject{|el| el.nil?}.uniq
|
222
|
+
|
223
|
+
# Check that each net has at least one fanout #
|
224
|
+
nets.each do |net|
|
225
|
+
if net.fanouts.empty? and not(clocks.include?(net.name)) then
|
226
|
+
STDERR.puts "WARNING: In model \"#{name}\": net \"#{net.name}\" has no fanouts" unless quiet
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
return BlifUtils::Netlist::Model.new(name, inputs, outputs, components, nets, clocks)
|
231
|
+
end # BlifUtils::Elaborator::elaborate_model
|
232
|
+
|
233
|
+
end # BlifUtils::Elaborator
|
234
|
+
|
235
|
+
|
236
|
+
def self.read(fileName, quiet: false)
|
237
|
+
ast = BlifUtils::Parser.parse(fileName, quiet: quiet)
|
238
|
+
netlist = BlifUtils::Elaborator.elaborate_netlist(ast, quiet: quiet)
|
239
|
+
return netlist
|
240
|
+
end # BlifUtils::read
|
241
|
+
|
242
|
+
end # BlifUtils
|
243
|
+
|
244
|
+
|
245
|
+
|
246
|
+
if __FILE__ == $0
|
247
|
+
if ARGV.length == 0
|
248
|
+
puts "You must provide the file to process as argument!"
|
249
|
+
exit
|
250
|
+
end
|
251
|
+
|
252
|
+
ast = BlifUtils::Parser.parse(ARGV[0])
|
253
|
+
|
254
|
+
netlist = BlifUtils::Elaborator.elaborate_netlist(ast)
|
255
|
+
puts netlist.analyze
|
256
|
+
end
|
257
|
+
|
@@ -0,0 +1,406 @@
|
|
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
|
+
|
22
|
+
|
23
|
+
module BlifUtils
|
24
|
+
|
25
|
+
module NetlistGraph
|
26
|
+
|
27
|
+
class Graph
|
28
|
+
attr_accessor :vertices
|
29
|
+
attr_reader :fromModel
|
30
|
+
|
31
|
+
def initialize (vertices = [], model = nil)
|
32
|
+
@vertices = vertices
|
33
|
+
@fromModel = model
|
34
|
+
check unless @vertices.empty?
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def get_graph_without_input_output_reg_cst_modinst
|
39
|
+
newGraph = clone
|
40
|
+
newGraph.vertices.delete_if do |vertice|
|
41
|
+
vertice.component == :input or
|
42
|
+
vertice.component == :output or
|
43
|
+
vertice.component.class == BlifUtils::Netlist::SubCircuit or
|
44
|
+
vertice.component.class == BlifUtils::Netlist::Latch or
|
45
|
+
(vertice.component.class == BlifUtils::Netlist::LogicGate and vertice.component.is_constant?)
|
46
|
+
end
|
47
|
+
newGraph.vertices.each do |vertice|
|
48
|
+
vertice.remove_input_output_reg_cst_modinst_references
|
49
|
+
end
|
50
|
+
return newGraph
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def clone
|
55
|
+
vertices = @vertices.collect{|vertice| vertice.clone}
|
56
|
+
# Update successors and predecessors references to cloned vertices
|
57
|
+
vertices.each do |vertice|
|
58
|
+
(0 ... vertice.successors.length).each do |i|
|
59
|
+
next if vertice.successors[i] == :output
|
60
|
+
successorVertice = vertices.select{|vever| vever.component == vertice.successors[i].component}
|
61
|
+
if successorVertice.empty? then
|
62
|
+
abort "ERROR: While cloning netlist graph: successor #{vertice.successors[i].component} of component #{vertice.component} has no reference in the graph."
|
63
|
+
end
|
64
|
+
if successorVertice.length > 1 then
|
65
|
+
abort "ERROR: While cloning netlist graph: successor #{vertice.successors[i].component} of component #{vertice.component} has more than one reference in the graph."
|
66
|
+
end
|
67
|
+
vertice.successors[i] = successorVertice[0]
|
68
|
+
end
|
69
|
+
(0 ... vertice.predecessors.length).each do |i|
|
70
|
+
next if vertice.predecessors[i] == :input
|
71
|
+
predecessorVertice = vertices.select{|vever| vever.component == vertice.predecessors[i].component}
|
72
|
+
if predecessorVertice.empty? then
|
73
|
+
abort "ERROR: While cloning netlist graph: predecessor #{vertice.predecessors[i].component} of component #{vertice.component} has no reference in the graph."
|
74
|
+
end
|
75
|
+
if predecessorVertice.length > 1 then
|
76
|
+
abort "ERROR: While cloning netlist graph: predecessor #{vertice.predecessors[i].component} of component #{vertice.component} has more than one reference in the graph."
|
77
|
+
end
|
78
|
+
vertice.predecessors[i] = predecessorVertice[0]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
newGraph = BlifUtils::NetlistGraph::Graph.new(vertices, @fromModel)
|
82
|
+
return newGraph
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def self.create_from_model (model)
|
87
|
+
vertices = BlifUtils::NetlistGraph::Vertice.get_vertices_from_model(model)
|
88
|
+
###vertices.each{|ver| puts "#{ver.component} #{ver.component.class.name} #{ver.component.label}"}
|
89
|
+
# Update successors and predecessors references to components by references to Vertices
|
90
|
+
vertices.each do |vertice|
|
91
|
+
(0 ... vertice.successors.length).each do |i|
|
92
|
+
next if vertice.successors[i] == :output
|
93
|
+
successorVertice = vertices.select{|vever| vever.component == vertice.successors[i]}
|
94
|
+
if successorVertice.empty? then
|
95
|
+
abort "ERROR: While elaborating netlist graph: successor #{vertice.successors[i]} of component #{vertice.component} has no reference in the graph."
|
96
|
+
end
|
97
|
+
if successorVertice.length > 1 then
|
98
|
+
abort "ERROR: While elaborating netlist graph: successor #{vertice.successors[i]} of component #{vertice.component} has more than one reference in the graph."
|
99
|
+
end
|
100
|
+
vertice.successors[i] = successorVertice[0]
|
101
|
+
end
|
102
|
+
(0 ... vertice.predecessors.length).each do |i|
|
103
|
+
next if vertice.predecessors[i] == :input
|
104
|
+
predecessorVertice = vertices.select{|vever| vever.component == vertice.predecessors[i]}
|
105
|
+
if predecessorVertice.empty? then
|
106
|
+
abort "ERROR: While elaborating netlist graph: predecessor #{vertice.predecessors[i]} of component #{vertice.component} has no reference in the graph."
|
107
|
+
end
|
108
|
+
if predecessorVertice.length > 1 then
|
109
|
+
abort "ERROR: While elaborating netlist graph: predecessor #{vertice.predecessors[i]} of component #{vertice.component} has more than one reference in the graph."
|
110
|
+
end
|
111
|
+
vertice.predecessors[i] = predecessorVertice[0]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
newGraph = BlifUtils::NetlistGraph::Graph.new(vertices, model)
|
115
|
+
return newGraph
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
def to_graphviz
|
120
|
+
@vertices.each_with_index{|vert, i| vert.id = i}
|
121
|
+
str = "digraph #{@fromModel.nil? ? '' : @fromModel.name} {\n"
|
122
|
+
@vertices.each do |vertice|
|
123
|
+
str += "\t#{vertice.id} [label=\"#{vertice.to_s}\""
|
124
|
+
if vertice.component == :input or
|
125
|
+
vertice.component == :output or
|
126
|
+
vertice.component.class == BlifUtils::Netlist::Latch or
|
127
|
+
(vertice.component.class == BlifUtils::Netlist::LogicGate and vertice.component.is_constant?) then
|
128
|
+
str += ",shape=box"
|
129
|
+
end
|
130
|
+
str += "];\n"
|
131
|
+
end
|
132
|
+
@vertices.each do |vertice|
|
133
|
+
vertice.successors.each do |successor|
|
134
|
+
next if successor.class == Symbol
|
135
|
+
str += "\t#{vertice.id} -> "
|
136
|
+
str += "#{successor.id};\n"
|
137
|
+
end
|
138
|
+
if vertice.successors.empty? and vertice.predecessors.empty? then
|
139
|
+
str += "\t#{vertice.id};\n"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
str += "}\n"
|
143
|
+
return str
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
def check
|
148
|
+
# Check that each component is in only one vertice
|
149
|
+
allComponents = @vertices.collect{|vertice| vertice.component}
|
150
|
+
allComponents.each do |component|
|
151
|
+
if allComponents.select{|compo| compo == component}.length > 1 then
|
152
|
+
abort "ERROR: Checking graph: component #{component} has more than one corresponding vertice."
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
@vertices.each do |vertice|
|
157
|
+
# Check that each successor has the current vertice as predecessor
|
158
|
+
vertice.successors.each do |successor|
|
159
|
+
next if successor == :output
|
160
|
+
predecessorVertices = successor.predecessors.select{|prede| prede == vertice}
|
161
|
+
if predecessorVertices.empty? then
|
162
|
+
abort "ERROR: While elaborating netlist graph: successor #{successor.component} of component #{vertice.component} has no reference to component #{vertice.component} as predecessor."
|
163
|
+
end
|
164
|
+
if predecessorVertices.length > 1 then
|
165
|
+
abort "ERROR: While elaborating netlist graph: successor #{successor.component} of component #{vertice.component} has more than one reference to component #{vertice.component} as predecessor."
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Check that each predecessor has the current vertice as successor
|
170
|
+
vertice.predecessors.each do |predecessor|
|
171
|
+
next if predecessor == :input
|
172
|
+
successorVertices = predecessor.successors.select{|succe| succe == vertice}
|
173
|
+
if successorVertices.empty? then
|
174
|
+
abort "ERROR: While elaborating netlist graph: predecessor #{predecessor.component} of component #{vertice.component} has no reference to component #{vertice.component} as successor."
|
175
|
+
end
|
176
|
+
if successorVertices.length > 1 then
|
177
|
+
abort "ERROR: While elaborating netlist graph: predecessor #{predecessor.component} of component #{vertice.component} has more than one reference to component #{vertice.component} as successor."
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
def get_connected_subgraphs
|
185
|
+
dags = []
|
186
|
+
|
187
|
+
verticePool = @vertices.collect{|vert| vert}
|
188
|
+
|
189
|
+
until verticePool.empty? do
|
190
|
+
newDAGvertices = []
|
191
|
+
# Pick up a vertice
|
192
|
+
BlifUtils::NetlistGraph::Graph.get_connected_vertices_recursive(verticePool[0], newDAGvertices, verticePool)
|
193
|
+
dags << BlifUtils::NetlistGraph::Graph.new(newDAGvertices, @fromModel)
|
194
|
+
end
|
195
|
+
|
196
|
+
return dags
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
def is_acyclic?
|
201
|
+
# If a directed graph is acyclic, it has at least a node with no successors,
|
202
|
+
# if there is no such node, the graph cannot be acyclic.
|
203
|
+
# If we remove a node with no successors, the graph is still acyclic as it leaves new nodes without successors
|
204
|
+
|
205
|
+
# We make a copy of the graph as we will modigy it and its nodes
|
206
|
+
graph = self.clone
|
207
|
+
|
208
|
+
until graph.vertices.empty? do
|
209
|
+
# Find a leaf, e.g. a node with no successors
|
210
|
+
leafs = graph.vertices.select{|vertice| vertice.successors.empty?}
|
211
|
+
return false if leafs.empty?
|
212
|
+
# Remove the leaf from the graph
|
213
|
+
leaf = leafs[0]
|
214
|
+
graph.vertices.delete(leaf)
|
215
|
+
leaf.predecessors.each do |predecessor|
|
216
|
+
predecessor.successors.delete(leaf)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
return true
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
def assign_layers_to_vertices
|
225
|
+
@vertices.each{|vertice| vertice.layer = nil}
|
226
|
+
v_remainder_set = @vertices.collect{|vert| vert}
|
227
|
+
u_new_set = []
|
228
|
+
u_set_length = 0
|
229
|
+
z_set = []
|
230
|
+
currentLayer = 1
|
231
|
+
while u_set_length != @vertices.length do
|
232
|
+
selectedVertice = nil
|
233
|
+
v_remainder_set.each do |vertice|
|
234
|
+
unless vertice.successors.collect{|suc| suc.layer != nil and suc.layer < currentLayer}.include?(false)
|
235
|
+
selectedVertice = vertice
|
236
|
+
break
|
237
|
+
end
|
238
|
+
end
|
239
|
+
if selectedVertice.nil? then
|
240
|
+
currentLayer += 1
|
241
|
+
z_set += u_new_set
|
242
|
+
u_new_set = []
|
243
|
+
else
|
244
|
+
selectedVertice.layer = currentLayer
|
245
|
+
u_set_length += 1
|
246
|
+
u_new_set << selectedVertice
|
247
|
+
v_remainder_set.delete(selectedVertice)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
|
253
|
+
private
|
254
|
+
|
255
|
+
|
256
|
+
def self.get_connected_vertices_recursive (vertice, newDAGvertices, verticePool)
|
257
|
+
return if newDAGvertices.include?(vertice)
|
258
|
+
newDAGvertices << vertice
|
259
|
+
raise 'Mah! Que passa ?' unless verticePool.include?(vertice)
|
260
|
+
verticePool.delete(vertice)
|
261
|
+
vertice.predecessors.each do |predecessor|
|
262
|
+
BlifUtils::NetlistGraph::Graph.get_connected_vertices_recursive(predecessor, newDAGvertices, verticePool)
|
263
|
+
end
|
264
|
+
vertice.successors.each do |successor|
|
265
|
+
BlifUtils::NetlistGraph::Graph.get_connected_vertices_recursive(successor, newDAGvertices, verticePool)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
end # BlifUtils::NetlistGraph::Graph
|
270
|
+
|
271
|
+
|
272
|
+
class Vertice
|
273
|
+
attr_accessor :component
|
274
|
+
attr_accessor :successors
|
275
|
+
attr_accessor :predecessors
|
276
|
+
attr_accessor :layer
|
277
|
+
attr_accessor :id
|
278
|
+
|
279
|
+
def initialize
|
280
|
+
@component = nil
|
281
|
+
@successors = []
|
282
|
+
@predecessors = []
|
283
|
+
@layer = nil
|
284
|
+
@id = -1
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
def clone
|
289
|
+
newVertice = BlifUtils::NetlistGraph::Vertice.new
|
290
|
+
newVertice.component = @component
|
291
|
+
newVertice.layer = @layer
|
292
|
+
newVertice.successors = @successors.collect{|suc| suc}
|
293
|
+
newVertice.predecessors = @predecessors.collect{|pred| pred}
|
294
|
+
newVertice.id = @id
|
295
|
+
return newVertice
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
def remove_input_output_reg_cst_modinst_references
|
300
|
+
@successors.delete_if do |successor|
|
301
|
+
successor == :output or
|
302
|
+
successor.component.class == BlifUtils::Netlist::Latch
|
303
|
+
end
|
304
|
+
@predecessors.delete_if do |predecessor|
|
305
|
+
predecessor == :input or
|
306
|
+
predecessor.component.class == BlifUtils::Netlist::Latch or
|
307
|
+
(predecessor.component.class == BlifUtils::Netlist::LogicGate and predecessor.component.is_constant?)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
|
312
|
+
def to_s
|
313
|
+
return "#{@component.class.name.split('::')[-1]} (#{@component.output.name})#{@layer.nil? ? '' : " [L#{@layer}]"}"
|
314
|
+
end
|
315
|
+
|
316
|
+
|
317
|
+
def self.create_from_model_component (component, model)
|
318
|
+
newVertice = BlifUtils::NetlistGraph::Vertice.new
|
319
|
+
|
320
|
+
newVertice.component = component
|
321
|
+
component.inputs.each do |net|
|
322
|
+
driverCompo = net.driver
|
323
|
+
newVertice.predecessors << driverCompo unless newVertice.predecessors.include?(driverCompo)
|
324
|
+
end
|
325
|
+
|
326
|
+
component.output.fanouts.each do |fanout|
|
327
|
+
fanoutCompo = fanout.target
|
328
|
+
newVertice.successors << fanoutCompo unless newVertice.successors.include?(fanoutCompo)
|
329
|
+
end
|
330
|
+
|
331
|
+
return newVertice
|
332
|
+
end
|
333
|
+
|
334
|
+
|
335
|
+
def self.get_vertices_from_model (model)
|
336
|
+
vertices = model.components.collect{|component| self.create_from_model_component(component, model)}
|
337
|
+
return vertices
|
338
|
+
end
|
339
|
+
|
340
|
+
end # BlifUtils::NetlistGraph::Vertice
|
341
|
+
|
342
|
+
end # BlifUtils::NetlistGraph
|
343
|
+
|
344
|
+
|
345
|
+
class Netlist
|
346
|
+
|
347
|
+
class Model
|
348
|
+
|
349
|
+
def simulation_components_to_schedule_stack (withOutputGraphviz: false, quiet: false)
|
350
|
+
unless is_self_contained? then
|
351
|
+
raise "#{self.class.name}##{__method__.to_s}() requires that the model has no model reference in it. You must flatten the model before."
|
352
|
+
end
|
353
|
+
puts "Generating graph from model components..." unless quiet
|
354
|
+
graphFull = BlifUtils::NetlistGraph::Graph.create_from_model(self)
|
355
|
+
print "Extracting connected subgraphs... " unless quiet
|
356
|
+
graphDAGs = graphFull.get_graph_without_input_output_reg_cst_modinst
|
357
|
+
dags = graphDAGs.get_connected_subgraphs
|
358
|
+
puts "#{dags.length} subgraph#{dags.length > 1 ? 's' : ''} found" unless quiet
|
359
|
+
|
360
|
+
print "Checking that there are no cycles in subgraphs... " unless quiet
|
361
|
+
# Check that all subgraphs are acyclic
|
362
|
+
dags.each_with_index do |dag, i|
|
363
|
+
unless dag.is_acyclic? then
|
364
|
+
str = "\nERROR: There is a combinatorial loop.\n (See cycle in file \"#{@name}_graph_DAG_#{i}.gv\")\n This subgraph includes components:\n"
|
365
|
+
dag.vertices.each do |vertice|
|
366
|
+
str += " Component #{vertice.to_s}\n"
|
367
|
+
end
|
368
|
+
|
369
|
+
abort str
|
370
|
+
end
|
371
|
+
end
|
372
|
+
puts "Ok" unless quiet
|
373
|
+
|
374
|
+
# Do graph layering
|
375
|
+
puts "Layering subgraphs..." unless quiet
|
376
|
+
dags.each_with_index do |dag, i|
|
377
|
+
dag.assign_layers_to_vertices
|
378
|
+
File.write("#{@name}_graph_DAG_#{i}.gv", dag.to_graphviz) if withOutputGraphviz
|
379
|
+
end
|
380
|
+
|
381
|
+
File.write("#{@name}_graph_subgraphs.gv", graphDAGs.to_graphviz) if withOutputGraphviz
|
382
|
+
graphDAGs.vertices.each do |vertice|
|
383
|
+
ind = graphFull.vertices.index{|vert| vert.component == vertice.component}
|
384
|
+
graphFull.vertices[ind].layer = vertice.layer unless ind.nil?
|
385
|
+
end
|
386
|
+
File.write("#{@name}_graph_full.gv", graphFull.to_graphviz) if withOutputGraphviz
|
387
|
+
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
|
388
|
+
|
389
|
+
puts "Writing static schedule for component simulation..." unless quiet
|
390
|
+
componentSchedulingStack = []
|
391
|
+
dags.each do |dag|
|
392
|
+
dag.vertices.sort{|verta, vertb| vertb.layer <=> verta.layer}.each{|vert| componentSchedulingStack << vert.component}
|
393
|
+
end
|
394
|
+
unless componentSchedulingStack.index{|comp| comp.class != BlifUtils::Netlist::LogicGate}.nil? then
|
395
|
+
raise "merde"
|
396
|
+
end
|
397
|
+
|
398
|
+
return componentSchedulingStack
|
399
|
+
end
|
400
|
+
|
401
|
+
end # BlifUtils::Netlist::Model
|
402
|
+
|
403
|
+
end # BlifUtils::Netlist
|
404
|
+
|
405
|
+
end # BlifUtils
|
406
|
+
|