###############################################################
|
###############################################################
|
#
|
#
|
# File: core_inst.rb
|
# File: core_inst.rb
|
#
|
#
|
# Author: Christian Hättich
|
# Author: Christian Hättich
|
#
|
#
|
# Project: System-On-Chip Maker
|
# Project: System-On-Chip Maker
|
#
|
#
|
# Target: Linux / Windows / Mac
|
# Target: Linux / Windows / Mac
|
#
|
#
|
# Language: ruby
|
# Language: ruby
|
#
|
#
|
#
|
#
|
###############################################################
|
###############################################################
|
#
|
#
|
#
|
#
|
# Copyright (C) 2014 Christian Hättich - feddischson [ at ] opencores.org
|
# Copyright (C) 2014 Christian Hättich - feddischson [ at ] opencores.org
|
#
|
#
|
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
# (at your option) any later version.
|
# (at your option) any later version.
|
#
|
#
|
# This program is distributed in the hope that it will be useful,
|
# This program is distributed in the hope that it will be useful,
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
#
|
#
|
# 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
|
|
|
|
|
|
|
attr_accessor :defn
|
attr_accessor :defn
|
attr_accessor :type
|
attr_accessor :type
|
attr_accessor :params
|
attr_accessor :params
|
|
|
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" )
|
|
|
@type = coder[ 'type' ]
|
@type = coder[ 'type' ]
|
|
|
@params = coder[ 'params' ] || {}
|
@params = coder[ 'params' ] || {}
|
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 )
|
|
|
|
|
# check, if the instance parameters in the core definition
|
# check, if the instance parameters in the core definition
|
@params.each do |param_name, value|
|
@params.each do |param_name, value|
|
verr_if( @defn.inst_parameters[ param_name ] == nil,
|
verr_if( @defn.inst_parameters[ param_name ] == nil,
|
"Parameter not found: " + param_name.to_s,
|
"Parameter not found: " + param_name.to_s,
|
field: 'params' )
|
field: 'params' )
|
end
|
end
|
|
|
## auto-complete parameters with default values
|
## auto-complete parameters with default values
|
@defn.inst_parameters.each do |param_name, param|
|
@defn.inst_parameters.each do |param_name, param|
|
|
|
# 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.
|
# If this port is within a interface of a core, we
|
# If this port is within a interface of a core, we
|
# pass the call to the core-definition of this instance, which
|
# pass the call to the core-definition of this instance, which
|
# knows all cores.
|
# knows all cores.
|
#
|
#
|
# +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.
|
# This is just a helper function and is used by gen_toplevel
|
# 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.
|
# +coder+:: A HDL coder, which is used to create the auto-generated HDL.
|
#
|
#
|
def assign_unused_to_default( coder )
|
def assign_unused_to_default( coder )
|
|
|
|
|
|
|
# iterate over all instances
|
# iterate over all instances
|
# and check all interfaces
|
# and check all interfaces
|
@defn.cores.each do |inst_name, inst|
|
@defn.cores.each do |inst_name, inst|
|
|
|
inst.defn.interfaces.each do |ifc_name, ifc|
|
inst.defn.interfaces.each do |ifc_name, ifc|
|
|
|
#
|
#
|
# 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.name, ifc.version )
|
ifc_spec = SOCMaker::lib.get_ifc( ifc.name, ifc.version )
|
|
|
if !@defn.ifc_in_use?( inst_name, ifc_name )
|
if !@defn.ifc_in_use?( inst_name, ifc_name )
|
|
|
default_tmp = {};
|
default_tmp = {};
|
ifc_spec.ports.each do |_name,_port|
|
ifc_spec.ports.each do |_name,_port|
|
default_tmp[ _name ] = _port[ :default ]
|
default_tmp[ _name ] = _port[ :default ]
|
end
|
end
|
|
|
coder.add_ifc_default_assignment( inst, inst_name, ifc_name, default_tmp )
|
coder.add_ifc_default_assignment( inst, inst_name, ifc_name, default_tmp )
|
end
|
end
|
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
|
# +rule+:: The combination rule (obsolete/unused)
|
# +rule+:: The combination rule (obsolete/unused)
|
# +src+:: Source hash with instance name as key and interface name as value
|
# +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
|
# +dst+:: Destination hash with instance name as key and interface name as value
|
# +coder+:: The HDL coder which is used
|
# +coder+:: The HDL coder which is used
|
#
|
#
|
def gen_toplevel_con( name, rule, src, dst, coder )
|
def gen_toplevel_con( name, rule, src, dst, coder )
|
|
|
src_inst = {};
|
src_inst = {};
|
dst_inst = {};
|
dst_inst = {};
|
|
|
#
|
#
|
# 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
|
#
|
#
|
# For each signal in the interface specification,
|
# For each signal in the interface specification,
|
# we create a list. The list has an entry for each source
|
# we create a list. The list has an entry for each source
|
# and destination signal, which defines the length.
|
# and destination signal, which defines the length.
|
#
|
#
|
# In the second step, the maximum in each list is extracted.
|
# In the second step, the maximum in each list is extracted.
|
#
|
#
|
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 ] } ]
|
|
|
|
|
#
|
#
|
# 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
|
|
|
|
|
|
|
# vim: noai:ts=2:sw=2
|
# vim: noai:ts=2:sw=2
|
|
|