class SOCMaker::VHDLCoder
VHDL coder class: is used to create and implement VHDL cores by SOCMaker::SOCDef
Public Instance Methods
Add a component declaration to the declaration-string @decl_part This for example looks like
component <<name>> is generic( g1 : ... g2 : ... ... ); port( p1 : ... p2 : ... p3 : ... ... ) end component <<name>>;
In addition, we add some VHDL comments (author, mail, license)
core_name
-
name of the core
core_spec
-
core definition (of type
SOCMaker::CoreDef
)
# File lib/soc_maker/hdl_coder.rb, line 113 def add_core_component( core_name, core_spec ) @decl_part << "--\n" @decl_part << "-- core author: #{core_spec.author} - #{core_spec.authormail}\n" @decl_part << "-- license: #{core_spec.license}\n" @decl_part << "--\n" @decl_part << "component #{core_spec.toplevel} is\n" generic_str = entity_generic_str( core_spec ); @decl_part << "generic ( #{ generic_str });\n" if generic_str.size > 0 @decl_part << "port( \n" << entity_port_str( core_spec ) <<" );\n" @decl_part << "end component #{core_spec.toplevel};\n" #entity_generic_str( core_spec ) end
This method create VHDL code to instanciate a core instance. The result is added to @inst_part and looks for example like
inst_name : core_name generic_map( generic_1 => 3; generic_2 => -1; .... ) port_map( p1 => inst_name_p1, p2 => inst_name_p2, ... );
In addition, for every port signal, a internal signal is defined and added to @decl_part. This looks for example like
signal inst_name_p1 : std_logic; signal inst_name_p2 : std_logic_vector( 4-1 downto 0 );
inst_name
-
name of the instance
inst
-
object of type
SOCMaker::CoreInst
, whih represents the instance
# File lib/soc_maker/hdl_coder.rb, line 263 def add_core_instance( inst_name, inst, top_cons, top_ifcs, soc ) @inst_part << inst_name << " : " << inst.defn.toplevel << "\n" generic_str = "" inst.generics do |generic, type, value, is_last| generic_str << "#{generic} => #{value}" generic_str << "," unless is_last generic_str << "\n" end @inst_part << "generic map( \n#{generic_str} )\n" if generic_str.size > 0 port_str = "" inst.defn.interfaces.each_with_index do |(ifc_name, ifc), i_ifc| top_con = is_ifc_connected?( inst_name, ifc_name, top_cons ) if top_con.size > 0 # direct assignment to entity-port inst.ports( ifc_name ) do |port_name, dir, length, default, ref, is_last| top_port = soc.port( top_con.values.first, ref.to_sym ) port_str << "#{port_name} => #{top_port[0]}" port_str << "," unless (is_last && i_ifc == inst.defn.interfaces.size-1) port_str << "\n" end else # assignment to signal (which is used later) # inst.ports( ifc_name ) do |port_name, dir, length, default, ref, is_last| port_str << "#{port_name} => #{inst_name}_#{port_name}" port_str << "," unless (is_last && i_ifc == inst.defn.interfaces.size-1) port_str << "\n" if length > 1 @decl_part << "signal #{inst_name}_#{port_name} : std_logic_vector( #{length}-1 downto 0 );\n" else @decl_part << "signal #{inst_name}_#{port_name} : std_logic;\n" end end end end @inst_part << "port map( \n#{port_str} );\n\n\n" if port_str.size > 0 end
This method is used to add VHDL code, which connects two interfaces
ifc_spec
-
interface specification
con_name
-
connection name
length
-
Hash, which contains the signal length for each port
src_inst
-
Array wich source instances
dst_inst
-
Array with destination instances
src_ifc
-
Hash with source interfaces
dst_ifc
-
Hash with destination interfaces
# File lib/soc_maker/hdl_coder.rb, line 347 def add_ifc_connection( ifc_spec, con_name, length, src_inst, dst_inst, src_ifc, dst_ifc ) ### # # declaration # # ifc_spec.ports.each do |port_name, port| @decl_part << "signal #{con_name}_#{port_name.to_s} : " if length[ port_name ] > 1 @decl_part << " std_logic_vector( #{length[ port_name ]}-1 downto 0 ) " else @decl_part << " std_logic " end # end of the line @decl_part << ";\n" end ### # # assignment # # ifc_spec.ports.each do |port_name, port_setup| if port_setup[ :dir ] == 0 src_inst_sel = src_inst dst_inst_sel = dst_inst src_ifc_sel = src_ifc dst_ifc_sel = dst_ifc else src_inst_sel = dst_inst dst_inst_sel = src_inst src_ifc_sel = dst_ifc dst_ifc_sel = src_ifc end # length == 0 means, that no # signal is assigned to this connection if length[ port_name ] > 0 port_tmp_name = "#{con_name}_#{port_name.to_s}" # combine all sources tmp = "#{port_tmp_name} <= " # loop over instances src_inst_sel.each_with_index do |(inst_name, inst), i| ( tmp_name, port) = inst.port( src_ifc_sel[ inst_name ], port_name ) if port != nil tmp << "#{inst_name}_#{tmp_name}" tmp << " and \n" unless i == src_inst_sel.size-1 else if length[ port_name ] > 1 tmp << "( others => '#{port_setup[ :default ] }' )" else tmp << "'#{port_setup[ :default ] }'" end end end tmp << ";\n" @asgn_part << tmp tmp = "" assigned = false # assign to destination dst_inst_sel.each_with_index do |(inst_name, inst), i| ( tmp_name, port) = inst.port( dst_ifc_sel[ inst_name ], port_name ) if port != nil tmp << "#{inst_name}_#{tmp_name} <= #{port_tmp_name};\n" assigned = true end end @asgn_part << tmp if assigned else SOCMaker::logger.info( "Port #{port_name.to_s} of" + "connection #{con_name} is not assigned" ) end end end
This method adds VHDL code to @asgn_part, which sets default values to an interface. This looks for example like
some_port1 <= ( others => '0' ); some_port2 <= '1';
inst
-
instance, which has the interface (of type
SOCMaker::CoreInst
) inst_name
-
name of the instance
ifc_name
-
name of the interface
# File lib/soc_maker/hdl_coder.rb, line 321 def add_ifc_default_assignment( inst, inst_name, ifc_name ) tmp = "" inst.ports( ifc_name ) do |port_name, dir, length, default_val, ref, is_last| if dir == 1 # assign default value only if it is an input if length > 1 tmp << "#{inst_name}_#{port_name} <= ( others => '#{default_val}' );\n" else tmp << "#{inst_name}_#{port_name} <= '#{default_val}';\n" end end end @asgn_part << tmp end
Method, which adds VHDL code to @asgn_part, which connects toplevel signals to intermediate signals.
soc
-
the soc, for which the signals are added
entity_name
-
name of the entity
# File lib/soc_maker/hdl_coder.rb, line 477 def add_toplevel_sig( soc, entity_name, top_con_ifc ) remaining_ifc = soc.interfaces.keys - top_con_ifc remaining_ifc = remaining_ifc.map{ |ifc| ifc.to_s } soc.ports( *remaining_ifc ) do |port_name, dir, length, default, ref, is_last| if dir == 0 @asgn_part << "#{port_name} <= #{entity_name}_#{port_name}" else @asgn_part << "#{entity_name}_#{port_name} <= #{port_name} " end @asgn_part << ";\n" if length > 1 @decl_part << "signal #{entity_name}_#{port_name} : std_logic_vector( #{length}-1 downto 0 );\n" else @decl_part << "signal #{entity_name}_#{port_name} : std_logic;\n" end end end
Creates a the generic part for a core entity or component declaration. The result is something like
generic_1 : integer := 4; generic_2 : natural := 1; generic_3 : std_logic := '0'
return
-
a string holding the generic data as VHDL code
# File lib/soc_maker/hdl_coder.rb, line 144 def entity_generic_str( core ) generic_str = "" core.generics do |gen_name, gen_type, gen_val, is_last| generic_str << gen_name << " : " << gen_type << " := " << gen_val.to_s generic_str << ";" unless is_last generic_str << "\n" end return generic_str end
Create a string, which lists all signals of 'core' The method iterates over all interfaces: For each interface, this method iterates over all ports: For each port, the definition from the 'soc_lib' is loaded and the VHDL code according to the definition is added The result is simething like
port_1 : in std_logic; port_2 : out std_logic_vector( 4-1 downto 0 ); port_3 : in std_logic
core
-
the core, which is used to create the entity description
return
-
a string holding the entity description of a core as VHDL code
# File lib/soc_maker/hdl_coder.rb, line 171 def entity_port_str( core ) port_string = "" core.ports do |port_name, port_dir, port_len, port_default, port_ref, is_last | # The string we are add in every iteration looks for example like # myportname1 : out std_logic_vector( 6-1 downto 0 ) # or # myportname2 : in std_logic # port_string << port_name.to_s << " : " # port direction if port_dir == 2 port_string << " inout " elsif port_dir == 1 port_string << " in " else port_string << " out " end # port type / length if( port_len.is_a?( String ) || ( port_len.is_a?( Fixnum ) && port_len > 1 ) ) port_string << " std_logic_vector( #{port_len}-1 downto 0 ) " elsif ( port_len.is_a?( Fixnum ) && port_len == 1 ) port_string << " std_logic " else processing_error "failed to generate entity port entry because of wrong port-length type/value", port_length_class: port_len.class, port_length: port_len, core: core.name, port: port_name end # end of the line port_string << ";" unless is_last port_string << "\n" end return port_string end
Adds vhdl file suffix to name
# File lib/soc_maker/hdl_coder.rb, line 130 def filename( name ) return name + ".vhd" end
This method returns the VHDL code, which was created by this instance. It contains
-
the entity string
-
all component and signal declarations
-
all assignments
-
all core instanciations
# File lib/soc_maker/hdl_coder.rb, line 442 def get_hdl_code( soc, entity_name ) entity_str = SOCMaker::conf[ :LIC ].split(/\n/).map{ |s| "-- "+s }.join("\n") + "\n" entity_str << "-- Auto-Generated by #{SOCMaker::conf[ :app_name ]} \n" entity_str << "-- Date: #{Time.now}\n" entity_str << SOCMaker::conf[ :vhdl_include ] + "\n" entity_str << "entity #{entity_name} is \n" tmp = entity_port_str( soc ) entity_str << "port( \n" << tmp << " );\n" if tmp.size > 0 entity_str << "end entity #{entity_name};\n\n\n" entity_str << "ARCHITECTURE IMPL of #{entity_name} is \n" entity_str << @decl_part entity_str << "\n\n" entity_str << "begin" entity_str << "\n\n" entity_str << "--" entity_str << "-- assignments " entity_str << "--" entity_str << "\n\n" entity_str << @asgn_part entity_str << "\n\n" entity_str << "--" entity_str << "-- instances " entity_str << "--" entity_str << "\n\n" entity_str << @inst_part entity_str << "end ARCHITECTURE IMPL;" return entity_str end
Checks, if this instance/interface has an entry in top_cons. If yes, the top-level connection is returned, otherwise an empty Hash
inst_name
-
name of the instance
ifc_name
-
name of the interface
top_cons
-
connection Hash
return
-
{} if no entry exists, otherwise the top-level part of the entry
# File lib/soc_maker/hdl_coder.rb, line 228 def is_ifc_connected?( inst_name, ifc_name, top_cons ) top_cons.each do |con_name, con_entry| if con_entry[ :mapping ][ 0 ][ inst_name.to_sym ] == ifc_name.to_sym return con_entry[ :mapping ][ 1 ] elsif con_entry[ :mapping ][ 1 ][ inst_name.to_sym ] == ifc_name.to_sym return con_entry[ :mapping ][ 0 ] end end return {} end