class SOCMaker::SOCDef

This class represents a System-on-chip and derives the functionallity from SOCMaker::CoreDef. The two important fields are

In addition, the field @static is used to store static parameters, which are set for cores used in this SOC.

Attributes

cons[RW]

Hash of all connections. The structure is the following

@cons = { :connection_name_1 => {
            :mapping => [
                { :instance_1 => :interface_of_instance_1,  #\   dir=0
                  :instance_2 => :interface_of_instance_2,  #/
                  ...},
                { :instance_3 => :interface_of_instance_3,  #\   dir=1
                  :instance_4 => :interface_of_instance_4,  #/
                  ...}
              ] },

          :connection_name_2 => {
            :mapping => [
                { :instance_a => :interface_of_instance_a,  #\   dir=0
                  :instance_b => :interface_of_instance_b,  #/
                  ...},
                { :instance_c => :interface_of_instance_c,  #\   dir=1
                  :instance_d => :interface_of_instance_d,  #/
                  ...}
              ] },
               ....

              }

The important part is the mapping: it is a list with two entries. Ech entry is a Hash containing instance-interface assignments.

TODO: this needs to be re-designed, because it allowes only one core to be used in one connection-direction.

cores[RW]

Hash of cores (core instances: SOCMaker::CoreInst)

static[RW]

Hash of all static parameters defined within this SOC

Public Class Methods

new( name, id, toplevel, optional = {} ) click to toggle source

This constructor expects the name, an id, the toplevel-name as mandatory arguments. All other attributes can be privided as optional argument

# File lib/soc_maker/soc_def.rb, line 100
def initialize( name, id, toplevel, optional = {} )

  init_with( { 'name'     => name, 
               'id'       => id,
               'toplevel' => toplevel }.merge( optional ) )

end

Public Instance Methods

==(o) click to toggle source

Equality operator

Calls superclass method SOCMaker::CoreDef#==
# File lib/soc_maker/soc_def.rb, line 801
def ==(o)
  o.class   == self.class   &&
  o.cores   == self.cores   &&
  o.cons    == self.cons    &&
  o.static  == self.static  &&
  super( o )
end
add_connection( *args ) click to toggle source

Method add/modify a connection. The number of arguments are variable and multiple entries can be provided as once.

args

number of arguments must be >3 and odd. The first argument defines

the connection name. The following arguments are treaded as pairs. Each pair consists of the instance name and the interface name.

# File lib/soc_maker/soc_def.rb, line 316
def add_connection( *args )

    if args.size < 3 || args.size % 2 != 1
      processing_error "FATAL: wrong number of arguments: " +
                      "(#{args.size}) must be > = 3 and odd"
    end

    consistence_check


    con_name = args[0]
    args[ 1..-1].each_slice(2).to_a.each do |entry| 
      inst_name = entry[0]
      ifc_name  = entry[1]

      # get the core definition
      core_def = core_definition( inst_name ) or 
            consistence_error "Can't find definition of core #{inst_name}" 


      consistence_error_if ifc_in_use?( inst_name, ifc_name ), 
         "Interface #{ifc_name} of instance '#{inst_name}' is already in use " 


      consistence_error_if core_def.interfaces[ ifc_name ] == nil,
        "Interface '#{ifc_name}' dosn't exist in core '#{inst_name}' \n" +
        "The following interfaces do exist:  '#{core_def.interfaces.keys}'"  

      # get the interface specification
      ifc_spc = core_def.ifc_specification( ifc_name )

      # get the directions
      ifc_dir = core_def.interfaces[ ifc_name ].dir

      ifc_dir = ( ifc_dir + 1 ) % 2 if is_it_me?( inst_name )


      # create a new connection, if there is no one
      if @cons[ con_name ] == nil
        @cons[ con_name ] = { mapping: [ {},{} ] }
      end

      if ifc_spc.n_connections_ok?( ifc_dir, @cons[ con_name ][ :mapping ][ ifc_dir ].size+1 )
        @cons[ con_name ][ :mapping ][ ifc_dir ][ inst_name ] = ifc_name
      else
        consistence_error "Only #{ ifc_spc.multiplicity[ ifc_dir ] } " + 
                              "connections are allowed for direction #{ifc_dir}",
                              connection: con_name,
                              instance: inst_name,
                              interface: ifc_name

      end

    end


