blifutils 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|