Skip to content

Commit

Permalink
Fixed instructions and CSRs in #291 (CRDs list things like instructio…
Browse files Browse the repository at this point in the history
…ns, CSRs, and traps that aren't in the configuration). Still need to fix traps and interrupts.
  • Loading branch information
james-ball-qualcomm committed Jan 3, 2025
1 parent d990076 commit 924ffde
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 48 deletions.
30 changes: 13 additions & 17 deletions lib/arch_obj_models/csr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def defined_in_base64? = @data["base"].nil? || @data["base"] == 64
# @return [Boolean] true if this CSR is defined regardless of the effective XLEN
def defined_in_all_bases? = @data["base"].nil?

# @param design [Design] A configuration
# @param design [Design] The design
# @return [Boolean] Whether or not the format of this CSR changes when the effective XLEN changes in some mode
def format_changes_with_xlen?(design)
dynamic_length?(design) ||
Expand All @@ -55,7 +55,7 @@ def format_changes_with_xlen?(design)
end
end

# @param design [Design] A configuration
# @param design [Design] The design
# @return [Array<Idl::FunctionDefAst>] List of functions reachable from this CSR's sw_read or a field's sw_write function
def reachable_functions(design)
return @reachable_functions unless @reachable_functions.nil?
Expand Down Expand Up @@ -104,7 +104,7 @@ def reachable_functions_unevaluated(design)
@reachable_functions_unevaluated = fns.uniq
end

# @param design [Design] A configuration
# @param design [Design] The design
# @return [Boolean] Whether or not the length of the CSR depends on a runtime value
# (e.g., mstatus.SXL)
def dynamic_length?(design)
Expand Down Expand Up @@ -142,7 +142,7 @@ def min_length(design)
end
end

# @param design [Design] A configuration (can be nil if the lenth is not dependent on a config parameter)
# @param design [Design] The design (can be nil if the length is not dependent on a config parameter)
# @param effective_xlen [Integer] The effective xlen, needed since some fields change location with XLEN. If the field location is not determined by XLEN, then this parameter can be nil
# @return [Integer] Length, in bits, of the CSR, given effective_xlen
# @return [nil] if the length cannot be determined from the design (e.g., because SXLEN is unknown and +effective_xlen+ was not provided)
Expand Down Expand Up @@ -254,7 +254,7 @@ def length_cond64
end
end

# @param design [Design] A configuration
# @param design [Design] The design
# @return [String] Pretty-printed length string
def length_pretty(design, effective_xlen=nil)
if dynamic_length?(design)
Expand Down Expand Up @@ -306,7 +306,7 @@ def description_html
Asciidoctor.convert description
end

# @param design [Design] A configuration
# @param design [Design] The design
# @return [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
def implemented_fields_for(design, effective_xlen)
Expand All @@ -321,7 +321,7 @@ def implemented_fields_for(design, effective_xlen)
end
end

# @param design [Design] A configuration
# @param design [Design] The design
# @return [Array<CsrField>] All implemented fields for this CSR
# Excluded any fields that are defined by unimplemented extensions
def implemented_fields(design)
Expand Down Expand Up @@ -377,7 +377,7 @@ def field(field_name)
field_hash[field_name.to_s]
end

# @param design [Design] A configuration
# @param design [Design] The design
# @param effective_xlen [Integer] The effective XLEN to apply, needed when field locations change with XLEN in some mode
# @return [Idl::BitfieldType] A bitfield type that can represent all fields of the CSR
def bitfield_type(design, effective_xlen = nil)
Expand Down Expand Up @@ -425,7 +425,7 @@ def type_checked_sw_read_ast(symtab)
end

# @return [FunctionBodyAst] The abstract syntax tree of the sw_read() function
# @param design [Design] A configuration
# @param design [Design] The design
def sw_read_ast(symtab)
raise ArgumentError, "Argument should be a symtab" unless symtab.is_a?(Idl::SymbolTable)

