Class: Udb::Csr

Inherits:
TopLevelDatabaseObject show all
Includes:
Idl::Csr, CertifiableObject
Defined in:
lib/udb/obj/csr.rb

Overview

CSR definition

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

This class inherits a constructor from Udb::TopLevelDatabaseObject

Instance Attribute Details

#nameString (readonly)

Returns:

  • (String)


22
23
24
# File 'lib/udb/obj/csr.rb', line 22

def name
  @name
end

Instance Method Details

#==(other) ⇒ Object



24
25
26
27
28
29
30
# File 'lib/udb/obj/csr.rb', line 24

def ==(other)
  if other.is_a?(Csr)
    name == other.name
  else
    raise ArgumentError, "Csr is not comparable to #{other.class.name}"
  end
end

#addressInteger?

Returns:

  • (Integer)

    CSR address (the value passed as an immediate to csrrw, etc.)

  • (nil)

    if the CSR is indirect-accesss-only



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

def address
  @data["address"]
end

#affected_by?(ext_ver) ⇒ Boolean

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

Returns:

  • (Boolean)

    Whether or not the presence of ext_ver affects this CSR definition



694
695
696
# File 'lib/udb/obj/csr.rb', line 694

def affected_by?(ext_ver)
  defined_by_condition.possibly_satisfied_by?(ext_ver) || fields.any? { |field| field.affected_by?(ext_ver) }
end

#baseInteger?

Returns:

  • (Integer)

    32 or 64, the XLEN this CSR is exclusively defined in

  • (nil)

    if this CSR is defined in all bases



95
# File 'lib/udb/obj/csr.rb', line 95

def base = @data["base"]

#bitfield_type(cfg_arch, effective_xlen = nil) ⇒ Idl::BitfieldType

Returns A bitfield type that can represent all fields of the CSR.

Parameters:

  • effective_xlen (Integer or nil) (defaults to: nil)

    32 or 64 for fixed xlen, nil for dynamic

Returns:

  • (Idl::BitfieldType)

    A bitfield type that can represent all fields of the CSR



476
477
478
479
480
481
482
483
# File 'lib/udb/obj/csr.rb', line 476

def bitfield_type(cfg_arch, effective_xlen = nil)
  Idl::BitfieldType.new(
    "Csr#{name.capitalize}Bitfield",
    length(effective_xlen),
    fields_for(effective_xlen).map(&:name),
    fields_for(effective_xlen).map { |f| f.location(effective_xlen) }
  )
end

#cert_coverage_point(id) ⇒ CertNormativeRule? Originally defined in module CertifiableObject

Parameters:

  • id (String)

    Unique ID for the normative rule

Returns:

  • (CertNormativeRule)
  • (nil)

    if there is no certification normative ruleed with ID of id

#cert_coverage_point_hashHash<String, CertNormativeRule> Originally defined in module CertifiableObject

Returns Hash with ID as key of all normative rules defined by database object.

Returns:

  • (Hash<String, CertNormativeRule>)

    Hash with ID as key of all normative rules defined by database object

#cert_normative_rulesArray<CertNormativeRule> Originally defined in module CertifiableObject

Returns:

#cert_test_procedure(id) ⇒ CertTestProcedure? Originally defined in module CertifiableObject

Parameters:

  • id (String)

    Unique ID for test procedure

Returns:

  • (CertTestProcedure)
  • (nil)

    if there is no certification test procedure with ID id

#cert_test_procedure_hashHash<String, CertTestProcedure> Originally defined in module CertifiableObject

Returns Hash of all normative rules defined by database object.

Returns:

  • (Hash<String, CertTestProcedure>)

    Hash of all normative rules defined by database object

#cert_test_proceduresArray<CertTestProcedure> Originally defined in module CertifiableObject

Returns:

#defined_in_all_bases?Boolean

Returns true if this CSR is defined regardless of the effective XLEN.

Returns:

  • (Boolean)

    true if this CSR is defined regardless of the effective XLEN



104
# File 'lib/udb/obj/csr.rb', line 104

def defined_in_all_bases? = @data["base"].nil?

#defined_in_base32?Boolean

Returns true if this CSR is defined when XLEN is 32.

Returns:

  • (Boolean)

    true if this CSR is defined when XLEN is 32



98
# File 'lib/udb/obj/csr.rb', line 98

