OpenCores
URL https://opencores.org/ocsvn/soc_maker/soc_maker/trunk

Subversion Repositories soc_maker

[/] [soc_maker/] [trunk/] [lib/] [soc_maker/] [core_inst.rb] - Blame information for rev 8

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 feddischso
###############################################################
2
#
3
#  File:      core_inst.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 a core instantiation within
37
#     a SOC. It contains a params (parameters) hash,
38
#     which defines, which parameters are set to which values.
39
#     The type field is used to identify the SOCMaker::CoreDef
40
#     and the field @defn is initialized as reference to
41
#     the corresponding CoreDef instance.
42
#
43
#
44
###############################################################
45
 
46
 
47
module SOCMaker
48
class CoreInst
49
  include ERR
50
 
51
 
52
 
53
  attr_accessor :defn
54
  attr_accessor :type
55
  attr_accessor :params
56
 
57
  def initialize(  type, params = {} )
58
    init_with(  'type'   => type,
59
                'params' => params  )
60 7 feddischso
 
61 3 feddischso
  end
62
  def encode_with( coder )
63
    %w[ type params ].
64
      each { |v| coder[ v ] = instance_variable_get "@#{v}" }
65
  end
66
 
67
  def init_with( coder )
68
 
69
    serr_if( coder[ 'type' ] == nil,
70
      "no type is provided for a core instance",
71
      field: "type" )
72
 
73
    @type = coder[ 'type' ]
74
 
75
    @params = coder[ 'params' ] || {}
76
    serr_if( !@params.is_a?( Hash ), 'Parameters are not given as hash',
77
      field: 'params' )
78
 
79
  end
80
 
81 8 feddischso
  def ports( *args )
82
    if args.size == 0
83
      @ports.each_with_index do |(name, port_def), i|
84
        yield( name.to_s, port_def[ :dir ], port_def[ :len ], port_def[ :default ], i==@ports.size-1 )
85
      end
86
    elsif args.size == 1
87
      @ifcs[ args.first.to_sym  ].each do |name, port_def, i|
88
        yield( name.to_s, port_def[ :dir ], port_def[ :len ], port_def[ :default ], i==@ports.size-1 )
89
      end
90 3 feddischso
    end
91
  end
92
 
93
 
94
  def generics
95
    @defn.generics do |name, type, default_value, is_last|
96
      value = @params[ name.to_sym ];
97
      value = value
98
      value = default_value if value == nil
99
      yield( name.to_s, type, value, is_last )
100
    end
101
  end
102
 
103
 
104
 
105
 
106 5 feddischso
 
107 3 feddischso
 
108 7 feddischso
  #
109
  # Get a port, identified by the interface and port name
110
  #
111
  #  +ifc_name+::       name of the interface
112
  #  +port_spec_name+:: name of the port
113
  #
114 3 feddischso
  def get_port( ifc_name, port_spec_name )
115
    tmp = @defn.interfaces[ ifc_name.to_sym ].
116
        ports.select{ |key,hash| hash.defn == port_spec_name.to_s }.
117
        keys.first.to_s
118
    return [ tmp, @ports[ tmp.to_sym ] ]
119
  end
120
 
121
 
122 7 feddischso
  # TODO do we need this?
123 8 feddischso
  #
124
  #
125 7 feddischso
# def implements_port?( ifc_name, port_spec_name )
126
#   @defn.implements_port?( ifc_name, port_spec_name )
127
# end
128 3 feddischso
 
129
 
130 7 feddischso
  def consistency_check
131
 
132 3 feddischso
    @defn = SOCMaker::lib.get_core( @type )
133
 
134
 
135
    # check, if the instance parameters in the core definition
136
    @params.each do |param_name, value|
137
      verr_if(  @defn.inst_parameters[ param_name ] == nil,
138
                "Parameter not found: " + param_name.to_s,
139
        field: 'params' )
140
    end
141
 
142
    ## auto-complete parameters with default values
143
    @defn.inst_parameters.each do |param_name, param|
144
 
145
      # auto-complete to default values
146
      @params[ param_name ] ||= param.default
147
    end
148
 
149
 
