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 9

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