def defined_in_base32? = @data["base"].nil? || @data["base"] == 32

#defined_in_base64?Boolean

Returns true if this CSR is defined when XLEN is 64.

Returns:

  • (Boolean)

    true if this CSR is defined when XLEN is 64



101
# File 'lib/udb/obj/csr.rb', line 101

def defined_in_base64? = @data["base"].nil? || @data["base"] == 64

#defined_in_base?(xlen) ⇒ Boolean

Returns true if this CSR is defined when XLEN is xlen.

Parameters:

  • xlen (32, 64)

    base

Returns:

  • (Boolean)

    true if this CSR is defined when XLEN is xlen



108
# File 'lib/udb/obj/csr.rb', line 108

def defined_in_base?(xlen) = @data["base"].nil? || @data["base"] == xlen

#description_htmlString

parse description field with asciidoctor, and return the HTML result

Returns:

  • (String)

    Parsed description in HTML



409
410
411
# File 'lib/udb/obj/csr.rb', line 409

def description_html
  Asciidoctor.convert description
end

#dynamic_length?Boolean

Returns Whether or not the length of the CSR depends on a runtime value (e.g., mstatus.SXL).

Returns:

  • (Boolean)

    Whether or not the length of the CSR depends on a runtime value (e.g., mstatus.SXL)



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/udb/obj/csr.rb', line 158

def dynamic_length?
  return false if @data["length"].is_a?(Integer)

  # when a CSR is only defined in one base, its length can't change
  return false unless @data["base"].nil?

  case @data["length"]
  when "MXLEN"
    # mxlen can never change at runtime, so if we have it in the config, the length is not dynamic
    # if we don't have it in the config, we don't know what the length is
    cfg_arch.mxlen.nil?
  when "SXLEN"
    # dynamic if either we don't know SXLEN or SXLEN is explicitly mutable
    [nil, 3264].include?(cfg_arch.param_values["SXLEN"])
  when "VSXLEN"
    # dynamic if either we don't know VSXLEN or VSXLEN is explicitly mutable
    [nil, 3264].include?(cfg_arch.param_values["VSXLEN"])
  when "XLEN"
    # must always have M-mode
    # SXLEN condition applies if S-mode is possible
    # VSXLEN condition applies if VS-mode is possible
    (cfg_arch.mxlen.nil?) || \
    (cfg_arch.possible_extensions.map(&:name).include?("S") && \
    [nil, 3264].include?(cfg_arch.param_values["SXLEN"])) || \
    (cfg_arch.possible_extensions.map(&:name).include?("H") && \
    [nil, 3264].include?(cfg_arch.param_values["VSXLEN"]))
  else
    raise "Unexpected length"
  end
end

#exists_in_cfg?(cfg_arch) ⇒ Boolean

Returns whether or not the CSR is possibly implemented given the supplied config options.

Parameters:

Returns:

  • (Boolean)

    whether or not the CSR is possibly implemented given the supplied config options

Raises:

  • (ArgumentError)


666
667
668
669
670
671
# File 'lib/udb/obj/csr.rb', line 666

def exists_in_cfg?(cfg_arch)
  raise ArgumentError, "cfg_arch is a class #{cfg_arch.class} but must be a ConfiguredArchitecture" unless cfg_arch.is_a?(ConfiguredArchitecture)

  @exists_in_cfg ||=
    cfg_arch.possible_csrs.include?(self)
end

#field(field_name) ⇒ Object

returns [CsrField,nil] field named ‘field_name’ if it exists, and nil otherwise



470
471
472
# File 'lib/udb/obj/csr.rb', line 470

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 in the csr, and false otherwise.

Returns:

  • (Boolean)

    true if a field named ‘field_name’ is defined in the csr, and false otherwise



465
466
467
# File 'lib/udb/obj/csr.rb', line 465

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



453
454
455
456
457
458
459
460
461
462
# File 'lib/udb/obj/csr.rb', line 453

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 CSR.

Returns:

  • (Array<CsrField>)

    All known fields of this CSR



438
439
440
441
442
# File 'lib/udb/obj/csr.rb', line 438

def fields
  return @fields unless @fields.nil?

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

#fields_for(effective_xlen) ⇒ Array<CsrField>

equivalent to #fields if effective_xlen is nil

Parameters:

  • effective_xlen (Integer, nil)

    32 or 64 for fixed xlen, nil for dynamic

