module HDLRuby

Module including the classes implementing the high-level and low-level libraries for describing digital hardware.

HDLRuby compiler interface program

High-level libraries for describing digital hardware.

Constants

FIELDS_OF_REF

The list of fields that correspond to reference.

FIELDS_TO_EXCLUDE

The list of fields to exclude from serialization.

FROM_BASICS_REFS

The table of the object that can be refered to, used when deserializing.

Infinity

Some useful constants

REF_ARG_NAMES

The name of the reference argument if any.

TO_BASICS

The classes meant to support to_basic.

TO_BASICS_TYPES

The classes describing types (must be described only once)

TO_BASIC_NAMES

The names of the classes of HDLRuby supporting to_basic

VERSION

Public Class Methods

basic_to_value(basic) click to toggle source

Convert a basic structure to a ruby object.

# File lib/HDLRuby/hruby_serializer.rb, line 141
def self.basic_to_value(basic)
    # print "For basic=#{basic} (#{basic.class})\n"
    # Detect which kind of basic struture it is.
    if basic.is_a?(NilClass) or basic.is_a?(Numeric) or 
            basic.is_a?(Low::Value) then
        # Nil, Numeric or Value objects are kept as they are.
        return basic
    elsif basic.is_a?(Range) then
        # First and last of range are converted.
        return basic_to_value(basic.first)..basic_to_value(basic.last)
    elsif basic.is_a?(String) then
        # String objects are cloned for avoiding side effects.
        return basic.clone
    elsif basic.is_a?(Array) then
        # Array objects are kept as they are, but their content is converted
        # to basic.
        return basic.map { |elem| basic_to_value(elem) }
    elsif basic.is_a?(Hash) then
        # Is the hash representing a class?
        # print "basic.size = #{basic.size}\n"
        # if basic.size == 1 then
        #     print "name = #{HDLRuby.const_reduce(basic.keys[0])}\n"
        # end
        if is_basic_HDLRuby?(basic) then
            # Yes, rebuild the object.
            # First get the class.
            klass = HDLRuby.const_get(basic.keys[0])
            # print "klass=#{klass}\n"
            # The the content.
            content = basic.values[0]
            # Handle the case of the ranges
            content.each do |k,v|
                if k.to_sym == :range and v.is_a?(Array) then
                    content[k] = basic_to_value(v[0])..basic_to_value(v[1])
                end
            end
            # Single instance variables are set with the structure,
            # separate them from the multiple instances.
            multiples,singles = content.partition do |k,v|
                (v.is_a?(Hash) or v.is_a?(Array)) and !is_basic_HDLRuby?(v)
            end
            # Create the object.
            # Get the name of the reference used in the constructor if any
            ref = REF_ARG_NAMES[klass]
            # Process the arguments of the object constructor.
            singles.map! do |k,v|
                # puts "ref=#{ref} k=#{k} v=#{v}"
                elem = basic_to_value(v)
                # puts "elem=#{elem}"
                # if ref == k and elem.is_a?(String) then
                if ref and ref.include?(k) and elem.is_a?(String) then
                    # The argument is actually a reference, get the
                    # corresponding object.
                    elem = FROM_BASICS_REFS[elem.to_sym]
                end
                # puts "now elem=#{elem}"
                elem
            end
            # Build the object with the processed arguments.
            # object = klass.new(*singles.map{|k,v| basic_to_value(v) })
            # puts "klass=#{klass}, singles=#{singles.join("\n")}, multiples=#{multiples.join("\n")}"
            object = klass.new(*singles)
            # Adds the multiple instances.
            multiples.each do |k,v|
                # puts "k=#{k} v=#{v}"
                # Construct the add method: add_<key name without ending s>
                add_meth = ("add_" + k)[0..-2].to_sym
                # Treat the values a an array.
                v = v.values if v.is_a?(Hash)
                # puts "v=#{v}"
                v.each do |elem|
                    # object.send(add_meth, *basic_to_value(elem) )
                    elem = basic_to_value(elem)
                    # puts "ref=#{ref}, k=#{k}"
                    # puts "to add elem=#{elem}"
                    # if ref == k and elem.is_a?(String) then
                    if ref and ref.include?(k) and elem.is_a?(String) then
                        # The argument is actually a reference, get the
                        # corresponding object.
                        elem = FROM_BASICS_REFS[elem.to_sym]
                    end
                    # puts "adding elem=#{elem} to object=#{object}" if elem.is_a?(SystemT)
                    # In general it is enough to add the element to
                    # the object. However, in the case of a systemI,
                    # the main systemT is added to the list at
                    # the creation of the SystemI and is therefore
                    # not to be added.
                    if !object.is_a?(SystemI) || object.systemT != elem
                        object.send(add_meth, *elem )
                    end
                end
            end
            # Store the objects if it is named.
            if object.respond_to?(:name) then
                # puts "Registering name=#{object.name} with #{object}"
                FROM_BASICS_REFS[object.name] = object
            end
            # Returns the resulting object.
            return object
        else
            # No, this a standard hash, keep it as is but convert its
            # contents.
            return basic.map do |k,v|
                [ basic_to_value(k), basic_to_value(v) ]
            end.to_h
        end
    else
        # Other cases should happen.
        raise AnyError, "Invalid class for a basic object: #{basic.class}."
    end