Expand Down Expand Up @@ -493,7 +493,7 @@ def pruned_sw_read_ast(design)
# {bits: 12, name: 'imm12', attr: [''], type: 6}
# ]}
#
# @param design [Design] A configuration
# @param design [Design] The design
# @param effective_xlen [Integer,nil] Effective XLEN to use when CSR length is dynamic
# @param exclude_unimplemented [Boolean] If true, do not create include unimplemented fields in the figure
# @param optional_type [Integer] Wavedrom type (Fill color) for fields that are optional (not mandatory) in a partially-specified design
Expand Down Expand Up @@ -543,10 +543,10 @@ def wavedrom_desc(design, effective_xlen, exclude_unimplemented: false, optional
def exists_in_design?(design)
if design.fully_configured?
(@data["base"].nil? || (design.possible_xlens.include? @data["base"])) &&
design.transitive_implemented_ext_vers.any? { |e| defined_by?(e) }
design.transitive_implemented_ext_vers.any? { |ext_ver| defined_by?(ext_ver) }
else
(@data["base"].nil? || (design.possible_xlens.include? @data["base"])) &&
design.prohibited_ext_reqs.none? { |ext_req| ext_req.satisfying_versions.any? { |e| defined_by?(e) } }
design.prohibited_ext_reqs.none? { |ext_req| ext_req.satisfying_versions.any? { |ext_ver| defined_by?(ext_ver) } }
end
end

Expand All @@ -556,10 +556,6 @@ def optional_in_design?(design)
raise "optional_in_design? should only be used by a partially-specified arch def" unless design.partially_configured?

exists_in_design?(design) &&
design.mandatory_ext_reqs.all? do |ext_req|
ext_req.satisfying_versions.none? do |ext_ver|
defined_by?(ext_ver)
end
end
design.mandatory_ext_reqs.all? { |ext_req| ext_req.satisfying_versions.none? { |ext_ver| defined_by?(ext_ver) } }
end
end
15 changes: 5 additions & 10 deletions lib/arch_obj_models/csr_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@ def initialize(parent_csr, field_name, field_data)
@type_cache = {}
end

# @param possible_xlens [Array<Integer>] List of xlens that be used in any implemented mode
# @param extensions [Array<ExtensionVersion>] List of extensions implemented
# @return [Boolean] whether or not the instruction is implemented given the supplies config options
# @param design [Design] The design
# @return [Boolean] whether or not the instruction is implemented given the supplied design
def exists_in_design?(design)
if design.fully_configured?
parent.exists_in_design?(design) &&
Expand All @@ -54,11 +53,7 @@ def optional_in_design?(design)
if data["definedBy"].nil?
parent.optional_in_design?(design)
else
design.mandatory_ext_reqs.all? do |ext_req|
ext_req.satisfying_versions.none? do |ext_ver|
defined_by?(ext_ver)
end
end
design.mandatory_ext_reqs.all? { |ext_req| ext_req.satisfying_versions.none? { |ext_ver| defined_by?(ext_ver) } }
end
)
end
Expand Down Expand Up @@ -146,7 +141,7 @@ def pruned_type_ast(symtab)
@pruned_type_asts[symtab_hash] = ast
end

# returns the definitive type for a design
# Returns the definitive type for the design part of the symbol table.
#
# @param symtab [SymbolTable] Symbol table
# @return [String]
Expand Down Expand Up @@ -250,9 +245,9 @@ def alias
@alias
end

# @return [Array<Idl::FunctionDefAst>] List of functions called thorugh this field
# @param design [Design] The design
# @Param effective_xlen [Integer] 32 or 64; needed because fields can change in different XLENs
# @return [Array<Idl::FunctionDefAst>] List of functions called thorough this field
def reachable_functions(design, effective_xlen)
return @reachable_functions unless @reachable_functions.nil?

Expand Down
22 changes: 17 additions & 5 deletions lib/arch_obj_models/database_obj.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,23 @@ def keys = @data.keys
# @return (see Hash#key?)
def key?(k) = @data.key?(k)

# @param ext_ver [ExtensionVersion] Version of the extension
# @param design [Design] The backend design
# @return [Boolean] Whether or not the object is defined-by the given ExtensionVersion in the given Design.
def in_scope?(ext_ver, design)
raise ArgumentError, "Require an ExtensionVersion object but got a #{ext_ver.class} object" unless ext_ver.is_a?(ExtensionVersion)
raise ArgumentError, "Require a Design object but got a #{design.class} object" unless design.is_a?(Design)

defined_by?(ext_ver)
end

