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

Subversion Repositories soc_maker

[/] [soc_maker/] [trunk/] [lib/] [soc_maker/] [core_inst.rb] - Diff between revs 8 and 9

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 8 Rev 9
Line 29... Line 29...
#   You should have received a copy of the GNU General Public License
#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see .
#   along with this program.  If not, see .
#
#
#
#
###############################################################
###############################################################
 
 
 
 
 
module SOCMaker
 
 
 
######
#
#
#   Description:
 
#     This class represents a core instantiation within
#     This class represents a core instantiation within
#     a SOC. It contains a params (parameters) hash,
# a SOC. It contains a parameter-hash (@params),
#     which defines, which parameters are set to which values.
# which is used to define, which parameters are set to which values.
#     The type field is used to identify the SOCMaker::CoreDef
#     The type field is used to identify the SOCMaker::CoreDef
#     and the field @defn is initialized as reference to
#     and the field @defn is initialized as reference to
#     the corresponding CoreDef instance.
#     the corresponding CoreDef instance.
#
 
#
 
###############################################################
 
 
 
 
 
module SOCMaker
 
class CoreInst
class CoreInst
  include ERR
  include ERR
 
 
 
 
 
 
Line 57... Line 55...
  def initialize(  type, params = {} )
  def initialize(  type, params = {} )
    init_with(  'type'   => type,
    init_with(  'type'   => type,
                'params' => params  )
                'params' => params  )
 
 
  end
  end
 
 
 
  #
 
  # Encoder function (to yaml)
 
  #
 
  # +coder+:: An instance of the Psych::Coder to encode this class to a YAML file
 
  #
  def encode_with( coder )
  def encode_with( coder )
    %w[ type params ].
    %w[ type params ].
      each { |v| coder[ v ] = instance_variable_get "@#{v}" }
      each { |v| coder[ v ] = instance_variable_get "@#{v}" }
  end
  end
 
 
 
  #
 
  # Initialization function (from yaml)
 
  #
 
  # +coder+:: An instance of the Psych::Coder to init this class from a YAML file
 
  #
 
  #
  def init_with( coder )
  def init_with( coder )
 
 
    serr_if( coder[ 'type' ] == nil,
    serr_if( coder[ 'type' ] == nil,
      "no type is provided for a core instance",
      "no type is provided for a core instance",
      field: "type" )
      field: "type" )
Line 76... Line 86...
    serr_if( !@params.is_a?( Hash ), 'Parameters are not given as hash',
    serr_if( !@params.is_a?( Hash ), 'Parameters are not given as hash',
      field: 'params' )
      field: 'params' )
 
 
  end
  end
 
 
  def ports( *args )
 
    if args.size == 0
 
      @ports.each_with_index do |(name, port_def), i|
 
        yield( name.to_s, port_def[ :dir ], port_def[ :len ], port_def[ :default ], i==@ports.size-1 )
 
      end
 
    elsif args.size == 1
 
      @ifcs[ args.first.to_sym  ].each do |name, port_def, i|
 
        yield( name.to_s, port_def[ :dir ], port_def[ :len ], port_def[ :default ], i==@ports.size-1 )
 
      end
 
    end
 
  end
 
 
 
 
 
  def generics
 
    @defn.generics do |name, type, default_value, is_last|
 
      value = @params[ name.to_sym ];
 
      value = value
 
      value = default_value if value == nil
 
      yield( name.to_s, type, value, is_last )
 
    end
 
  end
 
 
 
 
 
 
 
 
 
 
 
 
 
  #
  #
  # Get a port, identified by the interface and port name
  # Runs a consistency check and creates an internal
 
  # hash, which contains all evaluated ports.
 
  # Because the core-definition may contain variable port sizes,
 
  # which depend on the instance, these sizes need to be evaluated.
 
  # This is also done here and the result is stored in @_ifcs_evaluated.
  #
  #
  #  +ifc_name+::       name of the interface
 
  #  +port_spec_name+:: name of the port
 
  #
  #
  def get_port( ifc_name, port_spec_name )
 
    tmp = @defn.interfaces[ ifc_name.to_sym ].
 
        ports.select{ |key,hash| hash.defn == port_spec_name.to_s }.
 
        keys.first.to_s
 
    return [ tmp, @ports[ tmp.to_sym ] ]
 
  end
 
 
 
 
 
  # TODO do we need this?
 
  #
 
  #
 
