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

Class Method Details

.allianceObject

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.

Returns:

  • (Boolean)


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

.vhdl08Object

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.

Returns:

  • (Boolean)


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