# @overload defined_by?(ext_name, ext_version)
# @param ext_name [#to_s] An extension name
# @param ext_version [#to_s] A specific extension version
# @return [Boolean] Whether or not the instruction is defined by extension `ext`, version `version`
# @return [Boolean] Whether or not the object is defined by extension `ext`, version `version`
# @overload defined_by?(ext_version)
# @param ext_version [ExtensionVersion] An extension version
# @return [Boolean] Whether or not the instruction is defined by ext_version
# @return [Boolean] Whether or not the object is defined by ext_version
def defined_by?(*args)
ext_ver =
if args.size == 1
Expand All @@ -228,7 +238,7 @@ def defined_by?(*args)
raise ArgumentError, "Unsupported number of arguments (#{args.size})"
end

defined_by_condition.satisfied_by? { |req| req.satisfied_by?(ext_ver) }
defined_by_condition.satisfied_by? { |ext_req| ext_req.satisfied_by?(ext_ver) }
end

# because of multiple ("allOf") conditions, we generally can't return a list of extension versions here....
Expand Down Expand Up @@ -564,7 +574,6 @@ def to_rb_helper(hsh)
# return a string that can be eval'd to determine if the objects in +ary_name+
# meet the Condition
#
# @param ary_name [String] Name of a ruby string in the eval binding
# @return [Boolean] If the condition is met
def to_rb
to_rb_helper(@hsh)
Expand Down Expand Up @@ -592,7 +601,10 @@ def satisfied_by?(&block)

raise ArgumentError, "Expecting one argument to block" unless block.arity == 1

eval to_rb
# Written to allow debug breakpoints on individual lines.
to_rb_expr = to_rb
ret = eval to_rb_expr
ret
end

def satisfying_ext_versions
Expand Down
28 changes: 28 additions & 0 deletions lib/arch_obj_models/extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,34 @@ def implemented_instructions
inst.defined_by?(self)
end
end

# @param design [Design] The design
# @return [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.
def in_scope_csrs(design)
raise ArgumentError, "Require a Design object but got a #{design.class} object" unless design.is_a?(Design)

return @in_scope_csrs unless @in_scope_csrs.nil?

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

# @param design [Design] The design
# @return [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.
def in_scope_instructions(design)
raise ArgumentError, "Require a Design object but got a #{design.class} object" unless design.is_a?(Design)

return @in_scope_instructions unless @in_scope_instructions.nil?

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

# Is the extension mandatory, optional, various kinds of optional, etc.
Expand Down
5 changes: 2 additions & 3 deletions lib/arch_obj_models/instruction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -743,8 +743,7 @@ def excluded_by?(*args)
#
# TODO: Does this function actually work for a partially configured design?
# It is calling DatabaseObject.defined_by? with ExtensionRequirement objects
# returned from Design.prohibited_ext_reqs() and Design.mandatory_ext_reqs()
# but only accepts an ExtensionVersion object.
# returned from Design.mandatory_ext_reqs() but only accepts an ExtensionVersion object.
def exists_in_design?(design)
if design.fully_configured?
(@data["base"].nil? || (design.possible_xlens.include?(@data["base"]))) &&
Expand All @@ -754,7 +753,7 @@ def exists_in_design?(design)
raise "unexpected design type" unless design.partially_configured?

(@data["base"].nil? || (design.possible_xlens.include?(@data["base"]))) &&
design.prohibited_ext_reqs.none? { |ext_req| defined_by?(ext_req) } &&
design.prohibited_ext_reqs.none? { |ext_req| ext_req.satisfying_versions.any? { |ext_ver| defined_by?(ext_ver) } }
design.mandatory_ext_reqs.none? { |ext_req| excluded_by?(ext_req) }
end
end
Expand Down
28 changes: 20 additions & 8 deletions lib/arch_obj_models/portfolio.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,30 +127,36 @@ def in_scope_extensions

end

# @param design [Design] The design
# @return [Array<Instruction>] Sorted list of all instructions associated with extensions listed as
# mandatory or optional in portfolio. Uses instructions provided by the
# minimum version of the extension that meets the extension requirement.
def in_scope_instructions
def in_scope_instructions(design)
raise ArgumentError, "Require a Design object but got a #{design.class} object" unless design.is_a?(Design)

return @in_scope_instructions unless @in_scope_instructions.nil?

@in_scope_instructions = []
portfolios.each do |portfolio|
@in_scope_instructions += portfolio.in_scope_instructions
@in_scope_instructions += portfolio.in_scope_instructions(design)
end