# def implements_port?( ifc_name, port_spec_name )
 
#   @defn.implements_port?( ifc_name, port_spec_name )
 
# end
 
 
 
 
 
  def consistency_check
  def consistency_check
 
 
    @defn = SOCMaker::lib.get_core( @type )
    @defn = SOCMaker::lib.get_core( @type )
 
 
 
 
Line 144... Line 116...
 
 
      # auto-complete to default values
      # auto-complete to default values
      @params[ param_name ] ||= param.default
      @params[ param_name ] ||= param.default
    end
    end
 
 
 
    @_ifcs_evaluated ||= {}
#   @_params ||= {}
    @defn.interfaces.keys.each do |ifc_name|
#   if @params != nil
      @_ifcs_evaluated[ ifc_name ] = {}
#     @params.each do |name, val|
      @defn.ports( ifc_name.to_s ) do |port_name, port_dir, port_len, default, is_last |
#
 
#       param_type = defn.inst_parameters[ name ].type
 
#
 
#       if val.is_a? String
 
#         eval_match = SOCMaker::conf[ :eval_regex ].match( val )
 
#         #TODO error handling
 
#         if eval_match
 
#           #eval_func = eval_match.captures[0]
 
#           @_params[ name ] = { value: eval( eval_str ).to_s, type: param_type }
 
#         else
 
#           @_params[ name ] = { value: val, type: param_type }
 
#         end
 
#       else
 
#         @_params[ name ] = { value: val, type: param_type }
 
#       end
 
#     end
 