150
#   @_params ||= {}
151
#   if @params != nil
152
#     @params.each do |name, val|
153
#
154
#       param_type = defn.inst_parameters[ name ].type
155
#
156
#       if val.is_a? String
157
#         eval_match = SOCMaker::conf[ :eval_regex ].match( val )
158
#         #TODO error handling
159
#         if eval_match
160
#           #eval_func = eval_match.captures[0]
161
#           @_params[ name ] = { value: eval( eval_str ).to_s, type: param_type }
162
#         else
163
#           @_params[ name ] = { value: val, type: param_type }
164
#         end
165
#       else
166
#         @_params[ name ] = { value: val, type: param_type }
167
#       end
168
#     end
169
#   end
170 8 feddischso
 
171 3 feddischso
 
172 8 feddischso
    #
173
    #  TODO merge these two loops and create one hash
174
    ###
175
    #
176
    # create our own ports hash
177
    #
178 3 feddischso
    @ports ||= {}
179 8 feddischso
    @defn.ports do |port_name, port_dir, port_len, default, is_last |
180 3 feddischso
      if port_len.is_a?( String )
181
        param_match = SOCMaker::conf[ :length_regex ].match( port_len )
182
 
183
        if param_match and @params[ port_len.to_sym ] != nil
184
          tmp =@params[ port_len.to_sym ]
185
          tmp = tmp.to_i if tmp.is_a?( String )
186 8 feddischso
          @ports[ port_name.to_sym ] = { len: tmp, dir: port_dir, default: default }
187 3 feddischso
        else
188
          SOCMaker::logger.error( "Failed to evaluate #{port_len} for port #{port_name}" )
189
        end
190
      else
191 8 feddischso
        @ports[ port_name.to_sym ] = { len: port_len, dir: port_dir, default: default }
192 3 feddischso
      end
193
    end
194 8 feddischso
 
195 3 feddischso
 
196 8 feddischso
    @ifcs ||= {}
197
    @defn.interfaces.keys.each do |ifc_name|
198
      @ifcs[ ifc_name ] = {}
199
      @defn.ports( ifc_name ) do |port_name, port_dir, port_len, default, is_last |
200
 
201
        if port_len.is_a?( String )
202
          param_match = SOCMaker::conf[ :length_regex ].match( port_len )
203
 
204
          if param_match and @params[ port_len.to_sym ] != nil
205
            tmp =@params[ port_len.to_sym ]
206
            tmp = tmp.to_i if tmp.is_a?( String )
207
            @ifcs[ ifc_name ][ port_name.to_sym ] = { len: tmp, dir: port_dir, default: default }
208
          else
209
            SOCMaker::logger.error( "Failed to evaluate #{port_len} for port #{port_name}" )
210
          end
211
        else
212
          @ifcs[ ifc_name ][ port_name.to_sym ] = { len: port_len, dir: port_dir, default: default }
213
        end
214
        #
215
        #puts "#{port_def_ref}, #{port_name}, #{port_dir}, #{port_default}"
216
      end
217
    end
218
 
219
#   lerr_if( @defn == nil, 'Core not found in lib',
220
#     field:    'cores'    )
221 7 feddischso
 
222
 
223
    @defn.consistency_check
224
 
225 3 feddischso
 
226
  end
227
 
228
 
229 6 feddischso
 
230 7 feddischso
  #
231
  # Returns the length of a port within an interface.
232
  # If no instance is given, we know that it is
233
  # a toplevel interface.
234
  # Otherwise we check for this and we do a recursive call.
235
  # If this port is within a interface of a core, we
236
  # pass the call to the core-definition of this instance, which
237
  # knows all cores.
238
  #
239
  # +ifc_name+::        name of the interface
240
  # +port_spec_name+::  name of the port
241
  # +inst+::            name of the instance (optional), default is nil
242
  #
243
  def get_port_len( ifc_name, port_spec_name, inst = nil )
244
    if inst == nil
245
      tmp = @defn.interfaces[ ifc_name.to_sym ].
246
          ports.select{ |key,hash| hash.defn == port_spec_name.to_s }.
247
          keys.first.to_s
248
      return tmp.size == 0 ? 0 : @ports[ tmp.to_sym ][ :len ]
249
    else
250
      if inst == @defn.name.to_sym
251
        return get_port_len( ifc_name, port_spec_name )
252
      else
253
        return @defn.get_port_len( ifc_name, port_spec_name, inst )
254
      end
255
    end
256
  end