Returns:

  • (Array<CsrField>)

    All known fields of this CSR when XLEN == effective_xlen



448
449
450
# File 'lib/udb/obj/csr.rb', line 448

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

#fill_symtab(ast, effective_xlen) ⇒ IdL::SymbolTable

Returns A symbol table populated with globals and syms specific to this CSR.

Parameters:

  • ast (Idl::AstNode)

    An abstract syntax tree that will be evaluated with the returned symbol table

Returns:

  • (IdL::SymbolTable)

    A symbol table populated with globals and syms specific to this CSR



554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
# File 'lib/udb/obj/csr.rb', line 554

def fill_symtab(ast, effective_xlen)
  symtab = @cfg_arch.symtab.global_clone
  symtab.push(ast)
  # all CSR instructions are 32-bit
  symtab.add(
    "__instruction_encoding_size",
    Idl::Var.new("__instruction_encoding_size", Idl::Type.new(:bits, width: 6), 32)
  )
  symtab.add(
    "__expected_return_type",
    Idl::Type.new(:bits, width: 128)
  )
  if symtab.get("MXLEN").value.nil?
    symtab.add(
      "MXLEN",
      Idl::Var.new(
        "MXLEN",
        Idl::Type.new(:bits, width: 6, qualifiers: [:const]),
        effective_xlen,
        param: true
      )
    )
  end
  symtab
end

#format_changes_with_xlen?Boolean

Returns Whether or not the format of this CSR changes when the effective XLEN changes in some mode.

Returns:

  • (Boolean)

    Whether or not the format of this CSR changes when the effective XLEN changes in some mode



111
112
113
114
115
# File 'lib/udb/obj/csr.rb', line 111

def format_changes_with_xlen?
  dynamic_length? || \
    (defined_in_all_bases? && (possible_fields_for(32) != possible_fields_for(64))) || \
    possible_fields.any?(&:dynamic_location?)
end

#has_custom_sw_read?Boolean

Returns true if the CSR has a custom sw_read function.

Returns:

  • (Boolean)

    true if the CSR has a custom sw_read function



486
487
488
# File 'lib/udb/obj/csr.rb', line 486

def has_custom_sw_read?
  @data.key?("sw_read()") && !@data["sw_read()"].empty?
end

#implemented_without?(ext_name) ⇒ Boolean

can this CSR be implemented if ext_name is not?

Parameters:

  • ext_name (String)

Returns:

  • (Boolean)


77
78
79
80
81
82
83
84
85
86
87
# File 'lib/udb/obj/csr.rb', line 77

def implemented_without?(ext_name)
  raise "#{ext_name} is not an extension" if @cfg_arch.extension(ext_name).nil?

  defined_by_condition.satisfied_by? do |ext_req|
    if ext_req.name == ext_name
      false
    else
      @cfg_arch.possible_extension_versions.any? { |ext_ver| ext_req.satisfied_by?(ext_ver) }
    end
  end
end

#indirect?Boolean

Returns Whether or not the CSR can be accessed by indirect address.

Returns:

  • (Boolean)

    Whether or not the CSR can be accessed by indirect address



39
40
41
# File 'lib/udb/obj/csr.rb', line 39

def indirect?
  @data.key?("indirect_address")
end

#indirect_addressInteger

Returns The indirect address.

Returns:

  • (Integer)

    The indirect address



44
45
46
# File 'lib/udb/obj/csr.rb', line 44

def indirect_address
  @data["indirect_address"]
end

#indirect_slotInteger

Returns The indirect window slot.

Returns:

  • (Integer)

    The indirect window slot



49
50
51
# File 'lib/udb/obj/csr.rb', line 49

def indirect_slot
  @data["indirect_slot"]
end

#length(effective_xlen = nil) ⇒ Integer?

Parameters:

  • effective_xlen (Integer, nil) (defaults to: nil)

    32 or 64 for fixed xlen, nil for dynamic

Returns:

  • (Integer, nil)


204
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
# File 'lib/udb/obj/csr.rb', line 204