#   end
 
 
 
 
 
    #
 
    #  TODO merge these two loops and create one hash
 
    ###
 
    #
 
    # create our own ports hash
 
    #
 
    @ports ||= {}
 
    @defn.ports do |port_name, port_dir, port_len, default, is_last |
 
      if port_len.is_a?( String )
      if port_len.is_a?( String )
        param_match = SOCMaker::conf[ :length_regex ].match( port_len )
        param_match = SOCMaker::conf[ :length_regex ].match( port_len )
 
 
        if param_match and @params[ port_len.to_sym ] != nil
        if param_match and @params[ port_len.to_sym ] != nil
          tmp =@params[ port_len.to_sym ]
          tmp =@params[ port_len.to_sym ]
          tmp = tmp.to_i if tmp.is_a?( String )
          tmp = tmp.to_i if tmp.is_a?( String )
          @ports[ port_name.to_sym ] = { len: tmp, dir: port_dir, default: default }
            @_ifcs_evaluated[ ifc_name ][ port_name.to_sym ] = { len: tmp, dir: port_dir, default: default }
        else
        else
          SOCMaker::logger.error( "Failed to evaluate #{port_len} for port #{port_name}" )
          SOCMaker::logger.error( "Failed to evaluate #{port_len} for port #{port_name}" )
        end
        end
      else
      else
        @ports[ port_name.to_sym ] = { len: port_len, dir: port_dir, default: default }
          @_ifcs_evaluated[ ifc_name ][ port_name.to_sym ] = { len: port_len, dir: port_dir, default: default }
 
        end
      end
      end
    end
    end
 
 
 
    @defn.consistency_check
 
  end
 
 
    @ifcs ||= {}
 
    @defn.interfaces.keys.each do |ifc_name|
 
      @ifcs[ ifc_name ] = {}
 
      @defn.ports( ifc_name ) do |port_name, port_dir, port_len, default, is_last |
 
 
 
        if port_len.is_a?( String )
 
          param_match = SOCMaker::conf[ :length_regex ].match( port_len )
 
 
 
          if param_match and @params[ port_len.to_sym ] != nil
 
            tmp =@params[ port_len.to_sym ]
  #
            tmp = tmp.to_i if tmp.is_a?( String )
  # Generate toplevel hdl file for this instance.
            @ifcs[ ifc_name ][ port_name.to_sym ] = { len: tmp, dir: port_dir, default: default }
  # This assumes, that this instance represents a SOC with
          else
  # further instances.
            SOCMaker::logger.error( "Failed to evaluate #{port_len} for port #{port_name}" )
  #
 
  #
 
  # +coder+:: An instance of the SOCMaker::HDLCoder, which is used to
 
  #           create the auto-generated HDL (optional).
 
  #           If no coder is given, a SOCMaker::VHDLCoder is used.
 
  #
 
  #
 
  def gen_toplevel( coder = VHDLCoder.new )
 
 
 
 
 
    #
 
    # Get filename
 
    #
 
    file_name = coder.filename( @defn.name )
 
 
 
    SOCMaker::logger.proc( "START of creating top-level '" + file_name + "'" )
 
 
 
 
 
    #
 
    # Create a unique list of cores and
 
    # add for each core a component statement (vhdl only).
 
    # Even if there are multiple instances of a core,
 
    # we need to decalre it only once
 
    #
 
    @defn.cores.values.uniq{|x| x.type }.each do |inst; spec|
 
 
 
      spec = SOCMaker::lib.get_core( inst.type  )
 
      SOCMaker::lib.check_nil( spec, "Can't find #{ inst.type } in SOC library" )
 
 
 
      coder.add_core_component( inst.type, spec )
          end
          end
        else
 
          @ifcs[ ifc_name ][ port_name.to_sym ] = { len: port_len, dir: port_dir, default: default }
    #
 
    # Instanciate each core
 
    #
 
    @defn.cores.each do |inst_name, inst|
 
      coder.add_core_instance( inst_name.to_s, inst )
        end
        end
 
 
 
 
 
 
 
    # Iterate over all connections:
 
    #  - create signal instances
 
    #  - add assignments
        #
        #
        #puts "#{port_def_ref}, #{port_name}, #{port_dir}, #{port_default}"
    @defn.cons.each do |con_name, con_def|
 
      gen_toplevel_con(   con_name.to_s,
 
                          con_def[ :rule ],
 
                          con_def[ :mapping ][0],
 
                          con_def[ :mapping ][1],
 
                          coder  )
 
 
      end
      end
 
 
 
    assign_unused_to_default( coder )
 
 
 
    #
 
    # Write content to the file
 
    #
 
    SOCMaker::logger.proc( "writing top-level" )
 
    file_dir  = File.join( SOCMaker::conf[ :build_dir ],
 
                           SOCMaker::conf[ :hdl_dir   ] )
 
    ::FileUtils.mkdir_p file_dir
 
    File.open( File.join( file_dir, file_name ), 'w' ) do |f|
 
      f.write( coder.get_hdl_code( self, @defn.name ) )
    end
    end
 
    SOCMaker::logger.proc( "END of creating top-level hdl code for #{@defn.name}" )
 
 
#   lerr_if( @defn == nil, 'Core not found in lib',
  end
