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

Subversion Repositories soc_maker

[/] [soc_maker/] [trunk/] [lib/] [soc_maker/] [soc_def.rb] - Blame information for rev 3

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

Line No. Rev Author Line
1 3 feddischso
###############################################################
2
#
3
#  File:      soc_def.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 System-on-chip and derives
37
#     the functionallity from Component.
38
#     The two important fields are
39
#       - @cores: holds all core-instances
40
#       - cons:   holds all connections
41
#     In addition, the field @static is used to store
42
#     static parameters, which are set for cores used in this SOC.
43
#
44
###############################################################
45
 
46
module SOCMaker
47
class SOCDef < Component
48
  include ERR
49
  include YAML_EXT
50
 
51
  attr_accessor :cores
52
  attr_accessor :cons
53
  attr_accessor :static
54
  def initialize( name, version, toplevel, options = {} )
55
 
56
    init_with( { 'name'     => name,
57
                 'version'  => version,
58
                 'toplevel' => toplevel }.merge( options ) )
59
 
60
  end
61
 
62
  def encode_with( coder )
63
    super coder
64
    %w[ cores cons static ].
65
      each { |v| coder[ v ] = instance_variable_get "@#{v}" }
66
  end
67
 
68
  def init_with( coder )
69
    super coder
70
    @cores  = coder[ 'cores'  ] || {}
71
    @static = coder[ 'static' ] || {}
72
    @cons   = coder[ 'cons'   ] || {}
73
  end
74
 
75
  def verify
76
    super( true )
77
 
78
    @cores.each do |core_name, core_inst|
79
      core_inst.verify
80
    end
81
 
82
  end
83
 
84
 
85
  def get_and_ensure_dst_dir!( core_name )
86
      dst_dir =  File.expand_path(
87
            File.join(
88
              SOCMaker::conf[ :build_dir ],
89
              SOCMaker::conf[ :hdl_dir   ],
90
              core_name ) )
91
      FileUtils.mkdir_p dst_dir
92
      return dst_dir
93
  end
94
 
95
 
96
 
97
 
98
  # SOCMaker::logger.error( "instantiation #{inst_name} is already in use" )
99
  def inst_in_use?( inst_name )
100
       @cores[ inst_name.to_sym ] != nil or
101
       @cons[ inst_name.to_sym ]  != nil
102
  end
103
 
104
  def rm( inst_name )
105
 
106
    if @cores[ inst_name.to_sym ] != nil
107
      # TODO: remove also all related connections
108
      @cores.delete( inst_name.to_sym )
109
    elsif @cons[ inst_name.to_sym ]  != nil
110
      @cons.delete( inst_name.to_sym )
111
    else
112
      return false
113
    end
114
    return true
115
  end
116
 
117
 
118
  def add_core( name, version, inst_name )
119
 
120
    return false if inst_in_use?( inst_name )
121
 
122
    # check, if the core exits in our library
123
    #  if not: an error will be raised
124
    SOCMaker::lib.get_core( name, version )
125
 
126
    @cores[ inst_name.to_sym ] = SOCMaker::CoreInst.new( name+version )
127
  end
128
 
129
 
130
  def ifc_in_use?( inst_name, ifc_name )
131
 
132
    # go through all connections and check,
133
    # that non of the interfaces we want to connect is used
134
    @cons.each do |_con_name, con_def|
135
      return true if con_def[ :mapping ][ 0 ][ inst_name.to_sym] == ifc_name.to_sym
136
      return true if con_def[ :mapping ][ 1 ][ inst_name.to_sym] == ifc_name.to_sym
137
    end
138
    return false
139
 
140
  end
141
 
142
 
143
  def add_connection( inst1, ifc1_name, inst2, ifc2_name, con_name )
144
 
145
    return nil if inst_in_use?( con_name )
146
 
147
 
148
   [ [ inst1, ifc1_name ],
149
     [ inst2, ifc2_name ] ].each do |sub_arr|