def length(effective_xlen = nil)
  case @data["length"]
  when "MXLEN"
    return T.must(cfg_arch.mxlen) unless cfg_arch.mxlen.nil?

    if !@data["base"].nil?
      @data["base"]
    else
      # don't know MXLEN
      effective_xlen
    end
  when "SXLEN"
    if cfg_arch.param_values.key?("SXLEN")
      if cfg_arch.param_values["SXLEN"] == 3264
        effective_xlen
      else
        cfg_arch.param_values["SXLEN"]
      end
    elsif !@data["base"].nil?
      # if this CSR is only available in one base, then we know its length
      @data["base"]
    else
      # don't know SXLEN
      effective_xlen
    end
  when "VSXLEN"
    if cfg_arch.param_values.key?("VSXLEN")
      if cfg_arch.param_values["VSXLEN"] == 3264
        effective_xlen
      else
        cfg_arch.param_values["VSXLEN"]
      end
    elsif !@data["base"].nil?
      # if this CSR is only available in one base, then we know its length
      @data["base"]
    else
      # don't know VSXLEN
      effective_xlen
    end
  when "XLEN"
    effective_xlen
  when Integer
    @data["length"]
  else
    raise "Unexpected length field for #{name}"
  end
end

#length_cond32String

Returns IDL condition of when the effective xlen is 32.

Returns:

  • (String)

    IDL condition of when the effective xlen is 32



325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/udb/obj/csr.rb', line 325

def length_cond32
  case @data["length"]
  when "MXLEN"
    "CSR[misa].MXL == 0"
  when "SXLEN"
    "CSR[mstatus].SXL == 0"
  when "VSXLEN"
    "CSR[hstatus].VSXL == 0"
  when "XLEN"
    "(priv_mode() == PrivilegeMode::M && CSR[misa].MXL == 0) || (priv_mode() == PrivilegeMode::S && CSR[mstatus].SXL == 0) || (priv_mode() == PrivilegeMode::VS && CSR[hstatus].VSXL == 0)"
  else
    raise "Unexpected length #{@data['length']} for #{name}"
  end
end

#length_cond64String

Returns IDL condition of when the effective xlen is 64.

Returns:

  • (String)

    IDL condition of when the effective xlen is 64



341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/udb/obj/csr.rb', line 341

def length_cond64
  case @data["length"]
  when "MXLEN"
    "CSR[misa].MXL == 1"
  when "SXLEN"
    "CSR[mstatus].SXL == 1"
  when "VSXLEN"
    "CSR[hstatus].VSXL == 1"
  when "XLEN"
    "(priv_mode() == PrivilegeMode::M && CSR[misa].MXL == 1) || (priv_mode() == PrivilegeMode::S && CSR[mstatus].SXL == 1) || (priv_mode() == PrivilegeMode::VS && CSR[hstatus].VSXL == 1)"
  else
    raise "Unexpected length"
  end
end

#length_pretty(effective_xlen = nil) ⇒ String

Returns Pretty-printed length string.

Parameters:

  • effective_xlen (Integer or nil) (defaults to: nil)

    32 or 64 for fixed xlen, nil for dynamic

Returns:

  • (String)

    Pretty-printed length string

Raises:

  • (ArgumentError)


358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'lib/udb/obj/csr.rb', line 358

def length_pretty(effective_xlen=nil)
  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)
  if dynamic_length?
    cond =
      case @data["length"]
      when "MXLEN"
        "CSR[misa].MXL == %%"
      when "SXLEN"
        "CSR[mstatus].SXL == %%"
      when "VSXLEN"
        "CSR[hstatus].VSXL == %%"
      when "XLEN"
        "(priv_mode() == PrivilegeMode::M && CSR[misa].MXL == %%) || (priv_mode() == PrivilegeMode::S && CSR[mstatus].SXL == %%) || (priv_mode() == PrivilegeMode::VS && CSR[hstatus].VSXL == %%)"
      else
        raise "Unexpected length '#{@data['length']}'"
      end

    if effective_xlen.nil?
      [
        "* #{length(32)} when #{cond.sub('%%', '0')}",
        "* #{length(64)} when #{cond.sub('%%', '1')}"
      ].join("\n")
    else
      "#{length(effective_xlen)}-bit"
    end
  else
    "#{length()}-bit"
  end
end

#long_nameObject



58
59
60
# File 'lib/udb/obj/csr.rb', line 58

def long_name
  @data["long_name"]
end

#max_lengthInteger

sig { override.returns(Integer) } dhower: sorbet doesn’t think this is an override??

Returns:

  • (Integer)

    The largest length of this CSR in any valid mode/xlen for the config



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
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
# File 'lib/udb/obj/csr.rb', line 255