#     field:    'cores'    )
 
 
 
 
 
    @defn.consistency_check
 
 
 
 
  #
 
  # Iterate over all ports and call the block with
 
  #   - port-name
 
  #   - port length
 
  #   - default value
 
  #   - is-last value
 
  #
 
  #  If no argument is given, all ports of this instance are processed.
 
  #  If arguments are given, each argument is supposed to the name of
 
  #  a interface. All specified interfaces with all ports are processed.
 
  #
 
  # +args+::  Optional list of interface names
 
  #
 
  #
 
  def ports( *args )
 
 
 
    if args.size == 0
 
      ifc_sel = @_ifcs_evaluated
 
    else
 
      ifc_sel = @_ifcs_evaluated.select{ |k,v| args.include?( k.to_s ) }
 
    end
 
 
 
    ifc_sel.each_with_index do |(ifc_name, ifc), i_ifc|
 
      ifc.each_with_index do |(port_name, port_def), i_port|
 
        yield(  port_name.to_s,
 
                port_def[ :dir ],
 
                port_def[ :len ],
 
                port_def[ :default ],
 
                i_port==ifc.size-1 && i_ifc == ifc_sel.size-1 )
 
      end
 
    end
 
  end
 
 
 
  #
 
  # Iterate over all generics and call the block with
 
  #   - generic-name
 
  #   - generic-type
 
  #   - the value
 
  #   - is-last information
 
  #
 
  def generics
 
    @defn.generics do |name, type, default_value, is_last|
 
      value = @params[ name.to_sym ];
 
      value = value
 
      value = default_value if value == nil
 
      yield( name.to_s, type, value, is_last )
 
    end
  end
  end
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  #
 
  # Returns a port, identified by the interface and port name
 
  #
 
  #  +ifc_name+::       name of the interface
 
  #  +port_spec_name+:: name of the port
 
  #
 
  def port( ifc_name, port_spec_name )
 
    tmp = @defn.interfaces[ ifc_name.to_sym ].
 
        ports.select{ |key,hash| hash.defn == port_spec_name.to_s }.
 
        keys.first.to_s
 
    return [ tmp, @_ifcs_evaluated[ ifc_name.to_sym ][ tmp.to_sym ] ]
 
  end
 
 
  #
  #
  # Returns the length of a port within an interface.
  # Returns the length of a port within an interface.
  # If no instance is given, we know that it is
  # If no instance is given, we know that it is
  # a toplevel interface.
  # a toplevel interface.
  # Otherwise we check for this and we do a recursive call.
  # Otherwise we check for this and we do a recursive call.
