Skip to content

Commit 899c3a1

Browse files
committed
Add type annotations to csr_field.rb
1 parent c77a9b4 commit 899c3a1

File tree

1 file changed

+54
-28
lines changed

1 file changed

+54
-28
lines changed

lib/arch_obj_models/csr_field.rb

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class CsrField < DatabaseObject
1212
extend T::Sig;
1313

1414
# @return [Csr] The Csr that defines this field
15+
sig { returns(Csr) }
1516
attr_reader :parent
1617

1718
# @!attribute field
@@ -22,12 +23,14 @@ class CsrField < DatabaseObject
2223

2324
# @return [Integer] The base XLEN required for this CsrField to exist. One of [32, 64]
2425
# @return [nil] if the CsrField exists in any XLEN
26+
sig { returns(T.nilable(Integer)) }
2527
def base
2628
@data["base"]
2729
end
2830

2931
# @param parent_csr [Csr] The Csr that defined this field
3032
# @param field_data [Hash<String,Object>] Field data from the arch spec
33+
sig { params(parent_csr: Csr, field_name: String, field_data: T::Hash[String, T.untyped]).void }
3134
def initialize(parent_csr, field_name, field_data)
3235
super(field_data, parent_csr.data_path, arch: parent_csr.arch)
3336
@name = field_name
@@ -38,6 +41,7 @@ def initialize(parent_csr, field_name, field_data)
3841
# For a partial config, whether or the it is possible for the field to be implemented
3942
#
4043
# @return [Boolean] True if this field might exist in a config
44+
sig { params(cfg_arch: ConfiguredArchitecture).returns(T::Boolean) }
4145
def exists_in_cfg?(cfg_arch)
4246
if cfg_arch.fully_configured?
4347
parent.exists_in_cfg?(cfg_arch) &&
@@ -53,6 +57,7 @@ def exists_in_cfg?(cfg_arch)
5357
end
5458

5559
# @return [Boolean] For a partially configured cfg_arch, whether or not the field is optional (not mandatory or prohibited)
60+
sig { params(cfg_arch: ConfiguredArchitecture).returns(T::Boolean) }
5661
def optional_in_cfg?(cfg_arch)
5762
raise "optional_in_cfg? should only be called on a partially configured cfg_arch" unless cfg_arch.partially_configured?
5863

@@ -71,18 +76,22 @@ def optional_in_cfg?(cfg_arch)
7176
# @return [Boolean] Whether or not the presence of ext_ver affects this CSR Field definition
7277
# This does not take the parent CSR into account, i.e., a field can be unaffected
7378
# by ext_ver even if the parent CSR is affected
79+
sig { params(ext_ver: ExtensionVersion).returns(T::Boolean) }
7480
def affected_by?(ext_ver)
7581
@data["definedBy"].nil? ? false : defined_by_condition.possibly_satisfied_by?(ext_ver)
7682
end
7783

7884
# @return [Idl::FunctionBodyAst] Abstract syntax tree of the type() function
7985
# @return [nil] if the type property is not a function
86+
sig { returns(T.nilable(Idl::FunctionBodyAst)) }
8087
def type_ast
8188
return @type_ast unless @type_ast.nil?
8289
return nil if @data["type()"].nil?
8390