def max_length
  return @data["base"] unless @data["base"].nil?

  case @data["length"]
  when "MXLEN"
    cfg_arch.mxlen || 64
  when "SXLEN"
    if cfg_arch.param_values.key?("SXLEN")
      if cfg_arch.param_values["SXLEN"] == 3264
        64
      else
        cfg_arch.param_values["SXLEN"]
      end
    else
      64
    end
  when "VSXLEN"
    if cfg_arch.param_values.key?("VSXLEN")
      if cfg_arch.param_values["VSXLEN"] == 3264
        64
      else
        cfg_arch.param_values["VSXLEN"]
      end
    else
      64
    end
  when "XLEN"
    if cfg_arch.possible_extensions.map(&:name).include?("M")
      cfg_arch.mxlen || 64
    elsif cfg_arch.possible_extensions.map(&:name).include?("S")
      if cfg_arch.param_values.key?("SXLEN")
        if cfg_arch.param_values["SXLEN"] == 3264
          64
        else
          cfg_arch.param_values["SXLEN"]
        end
      else
        # SXLEN can never be greater than MXLEN
        cfg_arch.mxlen || 64
      end
    elsif cfg_arch.possible_extensions.map(&:name).include?("H")
      if cfg_arch.param_values.key?("VSXLEN")
        if cfg_arch.param_values["VSXLEN"] == 3264
          64
        else
          cfg_arch.param_values["VSXLEN"]
        end
      else
        # VSXLEN can never be greater than MXLEN or SXLEN
        if cfg_arch.param_values.key?("SXLEN")
          if cfg_arch.param_values["SXLEN"] == 3264
            64
          else
            cfg_arch.param_values["SXLEN"]
          end
        else
          cfg_arch.mxlen || 64
        end
      end
    else
      raise "Unexpected"
    end
  when Integer
    @data["length"]
  else
    raise "Unexpected length field for #{name}"
  end
end

#min_lengthInteger

Returns Smallest length of the CSR in any mode.

Parameters:

Returns:

  • (Integer)

    Smallest length of the CSR in any mode



191
192
193
194
195
196
197
198
199
200
# File 'lib/udb/obj/csr.rb', line 191

def min_length
  case @data["length"]
  when "MXLEN", "SXLEN", "VSXLEN", "XLEN"
    @cfg_arch.possible_xlens.min
  when Integer
    @data["length"]
  else
    raise "Unexpected length"
  end
end

#modes_with_accessObject

list of modes that can potentially access the field



389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'lib/udb/obj/csr.rb', line 389

def modes_with_access
  case @data["priv_mode"]
  when "M"
    ["M"]
  when "S"
    ["M", "S", "VS"]
  when "U"
    ["M", "S", "U", "VS", "VU"]
  when "VS"
    ["M", "S", "VS"]
  when "D"
    ["M", "D"]
  else
    raise "unexpected priv mode"
  end
end

#optional_in_cfg?(cfg_arch) ⇒ Boolean

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

Parameters:

Returns:

  • (Boolean)

    whether or not the CSR is optional in the config



675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
# File 'lib/udb/obj/csr.rb', line 675

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?

  # exists in config and isn't satisfied by some combo of mandatory extensions
  @optional_in_cfg ||=
    exists_in_cfg?(cfg_arch) &&
    !defined_by_condition.satisfied_by? do |defining_ext_req|
      cfg_arch.mandatory_extension_reqs.any? do |mand_ext_req|
        mand_ext_req.satisfying_versions.any? do |mand_ext_ver|
          defining_ext_req.satisfied_by?(mand_ext_ver)
        end
      end
    end
end

#possible_fieldsArray<CsrField>

Returns All implemented fields for this CSR Excluded any fields that are defined by unimplemented extensions.

Returns:

  • (Array<CsrField>)

    All implemented fields for this CSR Excluded any fields that are defined by unimplemented extensions



430
431
432
433
434
# File 'lib/udb/obj/csr.rb', line 430

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 for this CSR at the given effective XLEN, sorted by location (smallest location first) Excluded any fields that are defined by unimplemented extensions or a base that is not effective_xlen.

Parameters:

  • effective_xlen (Integer or nil)

    32 or 64 for fixed xlen, nil for dynamic