end
add_core( id, inst_name ) click to toggle source

Add an instance to the SoC

id

the core ID, used to get the desired core from SOCMaker::Lib

inst_name

name of the instance

# File lib/soc_maker/soc_def.rb, line 230
def add_core( id, inst_name )

  consistence_error_if(
    inst_in_use?( inst_name ),
    "Instance name #{inst_name} is already in use"  )

  # check, if the core exits in our library
  #  if not: an error will be raised
  SOCMaker::lib.get_core( id )

  @cores[ inst_name ] = SOCMaker::CoreInst.new( id )
end
all_core_id() click to toggle source

Method to get all id's of all cores, sub-socs (recursively)

# File lib/soc_maker/soc_def.rb, line 783
def all_core_id
  @cores.values.map{ |c| c.defn.all_core_id }.flatten! << @id
end
all_static_parameters() click to toggle source

Method to get all static parameters of all cores, sub-socs (recursively)

# File lib/soc_maker/soc_def.rb, line 791
def all_static_parameters
  tmp = { @id => @static }
  @cores.values.each { |v| tmp.merge!( v.defn.all_static_parameters ) }
  return tmp
end
consistence_check() click to toggle source

Consistence check method:

  • ensures, that all cores are available and consistent

  • ensures, that all connections are possible

Calls superclass method SOCMaker::CoreDef#consistence_check
# File lib/soc_maker/soc_def.rb, line 143
def consistence_check
  super

  @cores.values.each do |inst|
    inst.consistence_check
  end


  @cons.each do |con_name, con_def|
    con_def[ :mapping ].each_with_index do |mapping,dir|
      mapping.each do |inst_name, ifc_name|
        if !is_it_me?( inst_name ) 
          consistence_error "#{inst_name} not does not exist in SOCDef #{@name}" if @cores[ inst_name ] == nil
        end

        core_def = core_definition( inst_name ) or 
              consistence_error "Can't find definition of core #{inst_name}" 

        consistence_error "Interface #{ifc_name} doesn exist in #{core_def.name}" if core_def.interfaces[ ifc_name ] == nil

        consistence_error "Wrong connection definition of #{inst_name}:#{ifc_name}",
          direction: core_def.interfaces[ ifc_name ].dir,
          localtion: dir,
          internal: is_it_me?( inst_name ) if !( 
              ( (core_def.interfaces[ ifc_name ].dir != dir) &&  is_it_me?( inst_name ) ) ||
              ( (core_def.interfaces[ ifc_name ].dir == dir) && !is_it_me?( inst_name ) ) )

      end
    end
  end



end
core_definition( inst ) click to toggle source

Method to get the core definition.

inst

instance name (as symbol)

return

nil, if there is no core with the name and if it is not this SOC

# File lib/soc_maker/soc_def.rb, line 291
def core_definition( inst )
    if @cores[ inst ] != nil
      return @cores[ inst ].defn

    elsif is_it_me?( inst )
      return self
    else
      return nil
    end
end
deploy( options = {} ) click to toggle source

Method, to deploy this SOC: It runs gen_toplevel and calls also super to copy files, which are added in addition to this SOC.

options

Common entries are coder and static:

coder must be a SOCMaker::Coder and static must be a hash of static parameters.

Calls superclass method SOCMaker::CoreDef#deploy
# File lib/soc_maker/soc_def.rb, line 468
def deploy( options = {}  )
  options = { coder: VHDLCoder.new  }.merge( options )
  gen_toplevel( options[ :coder ] )
  super( options )
