1 |
3 |
feddischso |
###############################################################
|
2 |
|
|
#
|
3 |
|
|
# File: component.rb
|
4 |
|
|
#
|
5 |
|
|
# Author: Christian Hättich
|
6 |
|
|
#
|
7 |
|
|
# Project: System-On-Chip Maker
|
8 |
|
|
#
|
9 |
|
|
# Target: Linux / Windows / Mac
|
10 |
|
|
#
|
11 |
|
|
# Language: ruby
|
12 |
|
|
#
|
13 |
|
|
#
|
14 |
|
|
###############################################################
|
15 |
|
|
#
|
16 |
|
|
#
|
17 |
|
|
# Copyright (C) 2014 Christian Hättich - feddischson [ at ] opencores.org
|
18 |
|
|
#
|
19 |
|
|
# This program is free software: you can redistribute it and/or modify
|
20 |
|
|
# it under the terms of the GNU General Public License as published by
|
21 |
|
|
# the Free Software Foundation, either version 3 of the License, or
|
22 |
|
|
# (at your option) any later version.
|
23 |
|
|
#
|
24 |
|
|
# This program is distributed in the hope that it will be useful,
|
25 |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
26 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
27 |
|
|
# GNU General Public License for more details.
|
28 |
|
|
#
|
29 |
|
|
# You should have received a copy of the GNU General Public License
|
30 |
|
|
# along with this program. If not, see .
|
31 |
|
|
#
|
32 |
|
|
#
|
33 |
|
|
###############################################################
|
34 |
|
|
#
|
35 |
|
|
# Description:
|
36 |
|
|
# This class represents an abstract component.
|
37 |
|
|
# It is one of the central classes and holds data,
|
38 |
|
|
# which is used to describe and instanciate a core or SOC.
|
39 |
|
|
#
|
40 |
|
|
# The following fields are defined and used
|
41 |
|
|
# by CoreDef and SOCDef
|
42 |
|
|
# - name : name of the core (mandatory)
|
43 |
|
|
# - version : version of the core (mandatory)
|
44 |
|
|
# - toplevel : toplevel name (mandatory)
|
45 |
|
|
# - description : description of this core
|
46 |
|
|
# - date : creation date
|
47 |
|
|
# - license : license of this core
|
48 |
|
|
# - licensefile : location of the license file
|
49 |
|
|
# - author : author of this core
|
50 |
|
|
# - authormail : author-mail of this core
|
51 |
|
|
# - vccmd : a version control command, which is used
|
52 |
|
|
# to download the files
|
53 |
|
|
# - interfaces : interfaces which are implemented
|
54 |
|
|
# see SOCMaker::IfcSpc
|
55 |
|
|
# - inst_parameters : hash of instantiation parameters
|
56 |
|
|
# see SOCMaker::Parameter
|
57 |
|
|
# - static_parameters : hash of static parameters
|
58 |
|
|
# see SOCMaker::SParameter
|
59 |
|
|
########
|
60 |
|
|
#
|
61 |
|
|
# TODO
|
62 |
|
|
#
|
63 |
|
|
#
|
64 |
|
|
###############################################################
|
65 |
|
|
|
66 |
|
|
|
67 |
|
|
module SOCMaker
|
68 |
|
|
class Component
|
69 |
|
|
include ERR
|
70 |
|
|
include YAML_EXT
|
71 |
|
|
|
72 |
|
|
attr_accessor :name
|
73 |
|
|
attr_accessor :version
|
74 |
|
|
attr_accessor :toplevel
|
75 |
|
|
attr_accessor :description
|
76 |
|
|
attr_accessor :date
|
77 |
|
|
attr_accessor :license
|
78 |
|
|
attr_accessor :licensefile
|
79 |
|
|
attr_accessor :author
|
80 |
|
|
attr_accessor :authormail
|
81 |
|
|
attr_accessor :vccmd
|
82 |
|
|
attr_accessor :interfaces
|
83 |
|
|
attr_accessor :functions
|
84 |
|
|
attr_accessor :inst_parameters
|
85 |
|
|
attr_accessor :static_parameters
|
86 |
|
|
def initialize( name, version, toplevel, options = {} )
|
87 |
|
|
init_with( { 'name' => name,
|
88 |
|
|
'version' => version,
|
89 |
|
|
'toplevel' => toplevel }.merge( options ) )
|
90 |
|
|
end
|
91 |
|
|
def encode_with( coder )
|
92 |
|
|
%w[ name version description date license licensefile
|
93 |
|
|
author authormail vccmd toplevel interfaces
|
94 |
|
|
functions inst_parameters static_parameters ].
|
95 |
|
|
each { |v| coder[ v ] = instance_variable_get "@#{v}" }
|
96 |
|
|
end
|
97 |
|
|
def init_with( coder )
|
98 |
|
|
|
99 |
|
|
serr_if( coder[ 'name' ] == nil,
|
100 |
|
|
'Name not defined',
|
101 |
|
|
field: 'name' )
|
102 |
|
|
@name = coder[ 'name' ]
|
103 |
|
|
verr_if( !@name.is_a?( String ),
|
104 |
|
|
'The name must be of type string',
|
105 |
|
|
field: 'name' )
|
106 |
|
|
serr_if( @name.size == 0,
|
107 |
|
|
'Name not defined (size == 0)',
|
108 |
|
|
field: 'name' )
|
109 |
|
|
verr_if( !!SOCMaker::conf[ :name_regex ].match( @name ) == false,
|
110 |
|
|
'The core name is invalid',
|
111 |
|
|
instance: @name,
|
112 |
|
|
field: 'name' )
|
113 |
|
|
|
114 |
|
|
serr_if( coder[ 'version' ] == nil,
|
115 |
|
|
'Version not defined',
|
116 |
|
|
instance: @name,
|
117 |
|
|
field: 'version' )
|
118 |
|
|
@version = coder[ 'version' ]
|
119 |
|
|
serr_if( @version.size == 0,
|
120 |
|
|
'Version not defined (size == 0)',
|
121 |
|
|
instance: @name,
|
122 |
|
|
field: 'version' )
|
123 |
|
|
|
124 |
|
|
# cast from numeric to string, if not given as string
|
125 |
|
|
@version = @version.to_s if @version.is_a? ( Numeric )
|
126 |
|
|
verr_if( !@version.is_a?( String ),
|
127 |
|
|
'The name must be of type string or numeric',
|
128 |
|
|
field: 'name' )
|
129 |
|
|
|
130 |
|
|
|
131 |
|
|
|
132 |
|
|
serr_if( coder[ 'toplevel' ] == nil,
|
133 |
|
|
'Toplevel not defined',
|
134 |
|
|
instance: @name,
|
135 |
|
|
field: 'toplevel' )
|
136 |
|
|
@toplevel = coder[ 'toplevel' ]
|
137 |
|
|
verr_if( !@toplevel.is_a?( String ),
|
138 |
|
|
"toplevel must be of type string",
|
139 |
|
|
instance: @name,
|
140 |
|
|
field: "toplevel" )
|
141 |
|
|
serr_if( @toplevel.size == 0,
|
142 |
|
|
'Toplevel not defined (size == 0 )',
|
143 |
|
|
instance: @name,
|
144 |
|
|
field: 'toplevel' )
|
145 |
|
|
|
146 |
|
|
|
147 |
|
|
|
148 |
|
|
|
149 |
|
|
# set non-nil values
|
150 |
|
|
# -> we don't need to check for nil in the rest of the
|
151 |
|
|
# processing
|
152 |
|
|
@description = coder[ 'description' ] || ""
|
153 |
|
|
@date = coder[ 'date' ] || ""
|
154 |
|
|
@license = coder[ 'license' ] || ""
|
155 |
|
|
@licensefile = coder[ 'licensefile' ] || ""
|
156 |
|
|
@author = coder[ 'author' ] || ""
|
157 |
|
|
@authormail = coder[ 'authormail' ] || ""
|
158 |
|
|
@vccmd = coder[ 'vccmd' ] || ""
|
159 |
|
|
@interfaces = coder[ 'interfaces' ] || {}
|
160 |
|
|
@functions = coder[ 'functions' ] || {}
|
161 |
|
|
@inst_parameters = coder[ 'inst_parameters' ] || {}
|
162 |
|
|
@static_parameters = coder[ 'static_parameters' ] || {}
|
163 |
|
|
|
164 |
|
|
|
165 |
|
|
# ensure, that these fields are of type String
|
166 |
|
|
%w[ description date license licensefile
|
167 |
|
|
author authormail vccmd ].each do |n|
|
168 |
|
|
verr_if( !instance_variable_get( '@'+n ).is_a?( String ),
|
169 |
|
|
"#{n} must be of type String",
|
170 |
|
|
instance: @name,
|
171 |
|
|
field: n )
|
172 |
|
|
end
|
173 |
|
|
|
174 |
|
|
# ensure, that these fields are of type Hash
|
175 |
|
|
%w[ interfaces inst_parameters
|
176 |
|
|
functions static_parameters ].each do |n|
|
177 |
|
|
verr_if( !instance_variable_get( '@'+n ).is_a?( Hash ),
|
178 |
|
|
"#{n} must be of type Hash",
|
179 |
|
|
instance: @name,
|
180 |
|
|
field: n )
|
181 |
|
|
end
|
182 |
|
|
|
183 |
|
|
|
184 |
|
|
|
185 |
|
|
# check interfaces
|
186 |
|
|
@interfaces.each do |ifc_name, ifc|
|
187 |
|
|
serr_if( ifc == nil,
|
188 |
|
|
'Interface not defined',
|
189 |
|
|
instance: @name+":"+ifc_name.to_s )
|
190 |
|
|
|
191 |
|
|
serr_if( !ifc.is_a?( SOCMaker::IfcDef ),
|
192 |
7 |
feddischso |
'Interface definition is not SOCMaker::IfcDef (please use SOCM_IFC)',
|
193 |
3 |
feddischso |
instance: @name+":"+ifc_name.to_s )
|
194 |
|
|
end
|
195 |
|
|
|
196 |
|
|
# check instance parameters
|
197 |
|
|
@inst_parameters.each do |name, param |
|
198 |
|
|
serr_if( param == nil,
|
199 |
|
|
'Instance parameter not defined',
|
200 |
|
|
instance: @name+":"+name.to_s )
|
201 |
|
|
|
202 |
|
|
serr_if( !param.is_a?( SOCMaker::Parameter ),
|
203 |
7 |
feddischso |
'Instance parameter not SOCMaker::Parameter (please use SOCM_PARAM)',
|
204 |
3 |
feddischso |
instance: @name+":"+name.to_s )
|
205 |
|
|
end
|
206 |
|
|
|
207 |
|
|
# check instance parameters
|
208 |
|
|
@static_parameters.each do |name, sparam |
|
209 |
|
|
serr_if( sparam == nil,
|
210 |
|
|
'Static parameter not defined',
|
211 |
|
|
instance: @name+":"+name.to_s )
|
212 |
|
|
|
213 |
|
|
serr_if( !sparam.is_a?( SOCMaker::SParameter ),
|
214 |
7 |
feddischso |
'Static parameter not SOCMaker::Parameter (please use SOCM_SPARAM)',
|
215 |
3 |
feddischso |
instance: @name+":"+name.to_s )
|
216 |
|
|
end
|
217 |
|
|
|
218 |
7 |
feddischso |
end
|
219 |
3 |
feddischso |
|
220 |
|
|
|
221 |
7 |
feddischso |
def consistency_check
|
222 |
8 |
feddischso |
@interfaces.values.each_with_index do | ifc, i_ifc; ifc_def|
|
223 |
|
|
|
224 |
|
|
# get interface definition
|
225 |
|
|
ifc_def = SOCMaker::lib.get_ifc( ifc.name, ifc.version )
|
226 |
3 |
feddischso |
|
227 |
8 |
feddischso |
|
228 |
|
|
# check, if all mandatory ports are implemented by this interface
|
229 |
|
|
ifc_def.ports.each do | port_name, port |
|
230 |
|
|
perr_if( port[ :mandatory ] == true &&
|
231 |
|
|
ifc.ports.select{ |key,port_def| port_def.defn.to_sym == port_name }.size == 0,
|
232 |
|
|
"Mandatory port #{port_name} is not implemented in interface #{ifc.name}" )
|
233 |
|
|
end
|
234 |
|
|
end
|
235 |
|
|
|
236 |
3 |
feddischso |
end
|
237 |
|
|
|
238 |
|
|
|
239 |
|
|
def get_files
|
240 |
5 |
feddischso |
unless self.vccmd.nil? or @vccmd.size == 0
|
241 |
6 |
feddischso |
#puts"cd #{@dir} && #{@vccmd}"
|
242 |
5 |
feddischso |
system( "cd #{@dir} && #{vccmd} " )
|
243 |
3 |
feddischso |
end
|
244 |
|
|
end
|
245 |
|
|
|
246 |
|
|
|
247 |
|
|
|
248 |
|
|
def generics
|
249 |
|
|
@inst_parameters.each_with_index do |(name, val), i|
|
250 |
|
|
yield( name.to_s, val.type, val.default, i == @inst_parameters.size-1 )
|
251 |
|
|
end
|
252 |
|
|
end
|
253 |
|
|
|
254 |
5 |
feddischso |
def get_and_ensure_dst_dir!( core_name )
|
255 |
|
|
dst_dir = File.expand_path(
|
256 |
|
|
File.join(
|
257 |
|
|
SOCMaker::conf[ :build_dir ],
|
258 |
|
|
SOCMaker::conf[ :hdl_dir ],
|
259 |
|
|
core_name ) )
|
260 |
|
|
FileUtils.mkdir_p dst_dir
|
261 |
|
|
return dst_dir
|
262 |
|
|
end
|
263 |
3 |
feddischso |
|
264 |
|
|
#
|
265 |
|
|
# Iterates over interface list.
|
266 |
|
|
# For each interface, all ports are processed.
|
267 |
|
|
# For each port within each interface, we lookup the port defn
|
268 |
|
|
# and yield the call block with
|
269 |
|
|
# - port-name
|
270 |
|
|
# - port-definition
|
271 |
|
|
# - info if last
|
272 |
|
|
# as argument
|
273 |
|
|
#
|
274 |
8 |
feddischso |
# An xor mechanism between port_dir and ifc=>dir is used
|
275 |
|
|
# to determine the direction of a port, for example:
|
276 |
|
|
# If the interface is declared as input (1) and a port is declared as input (1)
|
277 |
|
|
# the resulting direction will be an output 1^1 = 0.
|
278 |
|
|
# But if the overall interface direction is an output (0) and a port is declared
|
279 |
|
|
# as input, the resulting direction will an input 0^1 = 1.
|
280 |
|
|
# This allows to define a port-direction in the interface definition,
|
281 |
|
|
# and toggle the directions on core-definition level.
|
282 |
3 |
feddischso |
#
|
283 |
|
|
#
|
284 |
|
|
def ports( *args )
|
285 |
|
|
|
286 |
|
|
if args.size == 0
|
287 |
|
|
@interfaces.values.each_with_index do | ifc, i_ifc; ifc_def|
|
288 |
|
|
|
289 |
|
|
# get interface definition
|
290 |
|
|
ifc_def = SOCMaker::lib.get_ifc( ifc.name, ifc.version )
|
291 |
|
|
|
292 |
|
|
# loop over ports in this interface
|
293 |
|
|
ifc.ports.each_with_index do |(port_name, port_def), i_port; port_dir|
|
294 |
|
|
|
295 |
|
|
# the reference to the port in the definition
|
296 |
8 |
feddischso |
defn_ref = port_def.defn.to_sym
|
297 |
|
|
perr_if( !ifc_def.ports.has_key?( defn_ref ),
|
298 |
|
|
"Can't find #{port_def} in" +
|
299 |
|
|
"interface definition #{ifc_def.name} " +
|
300 |
|
|
"version #{ifc_def.version}" )
|
301 |
3 |
feddischso |
yield( port_name.to_s,
|
302 |
8 |
feddischso |
ifc_def.ports[ defn_ref ][:dir] ^ ifc.dir,
|
303 |
3 |
feddischso |
port_def.len,
|
304 |
8 |
feddischso |
ifc_def.ports[ defn_ref ][ :default ],
|
305 |
3 |
feddischso |
( (i_port == ifc.ports.size-1 ) and (i_ifc == @interfaces.size-1 ) ) )
|
306 |
|
|
end
|
307 |
|
|
end
|
308 |
|
|
|
309 |
|
|
elsif args.size == 1
|
310 |
|
|
|
311 |
|
|
# get interface (input is the name as string )
|
312 |
|
|
ifc = @interfaces[ args.first.to_sym ]
|
313 |
8 |
feddischso |
ifc_def = SOCMaker::lib.get_ifc( ifc.name, ifc.version )
|
314 |
3 |
feddischso |
|
315 |
8 |
feddischso |
# loop over all ports of this interface
|
316 |
|
|
ifc.ports.each_with_index do |(port_name, port_def),i_port; port_dir|
|
317 |
|
|
defn_ref = port_def.defn.to_sym
|
318 |
|
|
perr_if( !ifc_def.ports.has_key?( defn_ref ),
|
319 |
|
|
"Can't find #{defn_ref} in" +
|
320 |
|
|
"interface definition #{ifc_def.name} " +
|
321 |
|
|
"version #{ifc_def.version}" )
|
322 |
|
|
yield( port_name.to_s,
|
323 |
|
|
ifc_def.ports[ defn_ref ][:dir] ^ ifc.dir,
|
324 |
|
|
port_def.len,
|
325 |
|
|
ifc_def.ports[ defn_ref ][ :default ],
|
326 |
|
|
( (i_port == ifc.ports.size-1 ) )
|
327 |
|
|
)
|
328 |
|
|
#yield( port_def.to_s,
|
329 |
|
|
#port_name.to_s,
|
330 |
|
|
#port_dir ^ ifc.dir,
|
331 |
|
|
#port_default )
|
332 |
3 |
feddischso |
end
|
333 |
|
|
|
334 |
|
|
else
|
335 |
8 |
feddischso |
# TODO
|
336 |
3 |
feddischso |
end
|
337 |
|
|
|
338 |
|
|
end
|
339 |
|
|
|
340 |
|
|
|
341 |
7 |
feddischso |
|
342 |
|
|
# def implements_port?( ifc_name, port_spec_name )
|
343 |
|
|
# tmp = @interfaces[ ifc_name.to_sym ].
|
344 |
|
|
# ports.select{ |key,hash| hash.defn == port_spec_name.to_s }.keys
|
345 |
|
|
|
346 |
|
|
# perr_if( tmp.size > 1,
|
347 |
|
|
# "The port #{port_spec_name} of interface #{ifc_name} is implemented
|
348 |
|
|
# multiple times" )
|
349 |
5 |
feddischso |
|
350 |
7 |
feddischso |
# return tmp.size == 1
|
351 |
|
|
# end
|
352 |
3 |
feddischso |
|
353 |
|
|
def param_ok?( param_name, param_value )
|
354 |
|
|
param = inst_parameters[ param_name.to_sym ]
|
355 |
|
|
param = static_parameters[ param_name.to_sym ] if param == nil
|
356 |
|
|
return false if param == nil
|
357 |
|
|
end
|
358 |
|
|
|
359 |
|
|
|
360 |
|
|
|
361 |
|
|
def ==(o)
|
362 |
|
|
|
363 |
|
|
tmp = ( o.class == self.class )
|
364 |
|
|
return tmp if !tmp
|
365 |
|
|
|
366 |
|
|
%w[ name version description date license licensefile
|
367 |
|
|
author authormail vccmd toplevel interfaces
|
368 |
|
|
functions inst_parameters static_parameters ].
|
369 |
|
|
each do |v|
|
370 |
|
|
return false if instance_variable_get( "@#{v}" ) != o.instance_variable_get( "@#{v}" )
|
371 |
|
|
end
|
372 |
|
|
return true
|
373 |
|
|
end
|
374 |
|
|
|
375 |
5 |
feddischso |
def to_s
|
376 |
|
|
"version: #{@version}\n" +
|
377 |
|
|
"toplevel: #{@toplevel}\n" +
|
378 |
|
|
"description: #{@description}\n" +
|
379 |
|
|
"date: #{@date}\n" +
|
380 |
|
|
"license: #{@license}\n" +
|
381 |
|
|
"licensefile: #{@licensefile}\n" +
|
382 |
|
|
"author: #{@author}\n" +
|
383 |
|
|
"authormail: #{@authormail}\n" +
|
384 |
|
|
"vccmd: #{@vccmd}\n" +
|
385 |
|
|
"interfaces: #{@interfaces}\n" +
|
386 |
|
|
"functions: #{@functions}\n" +
|
387 |
|
|
"inst_parameters: #{@inst_parameters}\n" +
|
388 |
|
|
"static_parameters: #{@static_parameters}\n"
|
389 |
|
|
end
|
390 |
|
|
|
391 |
|
|
|
392 |
3 |
feddischso |
end # class CoreDef
|
393 |
|
|
end # module SOCMaker
|
394 |
|
|
|
395 |
|
|
|
396 |
|
|
# vim: noai:ts=2:sw=2
|
397 |
|
|
|
398 |
8 |
feddischso |
# vim: noai:ts=2:sw=2
|