91+
idl_code = T.must(@data["type()"])
92+
8493
@type_ast = @cfg_arch.idl_compiler.compile_func_body(
85-
@data["type()"],
94+
idl_code,
8695
name: "CSR[#{csr.name}].#{name}.type()",
8796
input_file: csr.__source,
8897
input_line: csr.source_line("fields", name, "type()"),
@@ -100,6 +109,7 @@ def type_ast
100109
# @return [Idl::FunctionBodyAst] Abstract syntax tree of the type() function, after it has been type checked
101110
# @return [nil] if the type property is not a function
102111
# @param effective_xlen [32, 64] The effective xlen to evaluate for
112+
sig { params(effective_xlen: T.nilable(Integer)).returns(T.nilable(Idl::FunctionBodyAst)) }
103113
def type_checked_type_ast(effective_xlen)
104114
@type_checked_type_ast ||= { 32 => nil, 64 => nil }
105115
return @type_checked_type_ast[effective_xlen] unless @type_checked_type_ast[effective_xlen].nil?
@@ -128,6 +138,7 @@ def type_checked_type_ast(effective_xlen)
128138
# @return [Idl::FunctionBodyAst] Abstract syntax tree of the type() function, after it has been type checked and pruned
129139
# @return [nil] if the type property is not a function
130140
# @param effective_xlen [32, 64] The effective xlen to evaluate for
141+
sig { params(effective_xlen: T.nilable(Integer)).returns(T.nilable(Idl::FunctionBodyAst)) }
131142
def pruned_type_ast(effective_xlen)
132143
@pruned_type_ast ||= { 32 => nil, 64 => nil }
133144
return @pruned_type_ast[effective_xlen] unless @pruned_type_ast[effective_xlen].nil?
@@ -169,6 +180,7 @@ def pruned_type_ast(effective_xlen)
169180
# 'RW-R' => Read-write, with a restricted set of legal values
170181
# 'RW-H' => Read-write, with a hardware update
171182
# 'RW-RH' => Read-write, with a hardware update and a restricted set of legal values
183+
sig { params(effective_xlen: T.nilable(Integer)).returns(String) }
172184
def type(effective_xlen = nil)
173185
@type ||= { 32 => nil, 64 => nil }
174186
return @type[effective_xlen] unless @type[effective_xlen].nil?
@@ -179,11 +191,8 @@ def type(effective_xlen = nil)
179191
@data["type"]
180192
else
181193
# the type is config-specific...
182-
idl = @data["type()"]
183-
raise "type() is nil for #{csr.name}.#{name} #{@data}?" if idl.nil?
184194

185-
# value_result = Idl::AstNode.value_try do
186-
ast = type_checked_type_ast(effective_xlen)
195+
ast = T.must(type_checked_type_ast(effective_xlen))
187196
begin
188197
symtab = fill_symtab_for_type(effective_xlen, ast)
189198

@@ -209,8 +218,8 @@ def type(effective_xlen = nil)
209218
type = nil
210219
end
211220
ensure
212-
symtab.pop
213-
symtab.release
221+
symtab.pop unless symtab.nil?
222+
symtab.release unless symtab.nil?
214223
end
215224
type
216225
# end
@@ -226,21 +235,21 @@ def type(effective_xlen = nil)
226235

227236
# @return [String] A pretty-printed type string
228237
# @param effective_xlen [32, 64] The effective xlen to evaluate for
238+
sig { params(effective_xlen: T.nilable(Integer)).returns(String) }
229239
def type_pretty(effective_xlen = nil)
230-
raise ArgumentError, "Expecting Integer" unless effective_xlen.nil? || effective_xlen.is_a?(Integer)
231-
232240
str = T.let(nil, T.nilable(String))
233241
value_result = Idl::AstNode.value_try do
234242
str = type(effective_xlen)
235243
end
236244
Idl::AstNode.value_else(value_result) do
237-
ast = type_ast
245+
ast = T.must(type_ast)
238246
str = ast.gen_option_adoc
239247
end
240-
str
248+
T.must(str)
241249
end
242250

243251
# @return [Alias,nil] The aliased field, or nil if there is no alias
252+
sig { returns(T.nilable(Alias)) }
244253
def alias
245254
return @alias unless @alias.nil?
246255

@@ -270,6 +279,7 @@ def alias
270279
# @return [Array<Idl::FunctionDefAst>] List of functions called through this field
271280
# @param cfg_arch [ConfiguredArchitecture] a configuration
272281
# @Param effective_xlen [Integer] 32 or 64; needed because fields can change in different XLENs
282+
sig { params(effective_xlen: T.nilable(Integer)).returns(T::Array[Idl::FunctionDefAst]) }
273283
def reachable_functions(effective_xlen)
274284
return @reachable_functions unless @reachable_functions.nil?
275285

@@ -307,6 +317,7 @@ def reachable_functions(effective_xlen)
307317

308318
# @return [Boolean] Whether or not the location of the field changes dynamically
309319
# (e.g., based on mstatus.SXL) in the configuration
320+
sig { returns(T::Boolean) }
310321
def dynamic_location?
311322
# if there is no location_rv32, the the field never changes
312323
return false unless @data["location"].nil?
@@ -317,6 +328,7 @@ def dynamic_location?
317328

318329
# @return [Idl::FunctionBodyAst] Abstract syntax tree of the reset_value function
319330
# @return [nil] If the reset_value is not a function
331+
sig { returns(T.nilable(Idl::FunctionBodyAst)) }
320332
def reset_value_ast
321333
return @reset_value_ast unless @reset_value_ast.nil?
322334
return nil unless @data.key?("reset_value()")
@@ -332,9 +344,9 @@ def reset_value_ast
332344
)
333345
end
334346

