Module: Udb::HasFields

Included in:
Csr, Mmr
Defined in:
lib/udb/obj/has_fields.rb

Overview

Shared field-management methods for register-like objects (CSR, MMR).

Includers must provide:

- length(effective_xlen)  — register width in bits
- max_length              — largest possible width
- cfg_arch                — ConfiguredArchitecture
- name                    — register name (String)
- defined_by_condition    — ExtensionRequirement condition
- exists_in_cfg?(cfg_arch)

Instance Method Summary collapse

Instance Method Details

#affected_by?(ext_ver) ⇒ Boolean

Returns Whether or not the presence of ext_ver affects this register definition.

Returns:

  • (Boolean)

    Whether or not the presence of ext_ver affects this register definition



145
146
147
148
# File 'lib/udb/obj/has_fields.rb', line 145

def affected_by?(ext_ver)
  defined_by_condition.satisfiability_depends_on_ext_req?(ext_ver.to_ext_req) || \
    fields.any? { |field| field.affected_by?(ext_ver) }
end

#field(field_name) ⇒ CsrField?

Returns field named ‘field_name’ if it exists, and nil otherwise.

Returns:

  • (CsrField, nil)

    field named ‘field_name’ if it exists, and nil otherwise



56
57
58
# File 'lib/udb/obj/has_fields.rb', line 56

def field(field_name)
  field_hash[field_name.to_s]
end

#field?(field_name) ⇒ Boolean

Returns true if a field named ‘field_name’ is defined.

Returns:

  • (Boolean)

    true if a field named ‘field_name’ is defined



51
52
53
# File 'lib/udb/obj/has_fields.rb', line 51

def field?(field_name)
  field_hash.key?(field_name.to_s)
end

#field_hashHash<String,CsrField>

Returns Hash of fields, indexed by field name.

Returns:

  • (Hash<String,CsrField>)

    Hash of fields, indexed by field name



39
40
41
42
43
44
45
46
47
48
# File 'lib/udb/obj/has_fields.rb', line 39

def field_hash
  @field_hash unless @field_hash.nil?

  @field_hash = {}
  fields.each do |field|
    @field_hash[field.name] = field
  end

  @field_hash
end

#fieldsArray<CsrField>

Returns All known fields of this register.

Returns:

  • (Array<CsrField>)

    All known fields of this register



21
22
23
24
25
26
27
28
29
30
# File 'lib/udb/obj/has_fields.rb', line 21

def fields
  return @fields unless @fields.nil?

  @fields =
    if @data["fields"].nil?
      []
    else
      @data["fields"].map { |field_name, field_data| CsrField.new(self, field_name, field_data) }
    end
end

#fields_for(effective_xlen) ⇒ Array<CsrField>

Returns All known fields when XLEN == effective_xlen.

Parameters:

  • effective_xlen (Integer or nil)

    32 or 64 for fixed xlen, nil for dynamic

Returns:

  • (Array<CsrField>)

    All known fields when XLEN == effective_xlen



34
35
36
# File 'lib/udb/obj/has_fields.rb', line 34

def fields_for(effective_xlen)
  fields.select { |f| effective_xlen.nil? || f.base.nil? || f.base == effective_xlen }
end

#optional_in_cfg?(cfg_arch) ⇒ Boolean

Returns whether or not the register is optional in the config.

Parameters:

Returns:

  • (Boolean)

    whether or not the register is optional in the config



133
134
135
136
137
138
139
140
141
142
# File 'lib/udb/obj/has_fields.rb', line 133

def optional_in_cfg?(cfg_arch)
  unless cfg_arch.is_a?(ConfiguredArchitecture)
    raise ArgumentError, "cfg_arch is a class #{cfg_arch.class} but must be a ConfiguredArchitecture"
  end
  raise "optional_in_cfg? should only be used by a partially-specified arch def" unless cfg_arch.partially_configured?

  @optional_in_cfg ||=
    exists_in_cfg?(cfg_arch) &&
    (defined_by_condition.satisfied_by_cfg_arch?(cfg_arch) == SatisfiedResult::Maybe)
end

#possible_fieldsArray<CsrField>