150
      perr_if( ifc_in_use?( sub_arr[ 0 ], sub_arr[ 1 ] ),
151
          "Interface #{sub_arr[ 1 ]} of instance '#{sub_arr[ 0 ]}' is already in use " )
152
    end
153
 
154
    [ inst1, inst2 ].each do |inst|
155
      perr_if( @cores[ inst.to_sym ] == nil,
156
          "Instance '#{inst}' does not exist in SOC '#{self.name}'" )
157
    end
158
 
159
    # get the core-specs
160
    core_spec_1 = SOCMaker::lib.get_core( @cores[ inst1.to_sym ].type )
161
    core_spec_2 = SOCMaker::lib.get_core( @cores[ inst2.to_sym ].type )
162
 
163
    [ [ core_spec_1, ifc1_name ],
164
      [ core_spec_2, ifc2_name ] ].each do |sub_arr|
165
        perr_if( sub_arr[ 0 ].interfaces[ sub_arr[ 1 ].to_sym ] == nil,
166
          "Interface '#{sub_arr[ 1 ]}' dosn't exist in core '#{sub_arr[0].name}' " )
167
    end
168
 
169
    # check name and version of the ifcs which will be connected
170
    perr_if( core_spec_1.interfaces[ ifc1_name.to_sym ].name     !=
171
             core_spec_2.interfaces[ ifc2_name.to_sym ].name     ||
172
             core_spec_1.interfaces[ ifc1_name.to_sym ].version  !=
173
             core_spec_2.interfaces[ ifc2_name.to_sym ].version,
174
          "Can't connect #{
175
            core_spec_1.interfaces[ ifc1_name.to_sym ].name } - #{
176
            core_spec_2.interfaces[ ifc2_name.to_sym ].name } : #{
177
            core_spec_1.interfaces[ ifc1_name.to_sym ].version } - #{
178
            core_spec_2.interfaces[ ifc2_name.to_sym ].version }" )
179
 
180
 
181
    @cons[ con_name.to_sym ] = {
182
          :rule    => "or",
183
          :mapping => [ { inst1.to_sym => ifc1_name.to_sym },
184
                        { inst2.to_sym => ifc2_name.to_sym } ] }
185
 
186
  end
187
 
188
  def set_param( instance, param, value )
189
 
190
    # get instance
191
    core_inst = @cores[ instance.to_sym ]
192
    perr_if( core_inst == nil,
193
      "Can't find '#{instance}' in SOC" )
194
 
195
    # get the core-definition
196
    core_def = SOCMaker::lib.get_core( core_inst.type  )
197
 
198
    # check if parameter exist
199
    if core_def.inst_parameters[ param.to_sym ] != nil
200
      core_inst.params[ param.to_sym ] = value
201
    else
202
      perr_if( true,
203
        "Parameter '#{param}' not found in '#{core_def.name}'" )
204
    end
205
 
206
  end
207
 
208
  def get_param( instance, param )
209
 
210
    # get instance
211
    core_inst = @cores[ instance.to_sym ]
212
    perr_if( core_inst == nil,
213
      "Can't find '#{instance}' in SOC" )
214
    param_val = core_inst.params[ param.to_sym ]
215
    perr_if( param_val == nil,
216
      "Can't find parameter '#{param}' in '#{instance}'" )
217
    return param_val
218
  end
219
 
220
 
221
  def set_sparam( core, param, value )
222
 
223
    #get instance
224
 
225
    # check, if we are instantiating this core
226
    perr_if( @cores.select{ |name,inst| inst.type == core }.size == 0,
227
      "Core '#{core}' is not instantiated in this SOC" )
228
 
229
    # get the core-definition
230
    core_def = SOCMaker::lib.get_core( core )
231
 
232
    # check if parameter exist
233
    perr_if( core_def.static_parameters.select{ |f,p| p.parameters[ param.to_sym ] != nil }.size == 0,
234
        "Parameter '#{param}' not found in '#{core_def.name}'" )