335-
# @param symtab [Idl::SymbolTable] A symbol table with globals
336347
# @return [Idl::FunctionBodyAst] Abstract syntax tree of the reset_value function, after being type checked
337348
# @return [nil] If the reset_value is not a function
349+
sig { returns(T.nilable(Idl::FunctionBodyAst)) }
338350
def type_checked_reset_value_ast
339351
return @type_checked_reset_value_ast unless @type_checked_reset_value_ast.nil?
340352

@@ -355,12 +367,13 @@ def type_checked_reset_value_ast
355367

356368
# @return [Idl::FunctionBodyAst] Abstract syntax tree of the reset_value function, type checked and pruned
357369
# @return [nil] If the reset_value is not a function
370+
sig { returns(T.nilable(Idl::FunctionBodyAst)) }
358371
def pruned_reset_value_ast
359372
return @pruned_reset_value_ast unless @pruned_reset_value_ast.nil?
360373

361374
return nil unless @data.key?("reset_value()")
362375

363-
ast = type_checked_reset_value_ast
376+
ast = T.must(type_checked_reset_value_ast)
364377

365378
symtab = fill_symtab_for_reset(ast)
366379
ast = ast.prune(symtab)
@@ -378,7 +391,7 @@ def reset_value
378391
if @data.key?("reset_value")
379392
@data["reset_value"]
380393
else
381-
ast = pruned_reset_value_ast
394+
ast = T.must(pruned_reset_value_ast)
382395
symtab = fill_symtab_for_reset(ast)
383396
val = T.let(nil, T.untyped)
384397
value_result = Idl::AstNode.value_try do
@@ -394,6 +407,7 @@ def reset_value
394407
end
395408
end
396409

410+
sig { returns(T::Boolean) }
397411
def dynamic_reset_value?
398412
return false unless @data["reset_value"].nil?
399413

@@ -403,32 +417,29 @@ def dynamic_reset_value?
403417
end || true
404418
end
405419

420+
sig { returns(String) }
406421
def reset_value_pretty
407422
str = T.let(nil, T.nilable(String))
408423
value_result = Idl::AstNode.value_try do
409424
str = reset_value
410425
end
411426
Idl::AstNode.value_else(value_result) do
412-
ast = reset_value_ast
427+
ast = T.must(reset_value_ast)
413428
str = ast.gen_option_adoc
414429
end
415-
str
416-
end
417-
418-
# @return [Boolean] true if the field could have an undefined value at any point
419-
def could_be_undefined?
420-
(reset_value == "UNDEFINED_LEGAL") || \
421-
(has_custom_sw_write? && sw_write_ast(cfg_arch.symtab).could_return_undefined?(cfg_arch.symtab))
430+
T.must(str)
422431
end
423432

424433
# @return [Boolean] true if the CSR field has a custom sw_write function
434+
sig { returns(T::Boolean) }
425435
def has_custom_sw_write?
426436
@data.key?("sw_write(csr_value)") && !@data["sw_write(csr_value)"].empty?
427437
end
428438

429439
# @return [FunctionBodyAst] The abstract syntax tree of the sw_write() function, after being type checked
430440
# @param effective_xlen [Integer] 32 or 64; the effective XLEN to evaluate this field in (relevant when fields move in different XLENs)
431441
# @param symtab [Idl::SymbolTable] Symbol table with globals
442+
sig { params(symtab: Idl::SymbolTable, effective_xlen: T.nilable(Integer)).returns(T.nilable(Idl::FunctionBodyAst)) }
432443
def type_checked_sw_write_ast(symtab, effective_xlen)
433444
@type_checked_sw_write_asts ||= {}
434445
ast = @type_checked_sw_write_asts[symtab.hash]
@@ -453,7 +464,7 @@ def type_checked_sw_write_ast(symtab, effective_xlen)
453464
Idl::Var.new("csr_value", csr.bitfield_type(symtab.cfg_arch, effective_xlen))
454465
)
455466