Line 238... Line 299...
  #
  #
  # +ifc_name+::        name of the interface
  # +ifc_name+::        name of the interface
  # +port_spec_name+::  name of the port
  # +port_spec_name+::  name of the port
  # +inst+::            name of the instance (optional), default is nil
  # +inst+::            name of the instance (optional), default is nil
  #
  #
  def get_port_len( ifc_name, port_spec_name, inst = nil )
  def port_length( ifc_name, port_spec_name, inst = nil )
    if inst == nil
    if inst == nil
      tmp = @defn.interfaces[ ifc_name.to_sym ].
      tmp = @defn.interfaces[ ifc_name.to_sym ].
          ports.select{ |key,hash| hash.defn == port_spec_name.to_s }.
          ports.select{ |key,hash| hash.defn == port_spec_name.to_s }.
          keys.first.to_s
          keys.first.to_s
      return tmp.size == 0 ? 0 : @ports[ tmp.to_sym ][ :len ]
      return tmp.size == 0 ? 0 : @_ifcs_evaluated[ ifc_name.to_sym ][ tmp.to_sym ][ :len ]
    else
    else
      if inst == @defn.name.to_sym
      if inst == @defn.name.to_sym
        return get_port_len( ifc_name, port_spec_name )
        return port_length( ifc_name, port_spec_name )
      else
      else
        return @defn.get_port_len( ifc_name, port_spec_name, inst )
        return @defn.port_length( ifc_name, port_spec_name, inst )
      end
      end
    end
    end
  end
  end
 
 
 
 
  #
  #
  # Returns the core definition for an instance (identified by its name)
  # Returns the core definition for an instance (identified by its name)
  #
  #
  # +inst+:: name of the instance
  # +inst+:: name of the instance
  #
  #
  def get_core_def( inst )
  def core_definition( inst )
      if inst == @defn.name
      if inst == @defn.name
        return @defn
        return @defn
      else
      else
        tmp = @defn.get_core_def( inst )
        tmp = @defn.core_definition( inst )
        perr_if( tmp == nil, "#Processing error: {inst} not found by get_core_def" )
        perr_if( tmp == nil, "#Processing error: {inst} not found by core_definition" )
        return tmp
        return tmp
      end
      end
  end
  end
 
 
 
 
  #
  #
  # Returns a core instance, identified by its name.
  # Returns a core instance, identified by its name.
  # If it is not a sub-core, we return our self
  # If it is not a sub-core, we return our self
  #
  #
  # +inst+::  name of the instance
  # +inst+::  name of the instance
  #
  #
  def get_core_inst( inst )
  def core_instance( inst )
    if @defn.cores[ inst ] != nil
    if @defn.cores[ inst ] != nil
      return @defn.cores[ inst ]
      return @defn.cores[ inst ]
    else
    else
      return self
      return self
    end
    end
  end
  end
 
 
 
 
  #
 
  # Generate toplevel hdl file for this instance.
 
  # This assumes, that this instance represents a SOC with
 
  # further instances.
 
  #
 
  #
 
  # +coder+:: A HDL coder, which is used to create the auto-generated HDL (optional).
 
  #           If no coder is given, a VHDLCoder is used.
 
  #
 
  #
 
  def gen_toplevel( coder = VHDLCoder.new )
 
 
 
 
 
    #
 
    # Get filename
 
    #
 
    file_name = coder.filename( @defn.name )
 
 
 
    SOCMaker::logger.proc( "START of creating top-level '" + file_name + "'" )
 
 
 
 
 
    #
    #
    # Create a unique list of cores and
  # Returns a string describing this instance
    # add for each core a component statement (vhdl only).
 
    # Even if there are multiple instances of a core,
 
    # we need to decalre it only once
 
    #
    #
    @defn.cores.values.uniq{|x| x.type }.each do |inst; spec|
  def to_s
 
    "type:     #{type}\n"   +
      spec = SOCMaker::lib.get_core( inst.type  )
    "params:   #{params}\n"
      SOCMaker::lib.check_nil( spec, "Can't find #{ inst.type } in SOC library" )
 
 
 
      coder.add_core_component( inst.type, spec )
 
    end
    end
 
 
    #
    #
    # Instanciate each core
  # Equality operator
    #
    #
    @defn.cores.each do |inst_name, inst|
  def ==(o)
      coder.add_core_instance( inst_name.to_s, inst )
    o.class     == self.class   &&
 
    o.type      == self.type    &&
 
    o.params    == self.params
    end
    end
 
 
 
 
 
 
    # Iterate over all connections:
 
    #  - create signal instances
 
    #  - add assignments
 
    #
 
    @defn.cons.each do |con_name, con_def|
 
      gen_toplevel_con(   con_name.to_s,
 
                          con_def[ :rule ],
 
                          con_def[ :mapping ][0],
 
                          con_def[ :mapping ][1],
 
                          coder  )
 
 
 
    end
 
 
 
    assign_unused_to_default( coder )
 
 
 
 
 
    #
 
    # Write content to the file
 
    #
 
    SOCMaker::logger.proc( "writing top-level" )
 
    file_dir  = File.join( SOCMaker::conf[ :build_dir ],
 
                           SOCMaker::conf[ :hdl_dir   ] )
 
    ::FileUtils.mkdir_p file_dir
 
    File.open( File.join( file_dir, file_name ), 'w' ) do |f|
 
      f.write( coder.get_hdl_code( self, @defn.name ) )
 
    end
 
    SOCMaker::logger.proc( "END of creating top-level hdl code for #{@defn.name}" )
 
 
 
  end
 
 
 
 
 
 
 
 
 
  #
  #
  # Assign default values for unused interfaces.
  # Assign default values for unused interfaces.
