Class: Udb::Csr

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

Overview

CSR definition

Defined Under Namespace

Classes: MemoizedState

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data, data_path, arch)

Parameters:



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

def initialize(data, data_path, arch)
  super(data, data_path, arch)

  @memo = MemoizedState.new(reachable_functions: {})
end

Instance Attribute Details

#nameString (readonly)

Returns:

  • (String)


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

def name
  @name
end

Instance Method Details

#==(other) ⇒ Object



36
37
38
39
40
41
42
# File 'lib/udb/obj/csr.rb', line 36

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



46
47
48
# File 'lib/udb/obj/csr.rb', line 46

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



730
731
732
733
# File 'lib/udb/obj/csr.rb', line 730

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

#basenil, Integer

Returns:

  • (nil)

    if this CSR is defined in all bases

  • (Integer, nil)

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



95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/udb/obj/csr.rb', line 95

def base
  return @base if defined?(@base)

  @base =
    if defined_by_condition.rv32_only?
      32
    elsif defined_by_condition.rv64_only?
      64
    else
      nil
    end
end

#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



516
517
518
519
520
521
522
523
# File 'lib/udb/obj/csr.rb', line 516

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



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

def defined_in_all_bases? = 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



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

def defined_in_base32? = base != 64

#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



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

def defined_in_base64? = base != 32

#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



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

def defined_in_base?(xlen) = xlen == 32 ? defined_in_base32? : defined_in_base64?

#defining_extension_requirementsArray<ExtensionRequirement>

return list of extension requirements that must be implemented for this Csr to be defined

will not include any extension requirements that are conditionally required e.g., definedBy = Zblah if XLEN == 32; defining_extension_requirements will not include Zblah

Returns:



430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'lib/udb/obj/csr.rb', line 430

def defining_extension_requirements
  @defining_extension_requirements ||=
    begin
      pb =
        Udb.create_progressbar(
          "Determining defining extensions for CSR #{name} [:bar] :current/:total",
          total: @cfg_arch.csrs.size,
          clear: true
        )
      @cfg_arch.extensions.map do |ext|
        pb.advance
        vers = ext.versions.select do |ext_ver|
          if defined_by_condition.mentions?(ext_ver)
            (-defined_by_condition & ext_ver.to_condition).unsatisfiable?
          end
        end
        unless vers.empty?
          ExtensionRequirement.create_from_ext_vers(vers)
        end
      end.compact
    end
end

#description_htmlString

parse description field with asciidoctor, and return the HTML result

Returns:

  • (String)

    Parsed description in HTML



421
422
423
# File 'lib/udb/obj/csr.rb', line 421

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)



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/udb/obj/csr.rb', line 170

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 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
    cfg_arch.param_values["SXLEN"].nil? || cfg_arch.param_values["SXLEN"].size > 1
  when "VSXLEN"
    # dynamic if either we don't know VSXLEN or VSXLEN is explicitly mutable
    !cfg_arch.param_values.key?("VSXLEN") || cfg_arch.param_values["VSXLEN"].size > 1
  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") && \
      (cfg_arch.param_values["SXLEN"].nil? || cfg_arch.param_values["SXLEN"].size > 1)) && \
    (cfg_arch.possible_extensions.map(&:name).include?("H") && \
      (cfg_arch.param_values["VSXLEN"].nil? || cfg_arch.param_values["VSXLEN"].size > 1))
  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



713
714
715
# File 'lib/udb/obj/csr.rb', line 713

def exists_in_cfg?(cfg_arch)
  @exists_in_cfg ||= defined_by_condition.could_be_satisfied_by_cfg_arch?(cfg_arch)
end

#field(field_name) ⇒ Object

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



510
511
512
# File 'lib/udb/obj/csr.rb', line 510

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



505
506
507
# File 'lib/udb/obj/csr.rb', line 505

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



493
494
495
496
497
498
499
500
501
502
# File 'lib/udb/obj/csr.rb', line 493

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



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

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



488
489
490
# File 'lib/udb/obj/csr.rb', line 488

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



594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
# File 'lib/udb/obj/csr.rb', line 594

def fill_symtab(ast, effective_xlen)
  symtab = @cfg_arch.symtab.global_clone
  symtab.push(ast)
  # all CSR instructions are 32-bit
  if effective_xlen
    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)
  )
  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



122
123
124
125
126
# File 'lib/udb/obj/csr.rb', line 122

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



526
527
528
# File 'lib/udb/obj/csr.rb', line 526