456-
ast = sw_write_ast(symtab)
467+
ast = T.must(sw_write_ast(symtab))
457468
symtab.cfg_arch.idl_compiler.type_check(
458469
ast,
459470
symtab,
@@ -466,10 +477,9 @@ def type_checked_sw_write_ast(symtab, effective_xlen)
466477

467478
# @return [Idl::FunctionBodyAst] The abstract syntax tree of the sw_write() function
468479
# @return [nil] If there is no sw_write() function
469-
# @param cfg_arch [ConfiguredArchitecture] An architecture definition
480+
# @param symtab [Idl::SymbolTable] Symbols
481+
sig { params(symtab: Idl::SymbolTable).returns(T.nilable(Idl::FunctionBodyAst)) }
470482
def sw_write_ast(symtab)
471-
raise ArgumentError, "Argument should be a symtab" unless symtab.is_a?(Idl::SymbolTable)
472-
473483
return @sw_write_ast unless @sw_write_ast.nil?
474484
return nil if @data["sw_write(csr_value)"].nil?
475485

@@ -489,6 +499,7 @@ def sw_write_ast(symtab)
489499
@sw_write_ast
490500
end
491501

502+
sig { params(effective_xlen: T.nilable(Integer), ast: Idl::AstNode).returns(Idl::SymbolTable) }
492503
def fill_symtab_for_sw_write(effective_xlen, ast)
493504
symtab = cfg_arch.symtab.global_clone
494505
symtab.push(ast)
@@ -520,6 +531,7 @@ def fill_symtab_for_sw_write(effective_xlen, ast)
520531
symtab
521532
end
522533

534+
sig { params(effective_xlen: T.nilable(Integer), ast: Idl::AstNode).returns(Idl::SymbolTable) }
523535
def fill_symtab_for_type(effective_xlen, ast)
524536
symtab = cfg_arch.symtab.global_clone
525537
symtab.push(ast)
@@ -571,7 +583,7 @@ def pruned_sw_write_ast(effective_xlen)
571583

572584
return nil unless @data.key?("sw_write(csr_value)")
573585

574-
ast = type_checked_sw_write_ast(cfg_arch.symtab, effective_xlen)
586+
ast = T.must(type_checked_sw_write_ast(cfg_arch.symtab, effective_xlen))
575587

576588
return ast if cfg_arch.unconfigured?
577589

@@ -644,24 +656,34 @@ def location(effective_xlen = nil)
644656
end
645657

646658
# @return [Boolean] Whether or not this field only exists when XLEN == 64
659+
sig { returns(T::Boolean) }
647660
def base64_only? = @data.key?("base") && @data["base"] == 64
648661

649662
# @return [Boolean] Whether or not this field only exists when XLEN == 32
663+
sig { returns(T::Boolean) }
650664
def base32_only? = @data.key?("base") && @data["base"] == 32
651665

666+
sig { returns(T::Boolean) }
652667
def defined_in_base32? = @data["base"].nil? || @data["base"] == 32
668+
669+
sig { returns(T::Boolean) }
653670
def defined_in_base64? = @data["base"].nil? || @data["base"] == 64
671+
672+
sig { params(xlen: Integer).returns(T::Boolean) }
654673
def defined_in_base?(xlen) = @data["base"].nil? || @data["base"] == xlen
655674

656675
# @return [Boolean] Whether or not this field exists for any XLEN
676+
sig { returns(T::Boolean) }
657677
def defined_in_all_bases? = @data["base"].nil?
658678

659679
# @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
660680
# @return [Integer] Number of bits in the field
681+
sig { params(effective_xlen: T.nilable(Integer)).returns(Integer) }
661682
def width(effective_xlen)
662-
location(effective_xlen).size
683+
T.must(location(effective_xlen).size)
663684
end
664685

686+
sig { returns(Integer) }
665687
def max_width
666688
@max_width ||=
667689
if base64_only?
@@ -675,6 +697,7 @@ def max_width
675697
end
676698
end
677699

700+
sig { returns(String) }
678701
def location_cond32
679702
case csr.priv_mode
680703
when "M"
@@ -688,6 +711,7 @@ def location_cond32
688711
end
689712
end
690713

714+
sig { returns(String) }
691715
def location_cond64
692716
case csr.priv_mode
693717
when "M"
@@ -702,6 +726,7 @@ def location_cond64
702726
end
703727

704728
# @return [String] Pretty-printed location string
729+
sig { params(effective_xlen: T.nilable(Integer)).returns(String) }
705730
def location_pretty(effective_xlen = nil)
706731
derangeify = proc { |loc|
707732
next loc.min.to_s if loc.size == 1
@@ -785,6 +810,7 @@ def location_pretty(effective_xlen = nil)
785810
}.freeze
786811

787812
# @return [String] Long description of the field type
813+
sig { params(effective_xlen: T.nilable(Integer)).returns(String) }
788814
def type_desc(effective_xlen=nil)
789815
TYPE_DESC_MAP[type(effective_xlen)]
790816
end

0 commit comments

Comments
 (0)