235
 
236
    @static[ core.to_sym ] ||= {}
237
    @static[ core.to_sym ][ param.to_sym ] = value
238
  end
239
 
240
  def get_sparam( core, param )
241
    perr_if( @static[ core.to_sym ] == nil,
242
      "Core '#{core}' does not exist in this SOC" )
243
 
244
    perr_if( @static[ core.to_sym ][ param.to_sym ] == nil,
245
      "Parameter '#{param}' does not exist for core '#{core}'" )
246
 
247
    return @static[ core.to_sym ][ param.to_sym ]
248
  end
249
 
250
 
251
 
252
  def gen_toplevel( coder = VHDLCoder.new() )
253
 
254
    file_name = @name
255
 
256
    if coder.is_a?( VHDLCoder )
257
      file_name << ".vhd"
258
    elsif coder.is_a?( VerilogCoder )
259
      file_name << ".v"
260
    else
261
      perr_if( true,
262
        "No valid coder" )
263
    end
264
 
265
 
266
    SOCMaker::logger.proc( "START of creating top-level '" + file_name + "'" )
267
 
268
 
269
    #
270
    # Create a unique list of cores and
271
    # add every core to your implementation.
272
    # Even if there are multiple instances of a core,
273
    # we need to decalre it only once
274
    #
275
    @cores.values.uniq{|x| x.type }.each do |inst; spec|
276
 
277
      spec = SOCMaker::lib.get_core( inst.type  )
278
      SOCMaker::lib.check_nil( spec, "Can't find #{ inst.type } in SOC library" )
279
 
280
      coder.add_core_declaration( inst.type, spec )
281
    end
282
 
283
   #core_instances = {}
284
   #@cores.each do |inst_name, _core_inst|
285
   #  # the corresponding core from SOC lib
286
   #  core_def = SOCMaker::lib.get_core( _core_inst[ :type ] )
287
   #  core_instances[ inst_name ] = SOCMaker::CoreInst.new( core_def, _core_inst[ :params ] )
288
   #end
289
 
290
 
291
    @cores.each do |inst_name, inst|
292
      coder.add_core_inst( inst_name.to_s, inst )
293
    end
294
 
295
 
296
 
297
    # Iterate over all connections:
298
    #  - create signal instances
299
    #  - add assignments
300
    #
301
    @cons.each do |con_name, con_def|
302
      gen_toplevel_con(   con_name.to_s,
303
                          con_def[ :rule ],
304
                          con_def[ :mapping ][0],
305
                          con_def[ :mapping ][1],
306
      coder  )
307
 
308
    end
309
 
310
    SOCMaker::logger.proc( "writing top-level" )
311
 
312
    file_dir  = File.join( SOCMaker::conf[ :build_dir ],
313
                           SOCMaker::conf[ :hdl_dir   ] )
314
    ::FileUtils.mkdir_p file_dir
315
    file_path = File.join( file_dir, file_name )
316
    File.open( file_path, 'w' ) do |f|
317
      f.write( coder.get_entity( self, "test" ) )
318
    end
319
    SOCMaker::logger.proc( "END of creating top-level" )
320
 
321
  end
322
 
323
 
324
  def gen_toplevel_con( name, rule, src, dst, coder )
325
 
326
    src_inst            = {};
327
    dst_inst            = {};
328
 
329
    # fetch somehow the spec
330
    ifc_spec = SOCMaker::lib.get_ifc(
331
      @cores[ src.keys.first ].defn.interfaces[ src.values.first ].name,
332
      @cores[ src.keys.first ].defn.interfaces[ src.values.first ].version )
333
 
334
    length_tmp = {};
335
 
336
    ifc_spec.ports.keys.each do |_name|
337
 
338
      # create a length table
339
      length_tmp[ _name ] = []
340
      dst.each do |inst_name, ifc_name|