Line 398... Line 406...
      end
      end
    end
    end
  end
  end
 
 
 
 
 
 
  #
  #
  # This function is called during the toplevel generation
  # This function is called during the toplevel generation
  # for each connection.
  # for each connection.
  #
  #
  # +name+::   The name of the connection
  # +name+::   The name of the connection
Line 419... Line 426...
    #
    #
    # Get the interface specification by using the 1st source entry
    # Get the interface specification by using the 1st source entry
    # and searching for the core-definition.
    # and searching for the core-definition.
    #
    #
    ifc_spec = SOCMaker::lib.get_ifc(
    ifc_spec = SOCMaker::lib.get_ifc(
      get_core_def( src.keys.first.to_s ).interfaces[ src.values.first ].name,
      core_definition( src.keys.first.to_s ).interfaces[ src.values.first ].name,
      get_core_def( src.keys.first.to_s ).interfaces[ src.values.first ].version )
      core_definition( src.keys.first.to_s ).interfaces[ src.values.first ].version )
 
 
 
 
    #
    #
    # Get the maximum required signal length
    # Get the maximum required signal length
    #
    #
Line 436... Line 443...
    #
    #
    length_tmp  = {};
    length_tmp  = {};
    ifc_spec.ports.keys.each do |_name|
    ifc_spec.ports.keys.each do |_name|
      length_tmp[ _name ] = []
      length_tmp[ _name ] = []
      dst.each do |inst_name, ifc_name|
      dst.each do |inst_name, ifc_name|
        length_tmp[ _name ] << get_port_len( ifc_name, _name, inst_name )
        length_tmp[ _name ] << port_length( ifc_name, _name, inst_name )
      end
      end
      src.each do |inst_name, ifc_name|
      src.each do |inst_name, ifc_name|
        length_tmp[ _name ] << get_port_len( ifc_name, _name, inst_name )
        length_tmp[ _name ] << port_length( ifc_name, _name, inst_name )
      end
      end
    end
    end
    max_length = Hash[ length_tmp.map{ |key, arr| [ key, arr.max ] } ]
    max_length = Hash[ length_tmp.map{ |key, arr| [ key, arr.max ] } ]
 
 
 
 
Line 451... Line 458...
    # Prepare a hash for all sources and destinations, where
    # Prepare a hash for all sources and destinations, where
    # the instance name is the key and the core-instance is
    # the instance name is the key and the core-instance is
    # the value.
    # the value.
    #
    #
    src.keys.each do |inst_name|
    src.keys.each do |inst_name|
      src_inst[ inst_name ]            = get_core_inst( inst_name )
      src_inst[ inst_name ] = core_instance( inst_name )
    end
    end
    dst.keys.each do |inst_name|
    dst.keys.each do |inst_name|
      dst_inst[ inst_name ]            = get_core_inst( inst_name )
      dst_inst[ inst_name ] = core_instance( inst_name )
    end
    end
 
 
    #
    #
    # create the declaraion and assignments
    # create the declaraion and assignments
    #
    #
    coder.add_ifc_connection( ifc_spec, name, max_length, src_inst, dst_inst, src, dst )
    coder.add_ifc_connection( ifc_spec, name, max_length, src_inst, dst_inst, src, dst )
 
 
  end
  end
 
 
 
 
  #
 
  # Returns a string describing this instance
 
  #
 
  def to_s
 
    "type:     #{type}\n"   +
 
    "params:   #{params}\n"
 
  end
 
 
 
  #
 
  # Equal operator
 
  #
 
  def ==(o)
 
    o.class     == self.class   &&
 
    o.type      == self.type    &&
 
    o.params    == self.params
 
  end
 
 
 
  # TODO
 
#  private: assign_unused_to_default, :gen_toplevel_con
 
 
 
 
 
 
 
 
 
 
  private :assign_unused_to_default, :gen_toplevel_con
 
 
 
 
 
 
end # CoreInst
end # CoreInst
end # SOCMaker
end # SOCMaker
 
 
 
 

powered by: WebSVN 2.1.0

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