Class: Udb::ExtensionVersion

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/udb/obj/extension.rb,
lib/udb/req_expression.rb

Overview

sorbet needs a forward declration

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, version_str, arch, fail_if_version_does_not_exist: false)

Parameters:

  • version (String)

    The version specifier

  • name (String)

    The extension name

  • version_str (String)
  • arch (ConfiguredArchitecture)

    The architecture definition

  • fail_if_version_does_not_exist (Boolean) (defaults to: false)


246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/udb/obj/extension.rb', line 246

def initialize(name, version_str, arch, fail_if_version_does_not_exist: false)
  @name = name
  @version_str = version_str
  @version_spec = VersionSpec.new(version_str)

  @arch = arch

  @ext = @arch.extension(@name)
  raise "Extension #{name} not found in architecture" if @ext.nil?

  @data = @ext.data["versions"].find { |v| VersionSpec.new(v["version"]) == @version_spec }

  if fail_if_version_does_not_exist && @data.nil?
    raise ArgumentError, "Version #{version_str} of #{@name} extension is not defined"
  elsif @data.nil?
    warn "Version #{version_str} of #{@name} extension is not defined"
  end
end

Instance Attribute Details

#archConfiguredArchitecture (readonly)



240
241
242
# File 'lib/udb/obj/extension.rb', line 240

def arch
  @arch
end

#extExtension (readonly)

Returns Extension.

Returns:



229
230
231
# File 'lib/udb/obj/extension.rb', line 229

def ext
  @ext
end

#nameString (readonly)

Returns Name of the extension.

Returns:

  • (String)

    Name of the extension



225
226
227
# File 'lib/udb/obj/extension.rb', line 225

def name
  @name
end

#version_specVersionSpec (readonly)

Returns:



233
234
235
# File 'lib/udb/obj/extension.rb', line 233

def version_spec
  @version_spec
end

#version_strString (readonly)

Returns:

  • (String)


237
238
239
# File 'lib/udb/obj/extension.rb', line 237

def version_str
  @version_str
end

Class Method Details

.to_ext_req(ext_vers) ⇒ ExtensionRequirement

given a set of extension versions from the same extension, return the minimal set of extension requirements that would cover then all

Parameters:

Returns:



268
269
270
271
272
273
274
275
276
277
278
# File 'lib/udb/obj/extension.rb', line 268

def self.to_ext_req(ext_vers)
  raise "ext_vers cannot be empty" if ext_vers.empty?
  raise "All ext_vers must be of the same extension" unless ext_vers.all? { |ev| ev.name == ext_vers.fetch(0).name }

  sorted = ext_vers.sort
  unless T.must(sorted.min).compatible?(sorted.max)
    raise "Impossible to combine because the set contains incompatible versions"
  end

  ExtensionRequirement.new(ext_vers.fetch(0).name, "~> #{T.must(sorted.min).version_str}", arch: ext_vers.fetch(0).arch)
end

Instance Method Details

#<=>(other) ⇒ Object

sorts extension by name, then by version



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

def <=>(other)
  unless other.is_a?(ExtensionVersion)
    raise ArgumentError, "ExtensionVersions are only comparable to other extension versions"
  end

  if other.name != @name
    @name <=> other.name
  else
    @version_spec <=> other.version_spec
  end
end

#==(other) ⇒ Boolean

Returns whether or not this ExtensionVersion has the exact same name and version as other.

Parameters:

Returns:

  • (Boolean)

    whether or not this ExtensionVersion has the exact same name and version as other



316
317
318
# File 'lib/udb/obj/extension.rb', line 316

def ==(other)
  eql?(other)
end

#breaking?Boolean

Returns Whether or not this is a breaking version (i.e., incompatible with all prior versions).

Returns:

  • (Boolean)

    Whether or not this is a breaking version (i.e., incompatible with all prior versions)



299
300
301
# File 'lib/udb/obj/extension.rb', line 299

def breaking?
  !@data["breaking"].nil?
end

#canonical_versionString

Returns Canonical version string.

Returns:

  • (String)

    Canonical version string



304
# File 'lib/udb/obj/extension.rb', line 304

def canonical_version = @version_spec.canonical

#changesObject



325
# File 'lib/udb/obj/extension.rb', line 325

def changes = @data["changes"].nil? ? [] : @data["changes"]

#compatible?(other) ⇒ Boolean

Returns Whether or not other is compatible with self.

Parameters:

Returns:

  • (Boolean)

    Whether or not other is compatible with self



