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
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.
Hash of cores (core instances: SOCMaker::CoreInst
)
Hash of all static parameters defined within this SOC
Public Class Methods
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
Equality operator
# 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
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 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
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
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 method:
-
ensures, that all cores are available and consistent
-
ensures, that all connections are possible
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
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
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.
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
Encoder method (to yaml)
coder
-
An instance of the Psych::Coder to encode this class to a YAML file
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
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, aSOCMaker::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
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
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
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
Initialization method (from yaml)
coder
-
An instance of the Psych::Coder to init this class from a YAML file
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
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
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
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
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
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
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
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
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
Returns a string describing this instance
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
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 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
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
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