341
        length_tmp[ _name ] << @cores[ inst_name ].get_len( ifc_name, _name )
342
      end
343
      src.each do |inst_name, ifc_name|
344
        length_tmp[ _name ] << @cores[ inst_name ].get_len( ifc_name, _name )
345
      end
346
 
347
    end
348
 
349
    # getting the maximum length for each signal
350
    max_length = Hash[ length_tmp.map{ |key, arr| [ key, arr.max ] } ]
351
 
352
    coder.ifc_declaration( ifc_spec, name, max_length )
353
 
354
 
355
 
356
    src.keys.each do |inst_name|
357
      src_inst[ inst_name ]            = @cores[ inst_name ]
358
    end
359
    dst.keys.each do |inst_name|
360
      dst_inst[ inst_name ]            = @cores[ inst_name ]
361
    end
362
 
363
 
364
 
365
    coder.ifc_assignment( ifc_spec, name, max_length, src_inst, dst_inst, src, dst )
366
 
367
  end
368
 
369
  def copy_files
370
 
371
    SOCMaker::logger.proc( "START of copying all HDL files" )
372
 
373
    #
374
    # Create a unique list of cores and
375
    # for every core, create a directory and copy files
376
    #
377
    @cores.values.uniq{|x| x.type }.each do |core_inst; core_def, dst_dir|
378
 
379
      core_def = SOCMaker::lib.get_core( core_inst.type )
380
 
381
      # create destination directory name and ensure, that it is exist
382
      dst_dir  = get_and_ensure_dst_dir!( core_def.name )
383
 
384
      # copy each file into destination dir
385
      core_def.hdlfiles.each do |file, val|
386
        file_path = File.join( core_def.dir, val.path )
387
        dst_path = File.join( dst_dir, file.to_s )
388
        SOCMaker::logger.proc( "copy #{file_path} to #{ dst_path} " )
389
        FileUtils.cp( file_path, dst_path )
390
      end
391
 
392
 
393
 
394
      #
395
      # handle the static parameters
396
      #   (search and replace in pakckage/include files)
397
      core_def.static_parameters.each do |file, param|
398
 
399
        token_val_map = {}
400
        param.parameters.each do |n,p|
401
 
402
          if  @static[ core_inst.type.to_sym ]      != nil and
403
              @static[ core_inst.type.to_sym ][ n ] != nil
404
 
405
            # use value defined in soc-spec
406
            token_val_map[ p.token ] = @static[ core_inst.type.to_sym ][ n ]
407
          else
408
            # use default value from core-spec
409
            token_val_map[ p.token ] =  p.default
410
          end
411
 
412
        end
413
 
414
        # create file paths
415
        src_path = File.join( core_def.dir, param.path )
416
        dst_dir  = get_and_ensure_dst_dir!( core_def.name )
417
        dst_path = File.join( dst_dir, param.file_dst )
418
 
419
 
420
        # process each line of input file
421
        # and replace tokens by value via
422
        # regular expression
423
        File.open( dst_path, 'w' ) do |dst_f|
424
          File.open( src_path ) do |src_f|
425
            SOCMaker::logger.proc( "create #{dst_path} from #{ src_path} " )
426
            while line = src_f.gets
427
              token_val_map.each { |token, val| line = line.sub( Regexp.new( token.to_s ), val.to_s ) }
428
              dst_f.puts line
429
            end
430
          end
431
        end
432
 
433
 
434
 
435
      end
436
 
437
    end
438
 
439
 
440
    SOCMaker::logger.proc( "END of copying all HDL files" )
441
  end
442
 
443
 
444
  def ==(o)
445
    o.class   == self.class   &&
446
    o.cores   == self.cores   &&
447
    o.cons    == self.cons    &&
448
    o.static  == self.static  &&
449
    super( o )
450
  end
451
 
452
 
453
end # class SOCSpec
454
end # module SOCMaker
455
 
456
 
457
# 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.