@in_scope_instructions =
@in_scope_instructions.uniq(&:name).sort_by(&:name)
end

# @param design [Design] The design
# @return [Array<Csr>] Unsorted list of all CSRs associated with extensions listed as
# mandatory or optional in portfolio. Uses CSRs provided by the
# minimum version of the extension that meets the extension requirement.
def in_scope_csrs
def in_scope_csrs(design)
raise ArgumentError, "Require a Design object but got a #{design.class} object" unless design.is_a?(Design)

return @in_scope_csrs unless @in_scope_csrs.nil?

@in_scope_csrs = []
portfolios.each do |portfolio|
@in_scope_csrs += portfolio.in_scope_csrs
@in_scope_csrs += portfolio.in_scope_csrs(design)
end

@in_scope_csrs.uniq(&:name)
Expand Down Expand Up @@ -349,24 +355,30 @@ def in_scope_min_satisfying_extension_versions
@in_scope_min_satisfying_extension_versions
end

# @param design [Design] The design
# @return [Array<Instruction>] Sorted list of all instructions associated with extensions listed as
# mandatory or optional in portfolio. Uses instructions provided by the
# minimum version of the extension that meets the extension requirement.
def in_scope_instructions
def in_scope_instructions(design)
raise ArgumentError, "Require a Design object but got a #{design.class} object" unless design.is_a?(Design)

return @in_scope_instructions unless @in_scope_instructions.nil?

@in_scope_instructions =
in_scope_min_satisfying_extension_versions.map {|ext_ver| ext_ver.implemented_instructions }.flatten.uniq.sort
in_scope_min_satisfying_extension_versions.map {|ext_ver| ext_ver.in_scope_instructions(design) }.flatten.uniq.sort
end

# @param design [Design] The design
# @return [Array<Csr>] Unsorted list of all CSRs associated with extensions listed as
# mandatory or optional in portfolio. Uses CSRs provided by the
# minimum version of the extension that meets the extension requirement.
def in_scope_csrs
def in_scope_csrs(design)
raise ArgumentError, "Require a Design object but got a #{design.class} object" unless design.is_a?(Design)

return @in_scope_csrs unless @in_scope_csrs.nil?

@in_scope_csrs =
in_scope_min_satisfying_extension_versions.map {|ext_ver| ext_ver.implemented_csrs }.flatten.uniq
in_scope_min_satisfying_extension_versions.map {|ext_ver| ext_ver.in_scope_csrs(design) }.flatten.uniq
end

# @return [Boolean] Does the profile differentiate between different types of optional.
Expand Down
3 changes: 0 additions & 3 deletions lib/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,4 @@ def implemented_extensions

def mandatory_extensions = raise "mandatory_extensions is only available for a PartialConfig"
def prohibited_extensions = raise "prohibited_extensions is only available for a PartialConfig"

# def prohibited_ext?(ext_name, cfg_arch) = !ext?(ext_name, cfg_arch)
# def ext?(ext_name, cfg_arch) = implemented_extensions(cfg_arch).any? { |e| e.name == ext_name.to_s }
end
6 changes: 4 additions & 2 deletions lib/portfolio_design.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,14 @@ def in_scope_ext_reqs = @portfolio_grp.in_scope_ext_reqs
# @return [Array<Instruction>] Sorted list of all instructions associated with extensions listed as
# mandatory or optional in portfolio. Uses instructions provided by the
# minimum version of the extension that meets the extension requirement.
def in_scope_instructions = @portfolio_grp.in_scope_instructions
# Factors in things like XLEN in design.
def in_scope_instructions = @portfolio_grp.in_scope_instructions(self)

# @return [Array<Csr>] Unsorted list of all CSRs associated with extensions listed as
# mandatory or optional in portfolio. Uses CSRs provided by the
# minimum version of the extension that meets the extension requirement.
def in_scope_csrs = @portfolio_grp.in_scope_csrs
# Factors in things like XLEN in design.
def in_scope_csrs = @portfolio_grp.in_scope_csrs(self)

# @return [String] Given an extension +ext_name+, return the presence as a string.
# Returns the greatest presence string across all portfolios in this design.
Expand Down

0 comments on commit 924ffde

Please sign in to comment.