Module: HDLRuby::Low::Low2VHDL
- Defined in:
- lib/HDLRuby/hruby_low2vhd.rb
Overview
Provides tools for converting HDLRuby::Low objects to VHDL.
Constant Summary collapse
- @@vhdl08 =
Indicates if VHDL'08 can be generated. Default: true
NOTE: when possible, it is better to be left true since the identifier does not require any mangling in VHDL'08
true
- @@alliance =
Indicates if target toolchain is Alliance: requires a slightly different VHDL syntax.
NOTE: this syntax is not lint-compatible and should be avoided unless using specifically Alliance.
false
Class Method Summary collapse
-
.alliance ⇒ Object
Tells if Allicance toolchain is targeted.
-
.alliance=(mode) ⇒ Object
Sets/unsets the Allicance toolchain targeting.
-
.architecture_name(name) ⇒ Object
Converts a +name+ to a VHDL architecture name.
-
.arith?(type) ⇒ Boolean
Tells if a +type+ is arithmetic-compatible.
-
.entity_name(name) ⇒ Object
Converts a +name+ to a VHDL entity name.
-
.mux_function(type, num, spaces) ⇒ Object
Generates the VHDL code for the mux function for type string +tstr+ with +num+ choices.
-
.mux_name(tstr, num) ⇒ Object
Generates the name of a mux function by type string +tstr+ and number of arguments +num+.
-
.packages(spaces) ⇒ Object
Generates the pakage requirement for an entity.
-
.to_arith(expr) ⇒ Object
Generates expression +expr+ while casting it to arithmetic-compatible type if required.
-
.to_boolean(expr) ⇒ Object
Generates a expression converted to the boolean type.
-
.to_type(type, expr) ⇒ Object
Generates epression +expr+ while casting it to match +type+ if required.
-
.unarith_cast(type) ⇒ Object
Cast a +type+ to undo arithmetic conversion if necessary.
-
.vhdl08 ⇒ Object
Tells if VHDL'08 is supported or not.
-
.vhdl08=(mode) ⇒ Object
Sets/unsets the support of VHDL'08.
-
.vhdl_name(name) ⇒ Object
Converts a +name+ to a VHDL-compatible name.
-
.vhdl_name?(name) ⇒ Boolean
Tells if a +name+ is VHDL-compatible.
-
.vhdl_string(str) ⇒ Object
Converts string +str+ to a VHDL-compatible string.
Class Method Details
.alliance ⇒ Object
Tells if Allicance toolchain is targeted.
44 45 46 |
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 44 def self.alliance return @@alliance end |
.alliance=(mode) ⇒ Object
Sets/unsets the Allicance toolchain targeting.
49 50 51 |
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 49 def self.alliance=(mode) @@alliance = mode ? true : false end |
.architecture_name(name) ⇒ Object
Converts a +name+ to a VHDL architecture name.
NOTE: assume names have been converted to VHDL-compatible ones.
122 123 124 |
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 122 def self.architecture_name(name) return self.vhdl_name(name.to_s + "_a") end |
.arith?(type) ⇒ Boolean
Tells if a +type+ is arithmetic-compatible.
127 128 129 130 |
# 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 |
.entity_name(name) ⇒ Object
Converts a +name+ to a VHDL entity name.
NOTE: assume names have been converted to VHDL-compatible ones.
115 116 117 |
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 115 def self.entity_name(name) return self.vhdl_name(name.to_s + "_e") end |
.mux_function(type, num, spaces) ⇒ Object
Generates the VHDL code for the mux function for type string +tstr+ with +num+ choices. +spaces+ is the ident for the resulting code.
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
# 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 |
.mux_name(tstr, num) ⇒ Object
Generates the name of a mux function by type string +tstr+ and number of arguments +num+.
290 291 292 |
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 290 def self.mux_name(tstr,num) return "mux#{tstr.gsub(/[^a-zA-Z0-9_]/,"_")}#{num}" end |
.packages(spaces) ⇒ Object
Generates the pakage requirement for an entity. +spaces+ are the spaces to put before each line.
64 65 66 67 68 |
# 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 |
.to_arith(expr) ⇒ Object
Generates expression +expr+ while casting it to arithmetic-compatible type if required.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# 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 |
.to_boolean(expr) ⇒ Object
Generates a expression converted to the boolean type.
192 193 194 195 196 197 198 199 200 201 |
# 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 |
.to_type(type, expr) ⇒ Object
Generates epression +expr+ while casting it to match +type+ if required.
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# 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 |
.unarith_cast(type) ⇒ Object
Cast a +type+ to undo arithmetic conversion if necessary.
277 278 279 280 281 282 283 284 285 286 |
# 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 |
.vhdl08 ⇒ Object
Tells if VHDL'08 is supported or not.
27 28 29 |
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 27 def self.vhdl08 return @@vhdl08 end |
.vhdl08=(mode) ⇒ Object
Sets/unsets the support of VHDL'08.
32 33 34 |
# File 'lib/HDLRuby/hruby_low2vhd.rb', line 32 def self.vhdl08=(mode) @@vhdl08 = mode ? true : false end |
.vhdl_name(name) ⇒ Object
Converts a +name+ to a VHDL-compatible name.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# 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 |
.vhdl_name?(name) ⇒ Boolean
Tells if a +name+ is VHDL-compatible. To ensure compatibile, assume all the character must have the same case.
73 74 75 76 77 78 79 80 81 |
# 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 |
.vhdl_string(str) ⇒ Object
Converts string +str+ to a VHDL-compatible string.
55 56 57 58 59 |
# 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 |