296
# File 'lib/udb/obj/extension.rb', line 296

def compatible?(other) = compatible_versions.include?(other)

#compatible_versionsArray<ExtensionVersions>

Returns List of known ExtensionVersions that are compatible with this ExtensionVersion (i.e., have larger version number and are not breaking).

Returns:

  • (Array<ExtensionVersions>)

    List of known ExtensionVersions that are compatible with this ExtensionVersion (i.e., have larger version number and are not breaking)



281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/udb/obj/extension.rb', line 281

def compatible_versions
  return @compatible_versions unless @compatible_versions.nil?

  @compatible_versions = []
  @ext.versions.each do |v|
    @compatible_versions << v if v.version_spec >= @version_spec
    break if @compatible_versions.size.positive? && v.breaking?
  end
  raise "Didn't even find self?" if compatible_versions.empty?

  @compatible_versions
end

#conflicts_conditionAbstractRequirement

Returns List of extensions that conflict with this ExtensionVersion The list is not transitive; if conflict C1 implies C2, only C1 shows up in the list.

Returns:

  • (AbstractRequirement)

    List of extensions that conflict with this ExtensionVersion The list is not transitive; if conflict C1 implies C2, only C1 shows up in the list



387
388
389
# File 'lib/udb/obj/extension.rb', line 387

def conflicts_condition
  ext.conflicts_condition
end

#contributorsArray<Person>

Returns List of contributors to this extension version.

Returns:

  • (Array<Person>)

    List of contributors to this extension version



330
331
332
333
334
335
336
337
338
# File 'lib/udb/obj/extension.rb', line 330

def contributors
  return @contributors unless @contributors.nil?

  @contributors = []
  @data["contributors"]&.each do |c|
    @contributors << Person.new(c)
  end
  @contributors
end

#eql?(other) ⇒ Boolean

Returns whether or not this ExtensionVersion has the exact same name and version as other.

Parameters:

Returns:

  • (Boolean)

    whether or not this ExtensionVersion has the exact same name and version as other



308
309
310
311
312
# File 'lib/udb/obj/extension.rb', line 308

def eql?(other)
  raise "ExtensionVersion is not comparable to #{other.class}" unless other.is_a?(ExtensionVersion)

  @ext.name == other.ext.name && @version_spec.eql?(other.version_spec)
end

#exception_codesArray<ExceptionCode>

Returns:



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
525
526
527
# File 'lib/udb/obj/extension.rb', line 498

def exception_codes
  @exception_codes ||=
    if @data.key?("exception_codes")
      ecodes = []

      d = T.cast(@data["exception_codes"], T::Array[T::Hash[String, T.any(Integer, String)]])
      d.each do |edata|
        if ecodes.any? { |e| e.num == edata["num"] || e.name == edata["name"] || e.var == edata["var"] }
          raise "Duplicate exception code"
        end

        cond = T.let(T.cast(edata["when"], T::Hash[String, String]), T.nilable(T::Hash[String, String]))
        unless cond.nil? || cond["version"].nil?
          # check version
          next unless ExtensionRequirement.new(name, T.must(cond["version"]), arch: @cfg_arch).satisfied_by?(self)
        end
        ecodes <<
          ExceptionCode.new(
            T.cast(edata["name"], String),
            T.cast(edata["var"], String),
            T.cast(edata["num"], Integer),
            ext
          )
      end

      ecodes
    else
      []
    end
end

#implemented_csrsArray<Csr>

Returns the list of CSRs implemented by this extension version (may be empty).

Returns:

  • (Array<Csr>)

    the list of CSRs implemented by this extension version (may be empty)



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

def implemented_csrs
  return @implemented_csrs unless @implemented_csrs.nil?

  raise "implemented_csrs needs an cfg_arch" if @cfg_arch.nil?

  @implemented_csrs = @cfg_arch.csrs.select do |csr|
    csr.defined_by_condition.possibly_satisfied_by?(self)
  end
end

#implemented_instructionsArray<Csr>

Returns the list of insts implemented by this extension version (may be empty).

Returns:

  • (Array<Csr>)

    the list of insts implemented by this extension version (may be empty)



487
488
489
490
491
492
493
494
495
# File 'lib/udb/obj/extension.rb', line 487

def implemented_instructions
  return @implemented_instructions unless @implemented_instructions.nil?

  raise "implemented_instructions needs an cfg_arch" if @cfg_arch.nil?

  @implemented_instructions = @cfg_arch.instructions.select do |inst|
    inst.defined_by_condition.possibly_satisfied_by?(self)
  end