end
encode_with( coder ) click to toggle source

Encoder method (to yaml)

coder

An instance of the Psych::Coder to encode this class to a YAML file

Calls superclass method SOCMaker::CoreDef#encode_with
# File lib/soc_maker/soc_def.rb, line 113
def encode_with( coder )
  init_error_if !coder.is_a?( Psych::Coder ), 
              'coder is not given as Psych::Coder'
  super coder
  %w[ cores cons static ].
    each { |v| coder[ v ] = instance_variable_get "@#{v}" }
end
gen_toplevel( coder = VHDLCoder.new ) click to toggle source

Generate toplevel hdl file for this instance. This assumes, that this instance represents a SOC with further instances.

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.

# File lib/soc_maker/soc_def.rb, line 521
def gen_toplevel( coder = VHDLCoder.new )


  #
  # Get filename
  #
  file_name = coder.filename( dir_name )
  dst_dir  = CoreDef::get_and_ensure_dst_dir!( dir_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
  #
  @cores.values.uniq{|x| x.type }.each do |inst; spec|

    spec = SOCMaker::lib.get_core( inst.type  )
    processing_error "Can't find #{ inst.type } in SOC library" if !spec

    coder.add_core_component( inst.type, spec )
  end


  top_connections = {}

  #
  # Instanciate each core
  #
  @cores.each do |inst_name, inst|

    # get all connections of this instance, which are connected
    # to top and are single-entry connections
    top_cons_tmp = top_connections( inst_name )
    top_cons_tmp = top_cons_tmp.select{ |k,v|  v[:mapping][0].size == 1 && v[:mapping][1].size == 1 }
    top_cons_tmp.keys.each do |con_name|
      @cons[ con_name ][ :top_assigned ] = true
    end
    coder.add_core_instance( inst_name.to_s, inst, top_cons_tmp, @interfaces, self )
    top_connections.merge!( top_cons_tmp )
  end


  # create a list of all top-interfaces, which are directly connected
  # to cores
  top_connected_ifcs = []
  top_connections.values.each do |con|
    if con[ :mapping ][0].has_key?( @toplevel.to_sym )
      top_connected_ifcs << con[ :mapping ][0][ @toplevel.to_sym ]
    else
      top_connected_ifcs << con[ :mapping ][1][ @toplevel.to_sym ]
    end
  end


  # Iterate over all connections:
  #  - create signal instances
  #  - add assignments
  #
  @cons.each do |con_name, con_def|
    if not con_def[ :top_assigned]
      gen_toplevel_con(   con_name.to_s, 
                          con_def[ :mapping ][0], 
                          con_def[ :mapping ][1],
                          coder  )
    end
  end

  assign_unused_to_default( coder )

  coder.add_toplevel_sig( self, @toplevel, top_connected_ifcs )

  #
  # Write content to the file
  #
  SOCMaker::logger.proc( "writing top-level" )
  File.open( File.join( dst_dir, file_name ), 'w' ) do |f| 
    f.write( coder.get_hdl_code( self, @toplevel ) )
  end
  SOCMaker::logger.proc( "END of creating top-level hdl code for #{@name}" )

  @cons.values.each{ |v| v[ :top_assigned ] = false }


end
get_param( instance, param ) click to toggle source

Method to get an instance parameter

instance

name of the instance

param

name of the parameter

# File lib/soc_maker/soc_def.rb, line 406
def get_param( instance, param )

  # get instance
  core_inst = @cores[ instance ]
  consistence_error "Can't find '#{instance}' in SOC" if core_inst == nil
  param_val = core_inst.params[ param ]
  consistence_error "Can't find parameter '#{param}' in '#{instance}'" if param_val == nil
  return param_val
end
get_sparam( core, param ) click to toggle source

Method to get a static parameter

instance

name of the instance

param

name of the parameter

# File lib/soc_maker/soc_def.rb, line 449
def get_sparam( core, param )
  consistence_error "Core '#{core}' does not exist in this SOC" if  @static[ core ] == nil

  consistence_error "Parameter '#{param}' does not exist for core '#{core}'" if @static[ core ][ param ] == nil

  return @static[ core ][ param ]
end
ifc_in_use?( inst_name, ifc_name ) click to toggle source

Method to check, if the interface of an instance is already connected

inst_name

name of the instance

ifc_name

name of the interface

# File lib/soc_maker/soc_def.rb, line 251
def ifc_in_use?( inst_name, ifc_name )

  # go through all connections and check,
  # that non of the interfaces we want to connect is used
  @cons.each do |_con_name, con_def|
    return true if con_def[ :mapping ][ 0 ][ inst_name] == ifc_name 
    return true if con_def[ :mapping ][ 1 ][ inst_name] == ifc_name   
  end
  return false

end
init_with( coder ) click to toggle source

Initialization method (from yaml)

coder

An instance of the Psych::Coder to init this class from a YAML file

Calls superclass method SOCMaker::CoreDef#init_with
# File lib/soc_maker/soc_def.rb, line 127
def init_with( coder )
  init_error_if !( coder.is_a?( Hash ) || coder.is_a?( Psych::Coder ) ), 
              'coder is not given as Hash neither as Psych::Coder'
  super coder
  @cores  = coder[ 'cores'  ] || {}
  @static = coder[ 'static' ] || {}
  @cons   = coder[ 'cons'   ] || {}
end
inst_connections( inst_name ) click to toggle source

Method to get all connections of an instance

inst_name

Instance name (as symbol)

return

A connection hash

# File lib/soc_maker/soc_def.rb, line 481
def inst_connections( inst_name )
  connections = {};
  @cons.each do |con_name, con|
    if con[ :mapping ][ 0 ].select{ |k,v| k == inst_name }.size > 0 ||
       con[ :mapping ][ 1 ].select{ |k,v| k == inst_name }.size > 0
      connections[ con_name ] = con
    end
  end
  return connections
end
inst_in_use?( inst_name ) click to toggle source

Check, if the instance name is already used within this SOC

# File lib/soc_maker/soc_def.rb, line 198
def inst_in_use?( inst_name )
  return ( @cores[ inst_name ] != nil or @cons[ inst_name ]  != nil )
end
is_it_me?( inst_name ) click to toggle source

Method to check, if inst_name means this SOC. For connecting cores, the instance name is used. But If a toplevel connection to a core needs to be done, the SOC is identified by @toplevel (even if this is not an instance)

inst_name

name of instance

return

true if inst_name == @toplevel.to_sym, otherwise false

# File lib/soc_maker/soc_def.rb, line 188
def is_it_me?( inst_name )
  # TODO: is there a better way to identify self via @toplevel?
  inst_name == @toplevel.to_sym
end
port( ifc_name, port_ref ) click to toggle source

Returns a port, identified by the interface and port name Note: this behaviour is exactly the same than of core_inst.port(…), but these ports are not evaluated.

ifc_name

name of the interface

port_ref

name of the port

# File lib/soc_maker/soc_def.rb, line 751
def port( ifc_name, port_ref )

  ifc = @interfaces[ ifc_name ]

  # get interface specification
  ifc_spc = SOCMaker::lib.get_ifc( ifc.id )

  # get the port
  port_tmp = ifc.ports.select{ |k,v| v.spc_ref.to_sym == port_ref }

  # get the reference to the port definition
  defn_ref = port_tmp.first[1].spc_ref.to_sym

  _port_name = port_tmp.first[0].to_s

  if ifc_spc.ports[ defn_ref ][ :dir ] == 2
    _port_dir = 1 ^ ifc.dir
  else
    _port_dir = ifc_spc.ports[ defn_ref ][ :dir ] ^ ifc.dir
  end

  _port_default = ifc_spc.ports[ defn_ref ][ :default ] 

  _port_len = port_tmp.first[1].len

  return [ _port_name, { len: _port_len, dir: _port_dir, default: _port_default, ref: port_tmp.first[1].spc_ref } ]
end
port_length( ifc_name, port_name, inst ) click to toggle source

Method to get the port length. All arguments as symbol.

ifc_name

name of the interface

port_name

name of the port

inst

name of the instance

# File lib/soc_maker/soc_def.rb, line 271
def port_length( ifc_name, port_name, inst )
  if @cores[ inst ] != nil
    return @cores[ inst ].port_length( ifc_name, port_name )
  elsif is_it_me?( inst )
    tmp =  @interfaces[ ifc_name ].ports.select{ |k,v| v.spc_ref == port_name.to_s }
    return tmp.values.first.len
  else
    return nil
  end 
end
rm( inst_name ) click to toggle source

Method to remove a instance

# File lib/soc_maker/soc_def.rb, line 205
def rm( inst_name )

  if @cores[ inst_name ] != nil 
    @cores.delete( inst_name )

    # remove all connection entries of this core
    @cons.each do |_con_name, con_def|
      con_def[ :mapping ][ 0 ].delete( inst_name ) if con_def[ :mapping ][ 0 ].has_key?( inst_name )
      con_def[ :mapping ][ 1 ].delete( inst_name ) if con_def[ :mapping ][ 1 ].has_key?( inst_name )
    end

  elsif @cons[ inst_name ]  != nil
    @cons.delete( inst_name )
  else
    consistence_error( "Can't remove instance #{inst_name}" )
  end
end
set_param( instance, param, value ) click to toggle source

Method to set an instance parameter

instance

name of the instance

param

name of the parameter

vlue

value, which is set

# File lib/soc_maker/soc_def.rb, line 382
def set_param( instance, param, value )

  # get instance
  core_inst = @cores[ instance ]
  consistence_error "Can't find '#{instance}' in SOC" if  core_inst == nil

  # get the core-definition
  core_def = SOCMaker::lib.get_core( core_inst.type  )

  # check if parameter exist
  if core_def.inst_parameters[ param ] != nil 
    core_inst.params[ param ] = value
  else
    consistence_error "Parameter '#{param}' not found in '#{core_def.name}'"
  end

end
set_sparam( core, param, value ) click to toggle source

Method to set a static parameter

instance

name of the instance

param

name of the parameter

vlue

value, which is set

# File lib/soc_maker/soc_def.rb, line 424
def set_sparam( core, param, value )

  #get instance

  # check, if we are instantiating this core
  processing_error_if( @cores.select{ |name,inst| inst.type == core }.size == 0,
    "Core '#{core}' is not instantiated in this SOC" )

  # get the core-definition
  core_def = SOCMaker::lib.get_core( core )

  # check if parameter exist
  processing_error_if( core_def.static_parameters.select{ |f,p| p.parameters[ param ] != nil }.size == 0,
      "Parameter '#{param}' not found in '#{core_def.name}'" )

  @static[ core ] ||= {}
  @static[ core ][ param ] = value
end
to_s() click to toggle source

Returns a string describing this instance

Calls superclass method SOCMaker::CoreDef#to_s
# File lib/soc_maker/soc_def.rb, line 813
def to_s

  tmp = "_________ SOC #{@name}: _______\n"     + 
        super                                   +
        "\n__connections__\n"                     

  @cons.each do |_con_name, con_def|
    tmp += "#{_con_name}: #{con_def}\n"
  end 

  tmp += "\n__cores__\n" 
  @cores.each do |inst_name, inst|
    tmp += "#{inst_name}:\n#{inst}\n"
  end 


  tmp += "\n__interfaces__\n"
  @interfaces.each do |ifc_name, ifc|
    tmp += "#{ifc_name}:#{ifc.id}\n"
  end

  tmp += "'''''''''''''''''''''''''''''''''''\n"
  return tmp
end
top_connections( inst_name ) click to toggle source

Method to get all connections which connected to the top

inst_name

Instance name (as symbol)

return

A connection hash

# File lib/soc_maker/soc_def.rb, line 499
def top_connections( inst_name )
  inst = inst_connections( inst_name )
  top  = inst_connections( toplevel.to_sym )

  tmp = inst.keys & top.keys
  return inst.select{ |k,v| tmp.include?( k ) }
end

Private Instance Methods

assign_unused_to_default( coder ) click to toggle source

Assign default values for unused interfaces. This is just a helper function and is used by gen_toplevel

coder

A HDL coder, which is used to create the auto-generated HDL.

# File lib/soc_maker/soc_def.rb, line 622
def assign_unused_to_default( coder )



  # iterate over all instances
  # and check all interfaces
  @cores.each do |inst_name, inst|

    inst.defn.interfaces.each do |ifc_name, ifc|

      #
      # Get the interface specification by using the 1st source entry
      # and searching for the core-definition.
      #
      if !ifc_in_use?( inst_name, ifc_name )
        coder.add_ifc_default_assignment(  inst, inst_name, ifc_name )
      end
    end
  end
end
core_instance( inst ) click to toggle source

Returns a core instance, identified by its name. If it is not a sub-core, we return our self

inst

name of the instance

# File lib/soc_maker/soc_def.rb, line 735
def core_instance( inst )
  if @cores[ inst ] != nil
    return @cores[ inst ]
  else
    return self
  end
end
gen_toplevel_con( name, src, dst, coder ) click to toggle source

This function is called during the toplevel generation for each connection.

name

The name of the connection

src

Source hash with instance name as key and interface name as value

dst

Destination hash with instance name as key and interface name as value

coder

The HDL coder which is used

# File lib/soc_maker/soc_def.rb, line 652
def gen_toplevel_con( name, src, dst, coder )

  src_inst            = {};
  dst_inst            = {};

  #
  # Get the interface specification by using the 1st source entry
  # and searching for the core-definition.
  #
  ifc_spec = SOCMaker::lib.get_ifc( 
    core_definition( src.keys.first ).interfaces[ src.values.first ].id )


  #
  # For each signal in the interface specification,
  # we create a list. The list has an entry for each source
  # and destination signal, which defines the length.
  #
  # In the second step, we compare all values
  #
  length_tmp  = Hash.new(0);
  ifc_spec.ports.keys.each do |_name|
    length_tmp[ _name ] = 0

    ref_val       = nil;
    ref_inst_name = nil;
    ref_ifc_name  = nil;


    [ dst, src].each do |con_hash|

      con_hash.each_with_index do | (inst_name, ifc_name), i|

        length = port_length( ifc_name, _name, inst_name )
        if length.to_i > 0
          if ref_val == nil
            ref_val       = port_length( ifc_name, _name, inst_name )
            ref_inst_name = inst_name
            ref_ifc_name  = ifc_name
            length_tmp[ _name ] = ref_val
          end

          consistence_error "Can't connect port #{_name}",
              length_1:     ref_val,
              instance_1:   ref_inst_name,
              interface_1:  ref_ifc_name,
              length_2:     length,
              instance_2:   inst_name,
              interface_2:  ifc_name if ref_val.to_i != length.to_i

          length_tmp[ _name ] = length
        end
      end 
    end
  end


  #
  # Prepare a hash for all sources and destinations, where
  # the instance name is the key and the core-instance is
  # the value.
  #
  src.keys.each do |inst_name|
    src_inst[ inst_name ] = core_instance( inst_name )
  end
  dst.keys.each do |inst_name|
    dst_inst[ inst_name ] = core_instance( inst_name )
  end

  #
  # create the declaraion and assignments
  #
  coder.add_ifc_connection( ifc_spec, name, length_tmp, src_inst, dst_inst, src, dst )

end