257
 
258
 
259
  #
260
  # Returns the core definition for an instance (identified by its name)
261
  #
262
  # +inst+:: name of the instance
263
  #
264 6 feddischso
  def get_core_def( inst )
265 7 feddischso
      if inst == @defn.name
266
        return @defn
267
      else
268
        tmp = @defn.get_core_def( inst )
269
        perr_if( tmp == nil, "#Processing error: {inst} not found by get_core_def" )
270 6 feddischso
        return tmp
271
      end
272
  end
273
 
274
 
275 7 feddischso
  #
276
  # Returns a core instance, identified by its name.
277
  # If it is not a sub-core, we return our self
278
  #
279
  # +inst+::  name of the instance
280
  #
281
  def get_core_inst( inst )
282
    if @defn.cores[ inst ] != nil
283
      return @defn.cores[ inst ]
284
    else
285
      return self
286
    end
287
  end
288 6 feddischso
 
289
 
290 7 feddischso
  #
291
  # Generate toplevel hdl file for this instance.
292
  # This assumes, that this instance represents a SOC with
293
  # further instances.
294
  #
295
  #
296
  # +coder+:: A HDL coder, which is used to create the auto-generated HDL (optional).
297
  #           If no coder is given, a VHDLCoder is used.
298
  #
299
  #
300
  def gen_toplevel( coder = VHDLCoder.new )
301 6 feddischso
 
302
 
303
    #
304 7 feddischso
    # Get filename
305 6 feddischso
    #
306 7 feddischso
    file_name = coder.filename( @defn.name )
307 6 feddischso
 
308
    SOCMaker::logger.proc( "START of creating top-level '" + file_name + "'" )
309
 
310
 
311
    #
312
    # Create a unique list of cores and
313 7 feddischso
    # add for each core a component statement (vhdl only).
314 6 feddischso
    # Even if there are multiple instances of a core,
315
    # we need to decalre it only once
316
    #
317
    @defn.cores.values.uniq{|x| x.type }.each do |inst; spec|
318
 
319
      spec = SOCMaker::lib.get_core( inst.type  )
320
      SOCMaker::lib.check_nil( spec, "Can't find #{ inst.type } in SOC library" )
321
 
322 7 feddischso
      coder.add_core_component( inst.type, spec )
323 6 feddischso
    end
324
 
325 7 feddischso
    #
326
    # Instanciate each core
327
    #
328 6 feddischso
    @defn.cores.each do |inst_name, inst|
329 7 feddischso
      coder.add_core_instance( inst_name.to_s, inst )
330 6 feddischso
    end
331
 
332
 
333
 
334
    # Iterate over all connections:
335
    #  - create signal instances
336
    #  - add assignments
337
    #
338
    @defn.cons.each do |con_name, con_def|
339
      gen_toplevel_con(   con_name.to_s,
340
                          con_def[ :rule ],
341
                          con_def[ :mapping ][0],
342
                          con_def[ :mapping ][1],
343 7 feddischso
                          coder  )
344 6 feddischso
 
345
    end
346 8 feddischso
 
347
    assign_unused_to_default( coder )
348
 
349 7 feddischso
 
350
    #
351
    # Write content to the file
352
    #
353 6 feddischso
    SOCMaker::logger.proc( "writing top-level" )
354
    file_dir  = File.join( SOCMaker::conf[ :build_dir ],
355
                           SOCMaker::conf[ :hdl_dir   ] )
356
    ::FileUtils.mkdir_p file_dir
357 7 feddischso
    File.open( File.join( file_dir, file_name ), 'w' ) do |f|
358
      f.write( coder.get_hdl_code( self, @defn.name ) )
359 6 feddischso
    end
360 7 feddischso
    SOCMaker::logger.proc( "END of creating top-level hdl code for #{@defn.name}" )
361 6 feddischso
 
362
  end
363
 
364
 
365 7 feddischso
 
366
 
367
  #
368 8 feddischso
  # Assign default values for unused interfaces.
369
  # This is just a helper function and is used by gen_toplevel
370
  #
371
  # +coder+:: A HDL coder, which is used to create the auto-generated HDL.
372
  #
373
  def assign_unused_to_default( coder )
374
 
375
 
376
 
377
    # iterate over all instances
378
    # and check all interfaces