end

#implicationsConditionalExtensionVersionList

Returns array of ExtensionVersions implied by this ExtensionVersion, along with a condition under which it is in the list (which may be an AlwaysTrueExtensionRequirementExpression)

Examples:

ext_ver.implications #=> { :ext_ver => ExtensionVersion.new(:A, "2.1.0"), :cond => ExtensionRequirementExpression.new(...) }

Returns:

  • (ConditionalExtensionVersionList)

    List of extension versions that this ExtensionVersion implies This list is not transitive; if an implication I1 implies another extension I2, only I1 shows up in the list



402
403
404
405
406
# File 'lib/udb/obj/extension.rb', line 402

def implications
  return ConditionalExtensionVersionList.new([], @arch) if @data["implies"].nil?

  ConditionalExtensionVersionList.new(@data["implies"], @arch)
end

#implied_byArray<ExtensionVersion>

Note that the list returned could include extension versions that conditionally imply this extension version For example, Zcd.implied_by will return C, even though C only implies Zcd if D is also implemented

Returns:

  • (Array<ExtensionVersion>)

    List of extension versions that might imply this ExtensionVersion



413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/udb/obj/extension.rb', line 413

def implied_by
  return @implied_by unless @implied_by.nil?

  @implied_by = []
  @arch.extensions.each do |ext|
    next if ext.name == name

    ext.versions.each do |ext_ver|
      ext_ver.implications.each do |implication|
        @implied_by << ext_ver if implication.ext_ver == self && implication.cond.could_be_true?(@arch)
      end
    end
  end
  @implied_by
end

#implied_by_with_conditionArray<Hash{Symbol => ExtensionVersion, ExtensionRequirementExpression>] List of extension versions that might imply this ExtensionVersion, along with the condition under which it applies

Returns Array<Hash{Symbol => ExtensionVersion, ExtensionRequirementExpression>] List of extension versions that might imply this ExtensionVersion, along with the condition under which it applies.

Examples:

zcd_ext_ver.implied_by_with_condition #=> [{ ext_ver: "C 1.0", cond: "D ~> 1.0"}]
zba_ext_ver.implied_by_with_condition #=> [{ ext_ver: "B 1.0", cond: AlwaysTrueExtensionRequirementExpression}]

Returns:

  • (Array<Hash{Symbol => ExtensionVersion, ExtensionRequirementExpression>] List of extension versions that might imply this ExtensionVersion, along with the condition under which it applies)

    Array<Hash{Symbol => ExtensionVersion, ExtensionRequirementExpression>] List of extension versions that might imply this ExtensionVersion, along with the condition under which it applies



437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/udb/obj/extension.rb', line 437

def implied_by_with_condition
  return @implied_by_with_condition unless @implied_by_with_condition.nil?

  @implied_by_with_condition = []
  @arch.extensions.each do |ext|
    next if ext.name == name

    ext.versions.each do |ext_ver|
      raise "????" if ext_ver.arch.nil?
      ext_ver.implications.each do |implication|
        @implied_by_with_condition << { ext_ver: ext_ver, cond: implication.cond } if implication.ext_ver == self
      end
    end
  end
  @implied_by_with_condition
end

#in_scope_csrs(design) ⇒ Array<Csr>

Returns List of CSRs in-scope for this design for this extension version (may be empty). Factors in effect of design’s xlen in the appropriate mode for the CSR.

Parameters:

  • design (Design)

    The design

Returns:

  • (Array<Csr>)

    List of CSRs in-scope for this design for this extension version (may be empty). Factors in effect of design’s xlen in the appropriate mode for the CSR.

Raises:

  • (ArgumentError)


564
565
566
567
568
569
570
571
572
573
# File 'lib/udb/obj/extension.rb', line 564

def in_scope_csrs(design)
  raise ArgumentError, "Require an PortfolioDesign object but got a #{design.class} object" unless design.is_a?(PortfolioDesign)

  return @in_scope_csrs unless @in_scope_csrs.nil?

  @in_scope_csrs = @arch.csrs.select do |csr|
    csr.defined_by_condition.possibly_satisfied_by?(self) &&
    (csr.base.nil? || (design.possible_xlens.include?(csr.base)))
  end
end

#in_scope_instructions(design) ⇒ Array<Instruction>

Returns List of instructions in-scope for this design for this extension version (may be empty). Factors in effect of design’s xlen in the appropriate mode for the instruction.