end
const_reduce(name, num = 1) click to toggle source

Reduce a constant name to num number of namespace levels.

# File lib/HDLRuby/hruby_serializer.rb, line 9
def self.const_reduce(name, num = 1)
    levels = name.split("::")
    return levels[-([num,levels.size].min)..-1].join("::")
end
from_yaml(stream) click to toggle source

Convert a stream to a HDLRuby list of objects.

# File lib/HDLRuby/hruby_serializer.rb, line 255
def self.from_yaml(stream)
    # Get the basic structure from the stream.
    basic = YAML.load_stream(stream)
    # Convert the basic structure to HDLRuby objects.
    return basic_to_value(basic)
end
is_basic_HDLRuby?(basic) click to toggle source

Tells if a basic structure is a representation of an HDLRuby object.

# File lib/HDLRuby/hruby_serializer.rb, line 72
def self.is_basic_HDLRuby?(basic)
    return ( basic.is_a?(Hash) and basic.size == 1 and
        TO_BASIC_NAMES.include?(HDLRuby.const_reduce(basic.keys[0])) )
end
uniq_name(base = "") click to toggle source

Generates an absolute uniq name.

# File lib/HDLRuby/hruby_tools.rb, line 15
def self.uniq_name(base = "")
    @@absoluteCounter += 1
    name = base.to_s + ":#{@@absoluteCounter}"
    if Symbol.all_symbols.find {|symbol| symbol.to_s == name } then
        # The symbol exists, try again.
        return self.uniq_name
    else
        return name.to_sym
    end
end
value_to_basic(ref, value, types = {}, generated = [[]]) click to toggle source

Converts a value to a basic structure easy-to-write YAML string.

Other parameters:

+top+:: indicates if the object is the top of the
description or not. If it is the top, the namespace it comes
from is kept.
+types+:: contains the type objects which will have to be converted
separately.

def self.value_to_basic(value, types = {}) Converts a value to a basic structure easy-to-write YAML string.

Other parameters:

+ref+:: indicates if the object is a reference or not.
+types+:: contains the type objects which will have to be converted
separately.
+generated+:: is the stack of the generated named objects in the current
context.
# File lib/HDLRuby/hruby_serializer.rb, line 95
def self.value_to_basic(ref, value, types = {}, generated = [[]])
    # Depending on the class.
    if value.is_a?(Symbol) then
        # Symbol objects are converted to strings.
        return value.to_s
    elsif value.is_a?(String) then
        # String objects are cloned for avoid side effects.
        return value.clone
    elsif value.is_a?(Numeric) or value.is_a?(NilClass) then
        # Nil and Numeric objects are kept as they are.
        return value
    elsif  value.is_a?(Range)
        # Convert to an array made of the converted first and last.
        return [value_to_basic(ref,value.first,types,generated),
                value_to_basic(ref,value.last,types,generated)]
    elsif value.is_a?(Array) then
        # Arrays are kept as they are, but their content is converted
        # to basic.
        return value.map { |elem| value_to_basic(ref,elem,types,generated) }
    # elsif value.is_a?(Base::HashName) then
    elsif value.is_a?(Low::HashName) then
        # Hash name, convert it to an array.
        return value.map { |v| value_to_basic(ref,v,types,generated) }
    elsif value.is_a?(Hash) then
        # Maybe the hash is empty.
        if value.empty? then
            return { }
        end
        # Convert its content to basic.
        return value.map do |k,v|
            [value_to_basic(ref,k,types,generated),
             value_to_basic(ref,v,types,generated)]
        end.to_h
    else
        # For the other cases, only HDLRuby classes supporting to_basic
        # are supported.
        unless TO_BASICS.include?(value.class) then
            raise AnyError, "Invalid class for converting to basic structure: #{value.class}"
        end
        # return value.to_basic(false,types)
        return value.to_basic(false,ref,types,generated)
    end
end

Public Instance Methods

error_manager(files,&code) click to toggle source

Execution context for processing error messages in code. The relevant error message to are assumed to be the ones whose file name is one given in files.

# File lib/HDLRuby/hruby_error.rb, line 27
def error_manager(files,&code)
    begin
        code.call
    rescue ::StandardError => e
        # pp e.backtrace
        # Keep the relevant
        e.backtrace.select! do |mess|
            files.find {|file| mess.include?(File.basename(file))}
        end
        puts "#{e.backtrace[0]}: #{e.message}"
        e.backtrace[1..-1].each { |mess| puts "   from #{mess}"}
        exit
    rescue 
        raise "Big Bad Bug"
    end
end
make_bit(value) click to toggle source

Converts a value to a valid bit if possible.

# File lib/HDLRuby/hruby_bstr.rb, line 10
def make_bit(value)
    value = value.to_s.downcase
    unless ["0","1","x","z"].include?(value)
        raise "Invalid value for a bit: #{value}"
    end
    return value
end