module HDLRuby::Low::Low2VHDL
Provides tools for converting HDLRuby::Low
objects to VHDL.
Public Class Methods
Tells if Allicance toolchain is targeted.
# File lib/HDLRuby/hruby_low2vhd.rb, line 44 def self.alliance return @@alliance end
Sets/unsets the Allicance toolchain targeting.
# File lib/HDLRuby/hruby_low2vhd.rb, line 49 def self.alliance=(mode) @@alliance = mode ? true : false end
Converts a +name+ to a VHDL architecture name.
NOTE: assume names have been converted to VHDL-compatible ones.
# File lib/HDLRuby/hruby_low2vhd.rb, line 122 def self.architecture_name(name) return self.vhdl_name(name.to_s + "_a") end
Tells if a type
is arithmetic-compatible.
# File lib/HDLRuby/hruby_low2vhd.rb, line 127 def self.arith?(type) return type.is_a?(TypeVector) && [:signed,:unsigned,:float].include?(type.base.name) end
Converts a +name+ to a VHDL entity name.
NOTE: assume names have been converted to VHDL-compatible ones.
# File lib/HDLRuby/hruby_low2vhd.rb, line 115 def self.entity_name(name) return self.vhdl_name(name.to_s + "_e") end
Generates the VHDL code for the mux function for type string tstr
with num
choices. spaces
is the ident for the resulting code.
# File lib/HDLRuby/hruby_low2vhd.rb, line 297 def self.mux_function(type,num,spaces) # Create the strin of the type. tstr = type.to_vhdl # Create the name of the function from the type. name = mux_name(tstr,num) # Create the condition. if num == 2 then cond = "cond : boolean" else # First compute the width of the condition. width = (num-1).width # Now generate the condition. cond = "val : std_logic_vector(#{width-1} downto 0)" end # Generate the arguments. args = num.times.map {|i| "arg#{i} : #{tstr}" }.join("; ") # Generate the body. if num == 2 then body = "#{spaces} if(cond) then\n" + "#{spaces} return arg0;\n" + "#{spaces} else\n" + "#{spaces} return arg1;\n" + "#{spaces} end if;\n" else # First compute the type of the choices. vtype = TypeVector.new(:"",Bit,width-1..0) # Now generate the body. body = "#{spaces} case(val) is\n" + num.times.map do |i| pos = Value.new(vtype,i).to_vhdl "#{spaces} when #{pos} => return arg#{i};\n" end.join + "#{spaces} end case;\n" end # Generate the choices. # Generates the function return "#{spaces}function #{name}" + "(#{cond}; #{args})\n" + "#{spaces}return #{tstr} is\n" + "#{spaces}begin\n" + body + "#{spaces}end #{mux_name(tstr,num)};\n\n" end
Generates the name of a mux function by type string tstr
and number of arguments num
.
# File lib/HDLRuby/hruby_low2vhd.rb, line 290 def self.mux_name(tstr,num) return "mux#{tstr.gsub(/[^a-zA-Z0-9_]/,"_")}#{num}" end
Generates the pakage requirement for an entity. spaces
are the spaces to put before each line.
# File lib/HDLRuby/hruby_low2vhd.rb, line 64 def self.packages(spaces) return "#{spaces}library ieee;\n" + "#{spaces}use ieee.std_logic_1164.all;\n" + "#{spaces}use ieee.numeric_std.all;\n\n" end
Generates expression expr
while casting it to arithmetic-compatible type if required.
# File lib/HDLRuby/hruby_low2vhd.rb, line 134 def self.to_arith(expr) if arith?(expr.type) then # The expression is arithmetic-compatible, just generate it. if expr.is_a?(Value) then return expr.to_arith else return expr.to_vhdl end else # The expression is to convert, by default convert to unsigned # (this is the standard interpretation of HDLRuby). if expr.type.to_vhdl == "std_logic" then # std_logic case: must convert to vector first. if alliance then # Alliance toolchain case. return "unsigned('0' & " + expr.to_vhdl + ")" else # General case. return "unsigned(\"\" & " + expr.to_vhdl + ")" end else # Other case, ue the expression direction. return "unsigned(" + expr.to_vhdl + ")" end end end
Generates a expression converted to the boolean type.
# File lib/HDLRuby/hruby_low2vhd.rb, line 192 def self.to_boolean(expr) # if boolean?(expr) then if expr.boolean? then # Comparison, no conversion required. return expr.to_vhdl else # Conversion to boolean required. return "(" + expr.to_vhdl + " = '1')" end end
Generates epression expr
while casting it to match type
if required.
# File lib/HDLRuby/hruby_low2vhd.rb, line 205 def self.to_type(type,expr) # puts "expr=#{expr.to_vhdl}" unless expr.is_a?(Concat) # puts "type.width=#{type.width}, expr.type.width=#{expr.type.width}" if type.to_vhdl == "std_logic" then # Conversion to std_logic required. if expr.is_a?(Value) then # Values can simply be rewritten. if expr.content.to_s.to_i(2) == 0 then return "'0'" else return "'1'" end elsif expr.type.to_vhdl != "std_logic" # Otherwise a cast is required. # if expr.type.base.name == :signed then # return "unsigned(#{expr.to_vhdl})(0)" # else # # return "unsigned(#{expr.to_vhdl}(0))" # return "unsigned(#{expr.to_vhdl})(0)" # end if alliance then # Specific syntax for casting to std_logic with Alliance if expr.type.width == 1 then # No cast required with alliance if bitwidth is 1. return expr.to_vhdl else # Multi-bit, need to select a bit and possibly # cast to unsigned. if expr.type.signed? then return "unsigned(#{expr.to_vhdl}(0))" # elsif expr.is_a?(RefRange) then # # Range reference case. # return "#{expr.ref.to_vhdl}(#{expr.range.first.to_vhdl})" else # Other cases. return "#{expr.to_vhdl}(0)" end end else # Lint-compatible casting to std_logic if expr.type.signed? then # Signed, cast to unsigned. return "unsigned(#{expr.to_vhdl})(0)" # elsif expr.is_a?(RefRange) then # # Range reference case. # return "#{expr.ref.to_vhdl}(#{expr.range.first.to_vhdl})" else # Other cases: for std_logic generation. return expr.to_vhdl(0,true) end end else # Both are std_logic, nothing to to. return expr.to_vhdl end elsif expr.is_a?(Value) then # puts "type=#{type}, type.range=#{type.range}" # Value width must be adjusted. return expr.to_vhdl(0,false,type.width) elsif expr.is_a?(Concat) then return expr.to_vhdl(type) elsif expr.type.width < type.width then # Need to extend the type. return '"' + "0" * (type.width - expr.type.width) + '" & ' + expr.to_vhdl else # No conversion required. return expr.to_vhdl end end
Cast
a type
to undo arithmetic conversion if necessary.
# File lib/HDLRuby/hruby_low2vhd.rb, line 277 def self.unarith_cast(type) # Is the type arithmetic? if arith?(type) then # Yes, no undo required. return "" else # No, undo required. return "std_logic_vector" end end
Tells if VHDL'08 is supported or not.
# File lib/HDLRuby/hruby_low2vhd.rb, line 27 def self.vhdl08 return @@vhdl08 end
Sets/unsets the support of VHDL'08.
# File lib/HDLRuby/hruby_low2vhd.rb, line 32 def self.vhdl08=(mode) @@vhdl08 = mode ? true : false end
Converts a name
to a VHDL-compatible name.
# File lib/HDLRuby/hruby_low2vhd.rb, line 84 def self.vhdl_name(name) if vhdl08 then # VHDL'08, nothing to do if the name is VHDL-compatible. return name.to_s if self.vhdl_name?(name) # Otherwise put the name between // return "\\#{name}\\".to_s else # Not VHDL'08, need to mangle the name. # For safety also force downcase. name = name.to_s # Other letters: convert special characters. name = name.each_char.map do |c| if c=~ /[a-uw-z0-9]/ then c elsif c == "v" then "vv" else "v" + c.ord.to_s end end.join # First character: only letter is possible. unless name[0] =~ /[a-z]/ then name = "v" + name end return name end end
Tells if a name
is VHDL-compatible. To ensure compatibile, assume all the character must have the same case.
# File lib/HDLRuby/hruby_low2vhd.rb, line 73 def self.vhdl_name?(name) name = name.to_s # First: character check. return false unless name =~ /^[a-zA-Z]|([a-zA-Z][a-zA-Z_0-9]*[a-zA-Z0-9])$/ # Then character sequence check. return false if name.include?("__") # Then case check. return (name == name.upcase || name == name.downcase) end
Converts string str
to a VHDL-compatible string.
# File lib/HDLRuby/hruby_low2vhd.rb, line 55 def self.vhdl_string(str) str = str.gsub(/\n/,"\\n") str.gsub!(/\t/,"\\t") return str end