379
    @defn.cores.each do |inst_name, inst|
380
 
381
      inst.defn.interfaces.each do |ifc_name, ifc|
382
 
383
        #
384
        # Get the interface specification by using the 1st source entry
385
        # and searching for the core-definition.
386
        #
387
        ifc_spec = SOCMaker::lib.get_ifc( ifc.name, ifc.version )
388
 
389
        if !@defn.ifc_in_use?( inst_name, ifc_name )
390
 
391
          default_tmp = {};
392
          ifc_spec.ports.each do |_name,_port|
393
            default_tmp[ _name ] = _port[ :default ]
394
          end
395
 
396
          coder.add_ifc_default_assignment(  inst, inst_name, ifc_name, default_tmp )
397
        end
398
      end
399
    end
400
  end
401
 
402
 
403
 
404
  #
405 7 feddischso
  # This function is called during the toplevel generation
406
  # for each connection.
407
  #
408
  # +name+::   The name of the connection
409
  # +rule+::   The combination rule (obsolete/unused)
410
  # +src+::    Source hash with instance name as key and interface name as value
411
  # +dst+::    Destination hash with instance name as key and interface name as value
412
  # +coder+::  The HDL coder which is used
413
  #
414 6 feddischso
  def gen_toplevel_con( name, rule, src, dst, coder )
415
 
416
    src_inst            = {};
417
    dst_inst            = {};
418
 
419 7 feddischso
    #
420
    # Get the interface specification by using the 1st source entry
421
    # and searching for the core-definition.
422
    #
423 6 feddischso
    ifc_spec = SOCMaker::lib.get_ifc(
424
      get_core_def( src.keys.first.to_s ).interfaces[ src.values.first ].name,
425
      get_core_def( src.keys.first.to_s ).interfaces[ src.values.first ].version )
426 7 feddischso
 
427
 
428
    #
429
    # Get the maximum required signal length
430
    #
431
    # For each signal in the interface specification,
432
    # we create a list. The list has an entry for each source
433
    # and destination signal, which defines the length.
434
    #
435
    # In the second step, the maximum in each list is extracted.
436
    #
437 6 feddischso
    length_tmp  = {};
438
    ifc_spec.ports.keys.each do |_name|
439
      length_tmp[ _name ] = []
440
      dst.each do |inst_name, ifc_name|
441 7 feddischso
        length_tmp[ _name ] << get_port_len( ifc_name, _name, inst_name )
442 6 feddischso
      end
443
      src.each do |inst_name, ifc_name|
444 7 feddischso
        length_tmp[ _name ] << get_port_len( ifc_name, _name, inst_name )
445 6 feddischso
      end
446
    end
447
    max_length = Hash[ length_tmp.map{ |key, arr| [ key, arr.max ] } ]
448
 
449
 
450 7 feddischso
    #
451
    # Prepare a hash for all sources and destinations, where
452
    # the instance name is the key and the core-instance is
453
    # the value.
454
    #
455 6 feddischso
    src.keys.each do |inst_name|
456 7 feddischso
      src_inst[ inst_name ]            = get_core_inst( inst_name )
457 6 feddischso
    end
458
    dst.keys.each do |inst_name|
459 7 feddischso
      dst_inst[ inst_name ]            = get_core_inst( inst_name )
460 6 feddischso
    end
461
 
462 7 feddischso
    #
463
    # create the declaraion and assignments
464
    #
465
    coder.add_ifc_connection( ifc_spec, name, max_length, src_inst, dst_inst, src, dst )
466 6 feddischso
 
467
  end
468
 
469
 
470 7 feddischso
  #
471
  # Returns a string describing this instance
472
  #
473 5 feddischso
  def to_s
474
    "type:     #{type}\n"   +
475
    "params:   #{params}\n"
476
  end
477 3 feddischso
 
478 7 feddischso
  #
479
  # Equal operator
480
  #
481 3 feddischso
  def ==(o)
482
    o.class     == self.class   &&
483
    o.type      == self.type    &&
484
    o.params    == self.params
485
  end
486
 
487 8 feddischso
  # TODO
488
#  private: assign_unused_to_default, :gen_toplevel_con
489 3 feddischso
 
490
end # CoreInst
491
end # SOCMaker
492
 
493
 
494
 
495
# vim: noai:ts=2:sw=2

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.