class SOCMaker::VHDLCoder

VHDL coder class: is used to create and implement VHDL cores by SOCMaker::SOCDef

Public Instance Methods

add_core_component( core_name, core_spec ) click to toggle source

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
add_core_instance( inst_name, inst, top_cons, top_ifcs, soc ) click to toggle source

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
add_ifc_connection( ifc_spec, con_name, length, src_inst, dst_inst, src_ifc, dst_ifc ) click to toggle source

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
add_ifc_default_assignment( inst, inst_name, ifc_name ) click to toggle source

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
add_toplevel_sig( soc, entity_name, top_con_ifc ) click to toggle source

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
entity_generic_str( core ) click to toggle source

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
entity_port_str( core ) click to toggle source

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
filename( name ) click to toggle source

Adds vhdl file suffix to name

# File lib/soc_maker/hdl_coder.rb, line 130
def filename( name )
  return name + ".vhd"
end
get_hdl_code( soc, entity_name ) click to toggle source

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
is_ifc_connected?( inst_name, ifc_name, top_cons ) click to toggle source

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