Returns All implemented fields, excluding fields defined by unimplemented extensions.

Returns:

  • (Array<CsrField>)

    All implemented fields, excluding fields defined by unimplemented extensions



61
62
63
64
65
# File 'lib/udb/obj/has_fields.rb', line 61

def possible_fields
  @possible_fields ||= fields.select do |f|
    f.exists_in_cfg?(cfg_arch)
  end
end

#possible_fields_for(effective_xlen) ⇒ Array<CsrField>

Returns All implemented fields at the given effective XLEN.

Parameters:

  • effective_xlen (Integer or nil)

    32 or 64 for fixed xlen, nil for dynamic

Returns:

  • (Array<CsrField>)

    All implemented fields at the given effective XLEN

Raises:

  • (ArgumentError)


69
70
71
72
73
74
75
76
77
# File 'lib/udb/obj/has_fields.rb', line 69

def possible_fields_for(effective_xlen)
  raise ArgumentError, "effective_xlen is non-nil and is a #{effective_xlen.class} but must be an Integer" unless effective_xlen.nil? || effective_xlen.is_a?(Integer)

  @possible_fields_for ||= {}
  @possible_fields_for[effective_xlen] ||=
    possible_fields.select do |f|
      f.base.nil? || f.base == effective_xlen
    end
end

#wavedrom_desc(cfg_arch, effective_xlen, exclude_unimplemented: false, optional_type: 2) ⇒ Hash

Returns A representation of the WaveDrom drawing for the register.

Parameters:

  • cfg_arch (ConfiguredArchitecture)

    Architecture definition

  • effective_xlen (Integer, nil)

    Effective XLEN to use

  • exclude_unimplemented (Boolean) (defaults to: false)

    If true, do not include unimplemented fields

  • optional_type (Integer) (defaults to: 2)

    Wavedrom type (fill color) for optional fields

Returns:

  • (Hash)

    A representation of the WaveDrom drawing for the register

Raises:

  • (ArgumentError)


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/udb/obj/has_fields.rb', line 89

def wavedrom_desc(cfg_arch, effective_xlen, exclude_unimplemented: false, optional_type: 2)
  unless cfg_arch.is_a?(ConfiguredArchitecture)
    raise ArgumentError, "cfg_arch is a class #{cfg_arch.class} but must be a ConfiguredArchitecture"
  end
  raise ArgumentError, "effective_xlen is non-nil and is a #{effective_xlen.class} but must be an Integer" unless effective_xlen.nil? || effective_xlen.is_a?(Integer)

  desc = {
    "reg" => []
  }
  last_idx = -1

  field_list =
    if exclude_unimplemented
      possible_fields_for(effective_xlen)
    else
      fields_for(effective_xlen)
    end

  field_list.sort! { |a, b| a.location(effective_xlen).min <=> b.location(effective_xlen).min }
  field_list.each do |field|
    if field.location(effective_xlen).min != last_idx + 1
      # reserved space
      n = field.location(effective_xlen).min - last_idx - 1
      raise "negative reserved space? #{n} #{name} #{field.location(effective_xlen).min} #{last_idx + 1}" if n <= 0

      desc["reg"] << { "bits" => n, type: 1 }
    end
    if cfg_arch.partially_configured? && field.optional_in_cfg?(cfg_arch)
      desc["reg"] << { "bits" => field.location(effective_xlen).size, "name" => field.name, type: optional_type }
    else
      desc["reg"] << { "bits" => field.location(effective_xlen).size, "name" => field.name, type: 3 }
    end
    last_idx = field.location(effective_xlen).max
  end
  if !field_list.empty? && (field_list.last.location(effective_xlen).max != (length(effective_xlen) - 1))
    desc["reg"] << { "bits" => (length(effective_xlen) - 1 - last_idx), type: 1 }
  end
  desc["config"] = { "bits" => length(effective_xlen) }
  desc["config"]["lanes"] = length(effective_xlen) / 16
  desc
end

#writableBoolean

Returns Whether or not the register can be written by software.

Returns:

  • (Boolean)

    Whether or not the register can be written by software



80
81
82
# File 'lib/udb/obj/has_fields.rb', line 80

def writable
  @data["writable"]
end