Returns:

  • (Array<CsrField>)

    All implemented fields for this CSR at the given effective XLEN, sorted by location (smallest location first) Excluded any fields that are defined by unimplemented extensions or a base that is not effective_xlen

Raises:

  • (ArgumentError)


416
417
418
419
420
421
422
423
424
425
# File 'lib/udb/obj/csr.rb', line 416

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

#priv_modeString

Returns Least-privileged mode that can access this CSR. One of [‘m’, ‘s’, ‘u’, ‘vs’, ‘vu’].

Returns:

  • (String)

    Least-privileged mode that can access this CSR. One of [‘m’, ‘s’, ‘u’, ‘vs’, ‘vu’]



54
55
56
# File 'lib/udb/obj/csr.rb', line 54

def priv_mode
  @data["priv_mode"]
end

#pruned_sw_read_ast(effective_xlen) ⇒ Object

Parameters:

  • effective_xlen (Integer or nil)

    32 or 64 for fixed xlen, nil for dynamic

Raises:

  • (ArgumentError)


581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
# File 'lib/udb/obj/csr.rb', line 581

def pruned_sw_read_ast(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)
  @pruned_sw_read_ast ||= {}
  return @pruned_sw_read_ast[effective_xlen] unless @pruned_sw_read_ast[effective_xlen].nil?

  ast = type_checked_sw_read_ast(effective_xlen)

  symtab = fill_symtab(ast, effective_xlen)

  ast = ast.prune(symtab)
  ast.freeze_tree(@cfg_arch.symtab)

  @cfg_arch.idl_compiler.type_check(
    ast,
    symtab,
    "CSR[#{name}].sw_read()"
  )

  symtab.pop
  symtab.release

  @pruned_sw_read_ast[effective_xlen] = ast
end

#reachable_functions(effective_xlen = nil) ⇒ Array<Idl::FunctionDefAst>

Returns List of functions reachable from this CSR’s sw_read or a field’s sw_write function.

Parameters:

  • effective_xlen (Integer or nil) (defaults to: nil)

    32 or 64 for fixed xlen, nil for dynamic

Returns:

  • (Array<Idl::FunctionDefAst>)

    List of functions reachable from this CSR’s sw_read or a field’s sw_write function

Raises:

  • (ArgumentError)


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/udb/obj/csr.rb', line 119

def reachable_functions(effective_xlen = nil)
  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)
  return @reachable_functions unless @reachable_functions.nil?

  fns = []

  if has_custom_sw_read?
    xlens =
      if cfg_arch.multi_xlen?
        defined_in_all_bases? ? [32, 64] : [base]
      else
        [cfg_arch.possible_xlens[0]]
      end
    xlens.each do |xlen|
      ast = pruned_sw_read_ast(xlen)
      symtab = cfg_arch.symtab.deep_clone
      symtab.push(ast)
      fns.concat(ast.reachable_functions(symtab))
    end
  end

  if cfg_arch.multi_xlen?
    possible_fields_for(32).each do |field|
      fns.concat(field.reachable_functions(32))
    end
    possible_fields_for(64).each do |field|
      fns.concat(field.reachable_functions(64))
    end
  else
    possible_fields_for(cfg_arch.mxlen).each do |field|
      fns.concat(field.reachable_functions(cfg_arch.mxlen))
    end
  end

  @reachable_functions = fns.uniq
end

#sw_read_ast(symtab) ⇒ FunctionBodyAst

Returns The abstract syntax tree of the sw_read() function.

Parameters:

Returns:

  • (FunctionBodyAst)

    The abstract syntax tree of the sw_read() function

Raises:

  • (ArgumentError)


528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
# File 'lib/udb/obj/csr.rb', line 528

def sw_read_ast(symtab)
  raise ArgumentError, "Argument should be a symtab" unless symtab.is_a?(Idl::SymbolTable)

  return @sw_read_ast unless @sw_read_ast.nil?
  return nil if @data["sw_read()"].nil?

  # now, parse the function
  @sw_read_ast = @cfg_arch.idl_compiler.compile_func_body(
    @data["sw_read()"],
    return_type: Idl::Type.new(:bits, width: 128), # big int to hold special return values
    name: "CSR[#{name}].sw_read()",
    input_file: __source,
    input_line: source_line(["sw_read()"]),
    symtab:,
    type_check: false
  )

  raise "unexpected #{@sw_read_ast.class}" unless @sw_read_ast.is_a?(Idl::FunctionBodyAst)

  @sw_read_ast.set_input_file_unless_already_set(T.must(__source), source_line(["sw_read()"]))

  @sw_read_ast
