taichi-ishitani/rggen

View on GitHub
lib/rggen/builtins/bit_field/type.rb

Summary

Maintainability
B
5 hrs
Test Coverage
list_item :bit_field, :type do
  register_map do
    item_base do
      define_helpers do
        def read_write
          @readable = true
          @writable = true
        end

        def read_only
          @readable = true
          @writable = false
        end

        def write_only
          @readable = false
          @writable = true
        end

        def reserved
          @readable = false
          @writable = false
        end

        def readable?
          @readable.nil? || @readable
        end

        def writable?
          @writable.nil? || @writable
        end

        def read_only?
          readable? && !writable?
        end

        def write_only?
          writable? && !readable?
        end

        def reserved?
          !(readable? || writable?)
        end

        attr_setter :required_width

        def full_width
          :full_width
        end

        def need_initial_value
          @need_initial_value = true
        end

        def need_initial_value?
          @need_initial_value || false
        end

        def use_reference(options = {})
          @use_reference      = true
          @reference_options  = options
        end

        attr_reader :reference_options

        def use_reference?
          @use_reference || false
        end

        def same_width
          :same_width
        end
      end

      field :type
      field :readable?  , forward_to_helper: true
      field :writable?  , forward_to_helper: true
      field :read_only? , forward_to_helper: true
      field :write_only?, forward_to_helper: true
      field :reserved?  , forward_to_helper: true

      class_delegator :full_width
      class_delegator :need_initial_value?
      class_delegator :use_reference?
      class_delegator :reference_options
      class_delegator :same_width

      build do |cell|
        @type = cell
      end

      validate do
        case
        when width_mismatch?
          error "#{required_width} bit(s) width required:" \
                " #{bit_field.width} bit(s)"
        when need_initial_value? && no_initial_value?
          error 'no initial value'
        when required_refercne_not_exist?
          error 'reference bit field required'
        when reference_width_mismatch?
          error "#{required_reference_width} bit(s) reference bit field" \
                " required: #{bit_field.reference.width}"
        end
      end

      def width_mismatch?
        return false if required_width.nil?
        if required_width.respond_to?(:include?)
          required_width.not.include?(bit_field.width)
        else
          bit_field.width != required_width
        end
      end

      def required_width
        width = self.class.required_width
        return nil if width.nil?
        return configuration.data_width if width == full_width
        width
      end

      def no_initial_value?
        !bit_field.initial_value?
      end

      def required_refercne_not_exist?
        return false unless use_reference?
        return false unless reference_options[:required]
        return false if bit_field.has_reference?
        true
      end

      def reference_width_mismatch?
        return false unless use_reference?
        return false unless bit_field.has_reference?
        bit_field.reference.width != required_reference_width
      end

      def required_reference_width
        return 1 unless reference_options[:width]
        return bit_field.width if reference_options[:width] == same_width
        reference_options[:width]
      end
    end

    factory do
      def select_target_item(cell)
        @target_items.fetch(cell.value) do
          error "unknown bit field type: #{cell.value}", cell
        end
      end

      def convert(cell)
        @target_items.keys.find(proc { cell }) do |type|
          type.to_sym.casecmp(cell.to_sym).zero?
        end
      end
    end
  end

  rtl do
    item_base do
      export :value

      delegate [
        :name, :width, :msb, :lsb, :type, :reserved?
      ] => :bit_field
      delegate [
        :dimensions, :index, :local_index, :loop_variables
      ] => :register
      delegate [
        :array_port_format
      ] => :configuration

      build do
        interface :bit_field, :bit_field_sub_if,
                  type:       :rggen_bit_field_if,
                  name:       :bit_field_sub_if,
                  parameters: [width]
      end

      generate_pre_code :bit_field do |c|
        c << subroutine_call(:'`rggen_connect_bit_field_if', [
          register.bit_field_if, bit_field_sub_if, msb, lsb
        ]) << nl
      end

      def value
        register.register_if.value[msb, lsb]
      end
    end

    default_item do
    end

    factory do
      def select_target_item(_, bit_field)
        @target_items[bit_field.type]
      end
    end
  end

  ral do
    item_base do
      export :access
      export :model_name
      export :hdl_path

      define_helpers do
        attr_setter :access

        def model_name(&body)
          define_method(:model_name, &body)
        end

        def hdl_path(&body)
          define_method(:hdl_path, &body)
        end
      end

      def access
        string((self.class.access || bit_field.type).to_s.upcase)
      end

      def model_name
        :rggen_ral_field
      end

      def hdl_path
        "g_#{bit_field.name}.u_bit_field.value"
      end
    end

    default_item do
    end

    factory do
      def select_target_item(_, bit_field)
        @target_items[bit_field.type]
      end
    end
  end
end