URL
https://opencores.org/ocsvn/soc_maker/soc_maker/trunk
Subversion Repositories soc_maker
[/] [soc_maker/] [trunk/] [lib/] [soc_maker/] [core_inst.rb] - Rev 8
Go to most recent revision | Compare with Previous | Blame | View Log
################################################################# File: core_inst.rb## Author: Christian Hättich## Project: System-On-Chip Maker## Target: Linux / Windows / Mac## Language: ruby#################################################################### Copyright (C) 2014 Christian Hättich - feddischson [ at ] opencores.org## 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# the Free Software Foundation, either version 3 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program. If not, see <http://www.gnu.org/licenses/>.################################################################### Description:# This class represents a core instantiation within# a SOC. It contains a params (parameters) hash,# which defines, which parameters are set to which values.# The type field is used to identify the SOCMaker::CoreDef# and the field @defn is initialized as reference to# the corresponding CoreDef instance.#################################################################module SOCMakerclass CoreInstinclude ERRattr_accessor :defnattr_accessor :typeattr_accessor :paramsdef initialize( type, params = {} )init_with( 'type' => type,'params' => params )enddef encode_with( coder )%w[ type params ].each { |v| coder[ v ] = instance_variable_get "@#{v}" }enddef init_with( coder )serr_if( coder[ 'type' ] == nil,"no type is provided for a core instance",field: "type" )@type = coder[ 'type' ]@params = coder[ 'params' ] || {}serr_if( !@params.is_a?( Hash ), 'Parameters are not given as hash',field: 'params' )enddef 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 )endelsif 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 )endendenddef generics@defn.generics do |name, type, default_value, is_last|value = @params[ name.to_sym ];value = valuevalue = default_value if value == nilyield( name.to_s, type, value, is_last )endend## Get a port, identified by the interface and port name## +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_sreturn [ 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 )# enddef consistency_check@defn = SOCMaker::lib.get_core( @type )# check, if the instance parameters in the core definition@params.each do |param_name, value|verr_if( @defn.inst_parameters[ param_name ] == nil,"Parameter not found: " + param_name.to_s,field: 'params' )end## auto-complete parameters with default values@defn.inst_parameters.each do |param_name, param|# auto-complete to default values@params[ param_name ] ||= param.defaultend# @_params ||= {}# if @params != nil# @params.each do |name, val|## 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 )param_match = SOCMaker::conf[ :length_regex ].match( port_len )if param_match and @params[ port_len.to_sym ] != niltmp =@params[ port_len.to_sym ]tmp = tmp.to_i if tmp.is_a?( String )@ports[ port_name.to_sym ] = { len: tmp, dir: port_dir, default: default }elseSOCMaker::logger.error( "Failed to evaluate #{port_len} for port #{port_name}" )endelse@ports[ port_name.to_sym ] = { len: port_len, dir: port_dir, default: default }endend@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 ] != niltmp =@params[ port_len.to_sym ]tmp = tmp.to_i if tmp.is_a?( String )@ifcs[ ifc_name ][ port_name.to_sym ] = { len: tmp, dir: port_dir, default: default }elseSOCMaker::logger.error( "Failed to evaluate #{port_len} for port #{port_name}" )endelse@ifcs[ ifc_name ][ port_name.to_sym ] = { len: port_len, dir: port_dir, default: default }end##puts "#{port_def_ref}, #{port_name}, #{port_dir}, #{port_default}"endend# lerr_if( @defn == nil, 'Core not found in lib',# field: 'cores' )@defn.consistency_checkend## Returns the length of a port within an interface.# If no instance is given, we know that it is# a toplevel interface.# Otherwise we check for this and we do a recursive call.# If this port is within a interface of a core, we# pass the call to the core-definition of this instance, which# knows all cores.## +ifc_name+:: name of the interface# +port_spec_name+:: name of the port# +inst+:: name of the instance (optional), default is nil#def get_port_len( ifc_name, port_spec_name, inst = nil )if inst == niltmp = @defn.interfaces[ ifc_name.to_sym ].ports.select{ |key,hash| hash.defn == port_spec_name.to_s }.keys.first.to_sreturn tmp.size == 0 ? 0 : @ports[ tmp.to_sym ][ :len ]elseif inst == @defn.name.to_symreturn get_port_len( ifc_name, port_spec_name )elsereturn @defn.get_port_len( ifc_name, port_spec_name, inst )endendend## Returns the core definition for an instance (identified by its name)## +inst+:: name of the instance#def get_core_def( inst )if inst == @defn.namereturn @defnelsetmp = @defn.get_core_def( inst )perr_if( tmp == nil, "#Processing error: {inst} not found by get_core_def" )return tmpendend## Returns a core instance, identified by its name.# If it is not a sub-core, we return our self## +inst+:: name of the instance#def get_core_inst( inst )if @defn.cores[ inst ] != nilreturn @defn.cores[ inst ]elsereturn selfendend## 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# 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## Instanciate each core#@defn.cores.each do |inst_name, inst|coder.add_core_instance( inst_name.to_s, inst )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 )endassign_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_dirFile.open( File.join( file_dir, file_name ), 'w' ) do |f|f.write( coder.get_hdl_code( self, @defn.name ) )endSOCMaker::logger.proc( "END of creating top-level hdl code for #{@defn.name}" )end## 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.#def assign_unused_to_default( coder )# iterate over all instances# and check all interfaces@defn.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.#ifc_spec = SOCMaker::lib.get_ifc( ifc.name, ifc.version )if !@defn.ifc_in_use?( inst_name, ifc_name )default_tmp = {};ifc_spec.ports.each do |_name,_port|default_tmp[ _name ] = _port[ :default ]endcoder.add_ifc_default_assignment( inst, inst_name, ifc_name, default_tmp )endendendend## This function is called during the toplevel generation# for each connection.## +name+:: The name of the connection# +rule+:: The combination rule (obsolete/unused)# +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#def gen_toplevel_con( name, rule, 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(get_core_def( src.keys.first.to_s ).interfaces[ src.values.first ].name,get_core_def( src.keys.first.to_s ).interfaces[ src.values.first ].version )## Get the maximum required signal length## 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, the maximum in each list is extracted.#length_tmp = {};ifc_spec.ports.keys.each do |_name|length_tmp[ _name ] = []dst.each do |inst_name, ifc_name|length_tmp[ _name ] << get_port_len( ifc_name, _name, inst_name )endsrc.each do |inst_name, ifc_name|length_tmp[ _name ] << get_port_len( ifc_name, _name, inst_name )endendmax_length = Hash[ length_tmp.map{ |key, arr| [ key, arr.max ] } ]## 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 ] = get_core_inst( inst_name )enddst.keys.each do |inst_name|dst_inst[ inst_name ] = get_core_inst( inst_name )end## create the declaraion and assignments#coder.add_ifc_connection( ifc_spec, name, max_length, src_inst, dst_inst, src, dst )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.paramsend# TODO# private: assign_unused_to_default, :gen_toplevel_conend # CoreInstend # SOCMaker# vim: noai:ts=2:sw=2
Go to most recent revision | Compare with Previous | Blame | View Log