end

#type_checked_sw_read_ast(effective_xlen) ⇒ Object

Parameters:

  • effective_xlen (Integer or nil)

    32 or 64 for fixed xlen, nil for dynamic

Raises:

  • (ArgumentError)


491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
# File 'lib/udb/obj/csr.rb', line 491

def type_checked_sw_read_ast(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)
  @type_checked_sw_read_asts ||= {}
  ast = @type_checked_sw_read_asts[effective_xlen.nil? ? :none : effective_xlen]
  return ast unless ast.nil?

  symtab = cfg_arch.symtab.global_clone
  symtab.push(ast)
  # all CSR instructions are 32-bit
  unless effective_xlen.nil?
    symtab.add(
      "__effective_xlen",
      Idl::Var.new("__effective_xlen", Idl::Type.new(:bits, width: 6), effective_xlen)
    )
  end
  symtab.add(
    "__instruction_encoding_size",
    Idl::Var.new("__instruction_encoding_size", Idl::Type.new(:bits, width: 6), 32)
  )
  symtab.add(
    "__expected_return_type",
    Idl::Type.new(:bits, width: 128)
   )

  ast = sw_read_ast(symtab)
  @cfg_arch.idl_compiler.type_check(
    ast,
    symtab,
    "CSR[#{name}].sw_read()"
  )
  symtab.pop
  symtab.release
  @type_checked_sw_read_asts[effective_xlen.nil? ? :none : effective_xlen] = ast
end

#valueInteger?

Returns:

  • (Integer, nil)


69
70
71
72
73
# File 'lib/udb/obj/csr.rb', line 69

def value
  return nil unless fields.all? { |f| f.type == "RO" }

  fields.reduce(0) { |val, f| val | (f.reset_value << f.location.begin) }
end

#virtual_addressInteger?

Returns:

  • (Integer)

    CSR address in VS/VU mode, if different from other modes

  • (nil)

    If the CSR is not accessible in VS/VU mode, or if it’s address does not change in those modes



64
65
66
# File 'lib/udb/obj/csr.rb', line 64

def virtual_address
  @data["virtual_address"]
end

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

Returns A representation of the WaveDrom drawing for the CSR (should be turned into JSON for wavedrom).

Examples:

Result for an I-type instruction

{reg: [
  {bits: 7,  name: 'OP-IMM',    attr: ['{op_major_name}'], type: 8},
  {bits: 5,  name: 'rd',        attr: [''], type: 2},
  {bits: 3,  name: {funct3},    attr: ['{mnemonic}'], type: 8},
  {bits: 5,  name: 'rs1',       attr: [''], type: 4},
  {bits: 12, name: 'imm12',     attr: [''], type: 6}
]}

Parameters:

  • cfg_arch (ConfiguredArchitecture)

    A configuration

  • effective_xlen (Integer, nil)

    Effective XLEN to use when CSR length is dynamic

  • exclude_unimplemented (Boolean) (defaults to: false)

    If true, do not create include unimplemented fields in the figure

  • optional_type (Integer) (defaults to: 2)

    Wavedrom type (Fill color) for fields that are optional (not mandatory) in a partially-specified cfg_arch

Returns:

  • (Hash)

    A representation of the WaveDrom drawing for the CSR (should be turned into JSON for wavedrom)

Raises:

  • (ArgumentError)


619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
# File 'lib/udb/obj/csr.rb', line 619

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
      # have some 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 = T.cast(field.location(effective_xlen).max, Integer)
  end
  if !field_list.empty? && (field_list.last.location(effective_xlen).max != (T.must(length(effective_xlen)) - 1))
    # reserved space at the end
    desc["reg"] << { "bits" => (T.must(length(effective_xlen)) - 1 - last_idx), type: 1 }
    # desc['reg'] << { 'bits' => 1, type: 1 }
  end
  desc["config"] = { "bits" => length(effective_xlen) }
  desc["config"]["lanes"] = T.must(length(effective_xlen)) / 16
  desc
end

#writableObject



89
90
91
# File 'lib/udb/obj/csr.rb', line 89

def writable
  @data["writable"]
end