Parameters:

  • design (Design)

    The design

Returns:

  • (Array<Instruction>)

    List of instructions in-scope for this design for this extension version (may be empty). Factors in effect of design’s xlen in the appropriate mode for the instruction.

Raises:

  • (ArgumentError)


578
579
580
581
582
583
584
585
586
587
# File 'lib/udb/obj/extension.rb', line 578

def in_scope_instructions(design)
  raise ArgumentError, "Require an PortfolioDesign object but got a #{design.class} object" unless design.is_a?(PortfolioDesign)

  return @in_scope_instructions unless @in_scope_instructions.nil?

  @in_scope_instructions = @arch.instructions.select do |inst|
    inst.defined_by_condition.possibly_satisfied_by?(self) &&
    (inst.base.nil? || (design.possible_xlens.include?(inst.base)))
  end
end

#interrupt_codesArray<InterruptCode>

Returns:



530
531
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
# File 'lib/udb/obj/extension.rb', line 530

def interrupt_codes
  @interrupt_codes ||=
    if @data.key?("interrupt_codes")
      ecodes = []

      d = T.cast(@data["interrupt_codes"], T::Array[T::Hash[String, T.any(Integer, String)]])
      d.each do |edata|
        if ecodes.any? { |e| e.num == edata["num"] || e.name == edata["name"] || e.var == edata["var"] }
          raise "Duplicate interrupt code"
        end

        cond = T.let(T.cast(edata["when"], T::Hash[String, String]), T.nilable(T::Hash[String, String]))
        unless cond.nil? || cond["version"].nil?
          # check version
          next unless ExtensionRequirement.new(name, T.must(cond["version"]), arch: @cfg_arch).satisfied_by?(self)
        end
        ecodes <<
          InterruptCode.new(
            T.cast(edata["name"], String),
            T.cast(edata["var"], String),
            T.cast(edata["num"], Integer),
            ext
          )
      end

      ecodes
    else
      []
    end
end

#paramsArray<Parameter>

Returns The list of parameters for this extension version.

Returns:

  • (Array<Parameter>)

    The list of parameters for this extension version



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

def params
  @ext.params.select do |p|
    p.when.satisfied_by? do |ext_req|
      if ext_req.name == name
        ext_req.satisfied_by?(self)
      else
        @arch.possible_extension_versions.any? { |poss_ext_ver| ext_req.satisfied_by?(poss_ext_ver) }
      end
    end
  end
end

#ratification_dateObject



323
# File 'lib/udb/obj/extension.rb', line 323

def ratification_date = @data["ratification_date"]

#requirement_conditionExtensionRequirementExpression

Returns Condition that must be met for this version to be allowed.

Returns:



368
369
370
371
372
373
374
375
376
377
378
379
380
381
# File 'lib/udb/obj/extension.rb', line 368

def requirement_condition
  @requirement_condition ||=
    begin
      r = case @data["requires"]
          when nil
            AlwaysTrueExtensionRequirementExpression.new
          when Hash
            ExtensionRequirementExpression.new(@data["requires"], @arch)
          else
            ExtensionRequirementExpression.new({ "oneOf" => [@data["requires"]] }, @arch)
          end
      r
    end
end

#stateString

Returns The state of the extension version (‘ratified’, ‘developemnt’, etc).

Returns:

  • (String)

    The state of the extension version (‘ratified’, ‘developemnt’, etc)



321
# File 'lib/udb/obj/extension.rb', line 321

def state = @data["state"]

#to_ext_reqExtensionRequirement



590
591
592
# File 'lib/udb/obj/extension.rb', line 590

def to_ext_req
  ExtensionRequirement.new(name, "= #{version_str}", arch: @arch)
end

#to_rvi_sString

Returns formatted like the RVI manual.

Examples:

ExtensionVersion.new("A", "2.2").to_rvi_s #=> "A2p2"

Returns:

  • (String)

    formatted like the RVI manual



358
359
360
# File 'lib/udb/obj/extension.rb', line 358

def to_rvi_s
  "#{name}#{@version_spec.to_rvi_s}"
end

#to_sString

Returns Ext@Version.

Returns:

  • (String)

    Ext@Version



363
364
365
# File 'lib/udb/obj/extension.rb', line 363

def to_s
  "#{name}@#{@version_spec.canonical}"
end

#urlObject



327
# File 'lib/udb/obj/extension.rb', line 327

def url = @data["url"]