def has_custom_sw_read?
  @data.key?("sw_read()") && !@data["sw_read()"].empty?
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



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

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

#indirect_addressInteger

Returns The indirect address.

Returns:

  • (Integer)

    The indirect address



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

def indirect_address
  @data["indirect_address"]
end

#indirect_slotInteger

Returns The indirect window slot.

Returns:

  • (Integer)

    The indirect window slot



61
62
63
# File 'lib/udb/obj/csr.rb', line 61

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)


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

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

    if !base.nil?
      base
    else
      # don't know MXLEN
      effective_xlen
    end
  when "SXLEN"
    if cfg_arch.param_values.key?("SXLEN")
      if cfg_arch.param_values["SXLEN"].size > 1
        effective_xlen
      else
        cfg_arch.param_values["SXLEN"][0]
      end
    elsif !base.nil?
      # if this CSR is only available in one base, then we know its length
      base
    else
      # don't know SXLEN
      effective_xlen
    end
  when "VSXLEN"
    if cfg_arch.param_values.key?("VSXLEN")
      if cfg_arch.param_values["VSXLEN"].size > 1
        effective_xlen
      else
        cfg_arch.param_values["VSXLEN"][0]
      end
    elsif !base.nil?
      # if this CSR is only available in one base, then we know its length
      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



337
338
339
340
341
342
343
344
345
346
347
348
349
350
# File 'lib/udb/obj/csr.rb', line 337

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



353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/udb/obj/csr.rb', line 353

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)


370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/udb/obj/csr.rb', line 370

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



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

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



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
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/udb/obj/csr.rb', line 267

def max_length
  return T.must(base) unless 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"].size > 1
        cfg_arch.param_values["SXLEN"].max
      else
        cfg_arch.param_values.fetch("SXLEN").fetch(0)
      end
    else
      64
    end
  when "VSXLEN"
    if cfg_arch.param_values.key?("VSXLEN")
      if cfg_arch.param_values["VSXLEN"].size > 1
        cfg_arch.param_values["VSXLEN"].max
      else
        cfg_arch.param_values["VSXLEN"][0]
      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.fetch("SXLEN").size > 1
          cfg_arch.param_values.fetch("SXLEN").max
        else
          cfg_arch.param_values.fetch("SXLEN").fetch(0)
        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"].size > 1
          cfg_arch.param_values["VSXLEN"].max
        else
          cfg_arch.param_values["VSXLEN"][0]
        end
      else
        # VSXLEN can never be greater than MXLEN or SXLEN
        if cfg_arch.param_values.key?("SXLEN")
          if cfg_arch.param_values.fetch("SXLEN").size > 1
            cfg_arch.param_values.fetch("SXLEN").max
          else
            cfg_arch.param_values.fetch("SXLEN").fetch(0)
          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



203
204
205
206
207
208
209
210
211
212
# File 'lib/udb/obj/csr.rb', line 203

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



401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# File 'lib/udb/obj/csr.rb', line 401

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



720
721
722
723
724
725
726
727
# File 'lib/udb/obj/csr.rb', line 720

def optional_in_cfg?(cfg_arch)
  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_cfg_arch?(cfg_arch) == SatisfiedResult::Maybe)
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



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

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)


456
457
458
459
460
461
462
463
464
465
# File 'lib/udb/obj/csr.rb', line 456

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’]



66
67
68
# File 'lib/udb/obj/csr.rb', line 66

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)


627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
# File 'lib/udb/obj/csr.rb', line 627

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, 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



131
132
133
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
160
161
162
163
164
165
166
# File 'lib/udb/obj/csr.rb', line 131

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

  @memo.reachable_functions[cache_key] = 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)


568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
# File 'lib/udb/obj/csr.rb', line 568

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) ⇒ Idl::FunctionBodyAst

Parameters:

  • effective_xlen (Integer, nil)

    32 or 64 for fixed xlen, nil for dynamic

Returns:

  • (Idl::FunctionBodyAst)


532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'lib/udb/obj/csr.rb', line 532

def type_checked_sw_read_ast(effective_xlen)
  @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? Also known as: reset_value

Returns:

  • (Integer, nil)


81
82
83
84
85
# File 'lib/udb/obj/csr.rb', line 81

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

  fields.reduce(0) { |val, f| val | (T.cast(f.reset_value, Integer) << 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



76
77
78
# File 'lib/udb/obj/csr.rb', line 76

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)


665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
# File 'lib/udb/obj/csr.rb', line 665

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



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

def writable
  @data["writable"]
end