idlc 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +26 -0
- data/bin/idlc +10 -0
- data/lib/idlc/ast.rb +9611 -0
- data/lib/idlc/ast_decl.rb +22 -0
- data/lib/idlc/cli.rb +232 -0
- data/lib/idlc/idl.treetop +675 -0
- data/lib/idlc/idl_parser.rb +15386 -0
- data/lib/idlc/interfaces.rb +135 -0
- data/lib/idlc/log.rb +23 -0
- data/lib/idlc/passes/find_referenced_csrs.rb +39 -0
- data/lib/idlc/passes/find_return_values.rb +76 -0
- data/lib/idlc/passes/find_src_registers.rb +125 -0
- data/lib/idlc/passes/gen_adoc.rb +355 -0
- data/lib/idlc/passes/gen_option_adoc.rb +169 -0
- data/lib/idlc/passes/prune.rb +957 -0
- data/lib/idlc/passes/reachable_exceptions.rb +206 -0
- data/lib/idlc/passes/reachable_functions.rb +221 -0
- data/lib/idlc/symbol_table.rb +549 -0
- data/lib/idlc/syntax_node.rb +64 -0
- data/lib/idlc/type.rb +992 -0
- data/lib/idlc/version.rb +10 -0
- data/lib/idlc.rb +409 -0
- metadata +394 -0
data/lib/idlc/type.rb
ADDED
|
@@ -0,0 +1,992 @@
|
|
|
1
|
+
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
|
2
|
+
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
3
|
+
|
|
4
|
+
# typed: true
|
|
5
|
+
# frozen_string_literal: true
|
|
6
|
+
|
|
7
|
+
require "sorbet-runtime"
|
|
8
|
+
|
|
9
|
+
module Idl
|
|
10
|
+
|
|
11
|
+
class AstNode; end
|
|
12
|
+
class EnumDefinitionAst < AstNode; end
|
|
13
|
+
class Type; end
|
|
14
|
+
class EnumerationType < Type; end
|
|
15
|
+
module Csr
|
|
16
|
+
include Kernel
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Data types
|
|
20
|
+
class Type
|
|
21
|
+
extend T::Sig
|
|
22
|
+
|
|
23
|
+
KINDS = [
|
|
24
|
+
:void, # empty
|
|
25
|
+
:boolean, # true or false, not compatible with bits/int/xreg
|
|
26
|
+
:bits, # integer with compile-time-known bit width
|
|
27
|
+
:enum, # enumeration class
|
|
28
|
+
:enum_ref, # reference to an enumeration element, convertible to int and/or Bits<bit_width(MAX_ENUM_VALUE)>
|
|
29
|
+
:bitfield, # bitfield, convertible to int and/or Bits<width>
|
|
30
|
+
:struct, # structure class
|
|
31
|
+
:array, # array of other types
|
|
32
|
+
:tuple, # tuple of other dissimilar types
|
|
33
|
+
:function, # function
|
|
34
|
+
:csr, # a CSR register type
|
|
35
|
+
:dontcare, # matches everything
|
|
36
|
+
:string # fixed-length character string
|
|
37
|
+
].freeze
|
|
38
|
+
QUALIFIERS = [
|
|
39
|
+
:const,
|
|
40
|
+
:signed,
|
|
41
|
+
:global,
|
|
42
|
+
:known
|
|
43
|
+
].freeze
|
|
44
|
+
|
|
45
|
+
# true for any type that can generally be treated as a scalar integer
|
|
46
|
+
sig { returns(T::Boolean) }
|
|
47
|
+
def integral?
|
|
48
|
+
@kind == :bits
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def ==(other)
|
|
52
|
+
return false unless other.is_a?(Type)
|
|
53
|
+
|
|
54
|
+
case other.kind
|
|
55
|
+
when :bits
|
|
56
|
+
@kind == :bits && @width == other.width
|
|
57
|
+
when :enum_ref
|
|
58
|
+
@kind == :enum_ref && T.must(@enum_class).name == other.name
|
|
59
|
+
else
|
|
60
|
+
raise "TODO: Type == for #{other.kind}"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def runtime?
|
|
65
|
+
if @kind == :array
|
|
66
|
+
T.must(@sub_type).runtime?
|
|
67
|
+
else
|
|
68
|
+
@kind == :bits && @width == :unknown
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def default
|
|
73
|
+
case @kind
|
|
74
|
+
when :bits, :bitfield
|
|
75
|
+
0
|
|
76
|
+
when :boolean
|
|
77
|
+
false
|
|
78
|
+
when :array
|
|
79
|
+
if @width == :unknown
|
|
80
|
+
Array.new
|
|
81
|
+
else
|
|
82
|
+
Array.new(T.cast(@width, Integer), sub_type.default)
|
|
83
|
+
end
|
|
84
|
+
when :string
|
|
85
|
+
""
|
|
86
|
+
when :enum_ref
|
|
87
|
+
T.must(@enum_class).element_values.min
|
|
88
|
+
when :enum
|
|
89
|
+
raise "?"
|
|
90
|
+
else
|
|
91
|
+
raise "No default for #{@kind}"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
sig { returns(Symbol) }
|
|
96
|
+
attr_reader :kind
|
|
97
|
+
|
|
98
|
+
sig { returns(T::Array[Symbol]) }
|
|
99
|
+
attr_reader :qualifiers
|
|
100
|
+
|
|
101
|
+
sig { returns(T.any(Integer, Symbol)) }
|
|
102
|
+
def width = T.must(@width)
|
|
103
|
+
|
|
104
|
+
sig { returns(T.nilable(AstNode)) }
|
|
105
|
+
attr_reader :width_ast
|
|
106
|
+
|
|
107
|
+
sig { returns(T.nilable(Integer)) }
|
|
108
|
+
attr_reader :max_width
|
|
109
|
+
|
|
110
|
+
sig { returns(Type) }
|
|
111
|
+
def sub_type = T.must(@sub_type)
|
|
112
|
+
|
|
113
|
+
sig { returns(T::Array[Type]) }
|
|
114
|
+
def tuple_types = T.must(@tuple_types)
|
|
115
|
+
|
|
116
|
+
sig { returns(EnumerationType) }
|
|
117
|
+
def enum_class = T.must(@enum_class)
|
|
118
|
+
|
|
119
|
+
def qualify(qualifier)
|
|
120
|
+
@qualifiers << qualifier
|
|
121
|
+
@qualifiers.uniq!
|
|
122
|
+
self
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def self.from_typename(type_name, cfg_arch)
|
|
126
|
+
case type_name
|
|
127
|
+
when "XReg"
|
|
128
|
+
return Type.new(:bits, width: cfg_arch.param_values.key?("MXLEN") ? cfg_arch.param_values.fetch("MXLEN") : :unknown, max_width: 64)
|
|
129
|
+
when /Bits<((?:0x)?[0-9a-fA-F]+)>/
|
|
130
|
+
Type.new(:bits, width: $1.to_i)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
sig {
|
|
135
|
+
params(
|
|
136
|
+
kind: Symbol,
|
|
137
|
+
qualifiers: T::Array[Symbol],
|
|
138
|
+
width: T.nilable(T.any(Integer, Symbol)),
|
|
139
|
+
width_ast: T.nilable(AstNode),
|
|
140
|
+
max_width: T.nilable(Integer),
|
|
141
|
+
sub_type: T.nilable(Type),
|
|
142
|
+
name: T.nilable(String),
|
|
143
|
+
tuple_types: T.nilable(T::Array[Type]),
|
|
144
|
+
return_type: T.nilable(Type),
|
|
145
|
+
enum_class: T.nilable(EnumerationType),
|
|
146
|
+
csr: T.nilable(Csr)
|
|
147
|
+
)
|
|
148
|
+
.void
|
|
149
|
+
}
|
|
150
|
+
def initialize(kind, qualifiers: [], width: nil, width_ast: nil, max_width: nil, sub_type: nil, name: nil, tuple_types: nil, return_type: nil, enum_class: nil, csr: nil)
|
|
151
|
+
raise "Invalid kind '#{kind}'" unless KINDS.include?(kind)
|
|
152
|
+
|
|
153
|
+
@kind = kind
|
|
154
|
+
raise "Invalid qualifier" unless qualifiers.intersection(QUALIFIERS) == qualifiers
|
|
155
|
+
|
|
156
|
+
@qualifiers = qualifiers
|
|
157
|
+
# raise "#{width.class.name}" if (kind == :bits && !width.is_a?(Integer))
|
|
158
|
+
|
|
159
|
+
raise "Should be a FunctionType" if kind == :function && !self.is_a?(FunctionType)
|
|
160
|
+
|
|
161
|
+
@width = width
|
|
162
|
+
@width_ast = width_ast
|
|
163
|
+
@max_width = max_width
|
|
164
|
+
@sub_type = sub_type
|
|
165
|
+
raise "Tuples need a type list" if kind == :tuple && tuple_types.nil?
|
|
166
|
+
@tuple_types = tuple_types
|
|
167
|
+
@enum_class = enum_class
|
|
168
|
+
@name = name
|
|
169
|
+
if kind == :bits
|
|
170
|
+
raise "Bits type must have width" unless @width
|
|
171
|
+
raise "Bits type must have positive width (has #{@width})" unless @width == :unknown || T.cast(@width, Integer).positive?
|
|
172
|
+
end
|
|
173
|
+
if kind == :enum
|
|
174
|
+
raise "Enum type must have width" unless @width
|
|
175
|
+
end
|
|
176
|
+
if kind == :array && width != 0
|
|
177
|
+
raise "Array must have a subtype" unless @sub_type
|
|
178
|
+
end
|
|
179
|
+
if kind == :csr
|
|
180
|
+
raise "CSR type must have a csr argument" if csr.nil?
|
|
181
|
+
|
|
182
|
+
@csr = csr
|
|
183
|
+
raise "CSR types must have a width" if width.nil?
|
|
184
|
+
|
|
185
|
+
@width = width
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
TYPE_FROM_KIND = [:boolean, :void, :dontcare].map { |k| [k, Type.new(k)] }.to_h.freeze
|
|
189
|
+
|
|
190
|
+
def clone
|
|
191
|
+
Type.new(
|
|
192
|
+
@kind,
|
|
193
|
+
qualifiers: @qualifiers.map(&:clone),
|
|
194
|
+
width: @width,
|
|
195
|
+
sub_type: @sub_type&.clone,
|
|
196
|
+
name: @name.dup,
|
|
197
|
+
tuple_types: @tuple_types&.map(&:clone),
|
|
198
|
+
enum_class: @enum_class&.clone,
|
|
199
|
+
csr: @csr
|
|
200
|
+
)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# returns true if 'type' can be compared (e.g., >=, <, etc) to self
|
|
204
|
+
# 'type' can be a Type object or a kind (as a Symbol)
|
|
205
|
+
def comparable_to?(type)
|
|
206
|
+
if type.is_a?(Symbol)
|
|
207
|
+
raise "#{type} is not a kind" unless KINDS.include?(type)
|
|
208
|
+
|
|
209
|
+
type = Type.new(type)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
case @kind
|
|
213
|
+
when :boolean
|
|
214
|
+
return type.kind == :boolean
|
|
215
|
+
when :enum_ref
|
|
216
|
+
return \
|
|
217
|
+
(type.kind == :enum_ref && type.enum_class.name == T.must(@enum_class).name) \
|
|
218
|
+
|| (type.kind == :enum && type.name == T.must(@enum_class).name)
|
|
219
|
+
when :bits
|
|
220
|
+
return type.convertable_to?(self) && (signed? == type.signed?)
|
|
221
|
+
when :enum
|
|
222
|
+
return type.convertable_to?(:bits)
|
|
223
|
+
when :function
|
|
224
|
+
# functions are not comparable to anything
|
|
225
|
+
return false
|
|
226
|
+
when :csr
|
|
227
|
+
return ((type.kind == :csr) && (type.csr.name == @csr.name)) ||
|
|
228
|
+
type.convertable_to?(Type.new(:bits, width: type.csr.width))
|
|
229
|
+
when :string
|
|
230
|
+
return type.kind == :string
|
|
231
|
+
else
|
|
232
|
+
raise "unimplemented #{@kind}"
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# returns true if identical to type, excluding qualifiers
|
|
237
|
+
def equal_to?(type)
|
|
238
|
+
if type.is_a?(Symbol)
|
|
239
|
+
raise "#{type} is not a kind" unless KINDS.include?(type)
|
|
240
|
+
|
|
241
|
+
type = TYPE_FROM_KIND[type]
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
case @kind
|
|
245
|
+
when :boolean
|
|
246
|
+
type.kind == :boolean
|
|
247
|
+
when :enum_ref
|
|
248
|
+
type.kind == :enum_ref && type.name == T.must(@enum_class).name
|
|
249
|
+
when :dontcare
|
|
250
|
+
true
|
|
251
|
+
when :bits
|
|
252
|
+
type.kind == :bits && type.width == @width
|
|
253
|
+
when :string
|
|
254
|
+
type.kind == :string && type.width == @width
|
|
255
|
+
when :array
|
|
256
|
+
type.kind == :array && type.sub_type.equal_to?(@sub_type)
|
|
257
|
+
when :struct
|
|
258
|
+
type.kind == :struct && (T.cast(type, StructType).type_name == T.cast(self, StructType).type_name)
|
|
259
|
+
else
|
|
260
|
+
raise "unimplemented type '#{@kind}'"
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# given an N-dimensional array type, return the primitive type
|
|
265
|
+
def ary_type(ary)
|
|
266
|
+
if ary.sub_type == :array
|
|
267
|
+
ary_type(ary.sub_type)
|
|
268
|
+
else
|
|
269
|
+
ary.sub_type
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# returns true if self can be converted to 'type'
|
|
274
|
+
# 'type' can be a Type object or a kind (as a Symbol)
|
|
275
|
+
def convertable_to?(type)
|
|
276
|
+
if type.is_a?(Symbol)
|
|
277
|
+
raise "#{type} is not a kind" unless KINDS.include?(type)
|
|
278
|
+
|
|
279
|
+
type = TYPE_FROM_KIND[type]
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
case @kind
|
|
283
|
+
when :boolean
|
|
284
|
+
return type.kind == :boolean
|
|
285
|
+
when :enum_ref
|
|
286
|
+
return \
|
|
287
|
+
(type.kind == :enum && type.name == T.must(@enum_class).name) || \
|
|
288
|
+
(type.kind == :enum_ref && type.enum_class.name == T.must(@enum_class).name)
|
|
289
|
+
when :dontcare
|
|
290
|
+
return true
|
|
291
|
+
when :bits
|
|
292
|
+
if type.kind == :enum_ref
|
|
293
|
+
warn "You seem to be missing an $enum cast"
|
|
294
|
+
return false
|
|
295
|
+
end
|
|
296
|
+
return type.kind == :bits || type.kind == :bitfield
|
|
297
|
+
when :enum
|
|
298
|
+
if type.kind == :bits
|
|
299
|
+
return false
|
|
300
|
+
# return (type.width == :unknown) || (width <= type.width)
|
|
301
|
+
elsif type.kind == :enum
|
|
302
|
+
return type.enum_class == enum_class
|
|
303
|
+
else
|
|
304
|
+
return false
|
|
305
|
+
end
|
|
306
|
+
when :tuple
|
|
307
|
+
is_tuple_of_same_size = (type.kind == :tuple) && (T.must(@tuple_types).size == type.tuple_types.size)
|
|
308
|
+
if is_tuple_of_same_size
|
|
309
|
+
T.must(@tuple_types).each_index do |i|
|
|
310
|
+
unless T.must(@tuple_types).fetch(i).convertable_to?(type.tuple_types.fetch(i))
|
|
311
|
+
return false
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
return true
|
|
315
|
+
else
|
|
316
|
+
return false
|
|
317
|
+
end
|
|
318
|
+
when :csr
|
|
319
|
+
return (type.kind == :csr && type.csr.name == @csr.name) || type.convertable_to?(Type.new(:bits, width:))
|
|
320
|
+
when :bitfield
|
|
321
|
+
if (type.kind == :bitfield && name == type.name)
|
|
322
|
+
return true
|
|
323
|
+
elsif (type.kind == :bits && type.width == @width)
|
|
324
|
+
return true
|
|
325
|
+
else
|
|
326
|
+
# be strict with bitfields -- only accept integrals that are exact width Bit types
|
|
327
|
+
return false
|
|
328
|
+
end
|
|
329
|
+
when :array
|
|
330
|
+
return type.kind == :array && type.sub_type.convertable_to?(sub_type) && type.width == @width
|
|
331
|
+
when :string
|
|
332
|
+
return type.kind == :string
|
|
333
|
+
when :void
|
|
334
|
+
return type.kind == :void
|
|
335
|
+
when :struct
|
|
336
|
+
return type.kind == :struct && (T.cast(type, StructType).name == T.cast(self, StructType).type_name)
|
|
337
|
+
else
|
|
338
|
+
raise "unimplemented type '#{@kind}'"
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# return IDL representation of the type
|
|
343
|
+
sig { returns(String) }
|
|
344
|
+
def to_idl
|
|
345
|
+
case @kind
|
|
346
|
+
when :bits
|
|
347
|
+
if @width == :unknown
|
|
348
|
+
raise "Cannot generate an IDL type with an unknown width"
|
|
349
|
+
end
|
|
350
|
+
if signed?
|
|
351
|
+
raise "Cannot directly represent a signed bits"
|
|
352
|
+
else
|
|
353
|
+
"Bits<#{@width}"
|
|
354
|
+
end
|
|
355
|
+
when :String
|
|
356
|
+
"String"
|
|
357
|
+
when :boolean
|
|
358
|
+
"Boolean"
|
|
359
|
+
else
|
|
360
|
+
raise "TODO"
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def to_s
|
|
365
|
+
((@qualifiers.empty?) ? "" : "#{@qualifiers.map(&:to_s).join(' ')} ") + \
|
|
366
|
+
if @kind == :bits
|
|
367
|
+
"Bits<#{@width}>"
|
|
368
|
+
elsif @kind == :enum
|
|
369
|
+
"enum definition #{@name}"
|
|
370
|
+
elsif @kind == :boolean
|
|
371
|
+
"Boolean"
|
|
372
|
+
elsif @kind == :enum_ref
|
|
373
|
+
"enum #{T.must(@enum_class).name}"
|
|
374
|
+
elsif @kind == :tuple
|
|
375
|
+
"(#{T.must(@tuple_types).map { |t| t.to_s }.join(',')})"
|
|
376
|
+
elsif @kind == :bitfield
|
|
377
|
+
"bitfield #{@name}"
|
|
378
|
+
elsif @kind == :array
|
|
379
|
+
"array of #{@sub_type}"
|
|
380
|
+
elsif @kind == :csr
|
|
381
|
+
"CSR[#{@csr.name}]"
|
|
382
|
+
elsif @kind == :void
|
|
383
|
+
"void"
|
|
384
|
+
elsif @kind == :string
|
|
385
|
+
"string"
|
|
386
|
+
elsif @kind == :struct
|
|
387
|
+
"struct #{T.cast(self, StructType).type_name}"
|
|
388
|
+
elsif @kind == :function
|
|
389
|
+
"function #{name}"
|
|
390
|
+
else
|
|
391
|
+
raise @kind.to_s
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
alias fully_qualified_name to_s
|
|
395
|
+
|
|
396
|
+
def name
|
|
397
|
+
if @kind == :bits
|
|
398
|
+
"Bits<#{@width}>"
|
|
399
|
+
elsif @kind == :enum
|
|
400
|
+
@name
|
|
401
|
+
elsif @kind == :bitfield
|
|
402
|
+
@name
|
|
403
|
+
elsif @kind == :function
|
|
404
|
+
@name
|
|
405
|
+
elsif @kind == :csr
|
|
406
|
+
@csr.name
|
|
407
|
+
elsif @kind == :enum_ref
|
|
408
|
+
T.must(@enum_class).name
|
|
409
|
+
else
|
|
410
|
+
raise @kind.to_s
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def ary?
|
|
415
|
+
@kind == :array
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def const?
|
|
419
|
+
@qualifiers.include?(:const)
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def mutable?
|
|
423
|
+
!const?
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
def signed?
|
|
427
|
+
@qualifiers.include?(:signed)
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def global?
|
|
431
|
+
@qualifiers.include?(:global)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def known?
|
|
435
|
+
@qualifiers.include?(:known)
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def make_signed
|
|
439
|
+
@qualifiers.append(:signed).uniq!
|
|
440
|
+
self
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
# make this Type constant, and return self
|
|
444
|
+
sig { returns(Type) }
|
|
445
|
+
def make_const!
|
|
446
|
+
@qualifiers.append(:const).uniq!
|
|
447
|
+
self
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
# make a clone of this Type, add a constant qualifier, and return the new type
|
|
451
|
+
sig { returns(Type) }
|
|
452
|
+
def make_const
|
|
453
|
+
new_t = clone
|
|
454
|
+
new_t.make_const!
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def make_global
|
|
458
|
+
@qualifiers.append(:global).uniq!
|
|
459
|
+
self
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def make_known
|
|
463
|
+
@qualifiers.append(:known).uniq!
|
|
464
|
+
self
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
# @return [Idl::Type] Type of a scalar
|
|
468
|
+
# @param schema [Hash] JSON Schema description of a scalar
|
|
469
|
+
sig { params(schema: T::Hash[String, T.untyped]).returns(T.nilable(Type)) }
|
|
470
|
+
def self.from_json_schema_scalar_type(schema)
|
|
471
|
+
if schema.key?("type")
|
|
472
|
+
case schema["type"]
|
|
473
|
+
when "boolean"
|
|
474
|
+
Type.new(:boolean)
|
|
475
|
+
when "integer"
|
|
476
|
+
if schema.key?("enum")
|
|
477
|
+
Type.new(:bits, width: schema["enum"].max.bit_length)
|
|
478
|
+
elsif schema.key?("maximum")
|
|
479
|
+
Type.new(:bits, width: schema["maximum"].bit_length)
|
|
480
|
+
else
|
|
481
|
+
Type.new(:bits, width: 128)
|
|
482
|
+
end
|
|
483
|
+
when "string"
|
|
484
|
+
if schema.key?("enum")
|
|
485
|
+
Type.new(:string, width: schema["enum"].map(&:length).max)
|
|
486
|
+
else
|
|
487
|
+
Type.new(:string, width: 4096)
|
|
488
|
+
end
|
|
489
|
+
else
|
|
490
|
+
raise "Unhandled JSON schema type"
|
|
491
|
+
end
|
|
492
|
+
elsif schema.key?("const")
|
|
493
|
+
case schema["const"]
|
|
494
|
+
when TrueClass, FalseClass
|
|
495
|
+
Type.new(:boolean)
|
|
496
|
+
when Integer
|
|
497
|
+
Type.new(:bits, width: schema["const"].bit_length)
|
|
498
|
+
when String
|
|
499
|
+
Type.new(:string, width: schema["const"].length)
|
|
500
|
+
else
|
|
501
|
+
raise "Unhandled const type"
|
|
502
|
+
end
|
|
503
|
+
elsif schema.key?("enum")
|
|
504
|
+
raise "Mixed types in enum" unless schema["enum"].all? { |e| e.class == schema["enum"].fetch(0).class }
|
|
505
|
+
|
|
506
|
+
case schema["enum"].fetch(0)
|
|
507
|
+
when TrueClass, FalseClass
|
|
508
|
+
Type.new(:boolean)
|
|
509
|
+
when Integer
|
|
510
|
+
Type.new(:bits, width: schema["enum"].map { |e| e.bit_length }.max)
|
|
511
|
+
when String
|
|
512
|
+
Type.new(:string, width: schema["enum"].map { |e| e.length }.max)
|
|
513
|
+
else
|
|
514
|
+
raise "unhandled enum type"
|
|
515
|
+
end
|
|
516
|
+
elsif schema.key?("allOf")
|
|
517
|
+
subschema_types = schema.fetch("allOf").map { |subschema| from_json_schema_scalar_type(subschema) }.compact
|
|
518
|
+
raise "No subschema has a defined type" if subschema_types.empty?
|
|
519
|
+
|
|
520
|
+
if subschema_types.fetch(0).kind == :string
|
|
521
|
+
raise "Subschema types do not agree" unless subschema_types[1..].all? { |t| t.kind == :string }
|
|
522
|
+
|
|
523
|
+
subschema_types.fetch(0)
|
|
524
|
+
elsif subschema_types.fetch(0).kind == :boolean
|
|
525
|
+
raise "Subschema types do not agree" unless subschema_types[1..].all? { |t| t.kind == :boolean }
|
|
526
|
+
|
|
527
|
+
subschema_types.fetch(0)
|
|
528
|
+
elsif subschema_types.fetch(0).kind == :bits
|
|
529
|
+
raise "Subschema types do not agree" unless subschema_types[1..].all? { |t| t.kind == :bits }
|
|
530
|
+
|
|
531
|
+
unknown_width_type = subschema_types.find { |t| t.width == :unknown }
|
|
532
|
+
return unknown_width_type unless unknown_width_type.nil?
|
|
533
|
+
|
|
534
|
+
subschema_types.max { |t1, t2| t1.width <=> t2.width }
|
|
535
|
+
else
|
|
536
|
+
raise "unhandled subschema type"
|
|
537
|
+
end
|
|
538
|
+
elsif schema.key?("$ref")
|
|
539
|
+
if schema.fetch("$ref") == "schema_defs.json#/$defs/uint32"
|
|
540
|
+
Type.new(:bits, width: 32)
|
|
541
|
+
elsif schema.fetch("$ref") == "schema_defs.json#/$defs/uint64"
|
|
542
|
+
Type.new(:bits, width: 64)
|
|
543
|
+
else
|
|
544
|
+
raise "unhandled ref: #{schema.fetch("$ref")}"
|
|
545
|
+
end
|
|
546
|
+
elsif schema.key?("not")
|
|
547
|
+
nil
|
|
548
|
+
else
|
|
549
|
+
raise "unhandled scalar schema:\n#{schema}"
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
private_class_method :from_json_schema_scalar_type
|
|
553
|
+
|
|
554
|
+
# @return [Idl::Type] Type of array
|
|
555
|
+
# @param schema [Hash] JSON Schema description of an array
|
|
556
|
+
sig { params(schema: T::Hash[String, T.untyped]).returns(Type) }
|
|
557
|
+
def self.from_json_schema_array_type(schema)
|
|
558
|
+
width = schema["minItems"]
|
|
559
|
+
if !schema.key?("minItems") || !schema.key?("maxItems") || (schema["minItems"] != schema["maxItems"])
|
|
560
|
+
width = :unknown
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
if schema["items"].is_a?(Hash)
|
|
564
|
+
Type.new(:array, width:, sub_type: from_json_schema(schema["items"]))
|
|
565
|
+
else
|
|
566
|
+
raise "unexpected #{schema}" unless schema["items"].is_a?(Array)
|
|
567
|
+
|
|
568
|
+
# this ia an array with each element specified
|
|
569
|
+
sub_type = T.let(nil, T.nilable(Type))
|
|
570
|
+
schema["items"].each do |item_schema|
|
|
571
|
+
if sub_type.nil?
|
|
572
|
+
sub_type = from_json_schema_scalar_type(item_schema)
|
|
573
|
+
else
|
|
574
|
+
unless sub_type.equal_to?(from_json_schema_scalar_type(item_schema))
|
|
575
|
+
raise "Schema error: Array elements must be the same type (#{sub_type} #{from_json_schema_scalar_type(item_schema)}) \n#{schema["items"]}"
|
|
576
|
+
end
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
if schema.key?("additionalItems")
|
|
580
|
+
if sub_type.nil?
|
|
581
|
+
sub_type = from_json_schema_scalar_type(schema["additionalItems"])
|
|
582
|
+
else
|
|
583
|
+
unless sub_type.equal_to?(from_json_schema_scalar_type(schema["additionalItems"]))
|
|
584
|
+
raise "Schema error: Array elements must be the same type"
|
|
585
|
+
end
|
|
586
|
+
end
|
|
587
|
+
end
|
|
588
|
+
Type.new(:array, width:, sub_type:)
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
private_class_method :from_json_schema_array_type
|
|
592
|
+
|
|
593
|
+
# @returns [Idl::Type] Type described by JSON +schema+
|
|
594
|
+
sig { params(schema: T::Hash[String, T.untyped]).returns(T.nilable(Type)) }
|
|
595
|
+
def self.from_json_schema(schema)
|
|
596
|
+
hsh = schema.to_h
|
|
597
|
+
if hsh.key?("type")
|
|
598
|
+
case hsh["type"]
|
|
599
|
+
when "boolean", "integer", "string"
|
|
600
|
+
from_json_schema_scalar_type(hsh)
|
|
601
|
+
when "array"
|
|
602
|
+
from_json_schema_array_type(hsh)
|
|
603
|
+
else
|
|
604
|
+
raise "unexpected"
|
|
605
|
+
end
|
|
606
|
+
else
|
|
607
|
+
from_json_schema_scalar_type(hsh)
|
|
608
|
+
end
|
|
609
|
+
end
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
class StructType < Type
|
|
613
|
+
sig { returns(String) }
|
|
614
|
+
attr_reader :type_name
|
|
615
|
+
|
|
616
|
+
sig { params(type_name: String, member_types: T::Array[Type], member_names: T::Array[String]).void }
|
|
617
|
+
def initialize(type_name, member_types, member_names)
|
|
618
|
+
super(:struct)
|
|
619
|
+
@type_name = type_name
|
|
620
|
+
@member_types = member_types
|
|
621
|
+
@member_names = member_names
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
sig { returns(String) }
|
|
625
|
+
def name = @type_name
|
|
626
|
+
|
|
627
|
+
def clone
|
|
628
|
+
StructType.new(@type_name, @member_types, @member_names)
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
def default
|
|
632
|
+
hsh = {}
|
|
633
|
+
@member_types.size.times do |i|
|
|
634
|
+
hsh[@member_names.fetch(i)] = @member_types.fetch(i).default
|
|
635
|
+
end
|
|
636
|
+
hsh
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
def member?(name) = @member_names.include?(name)
|
|
640
|
+
|
|
641
|
+
def member_type(member_name)
|
|
642
|
+
idx = @member_names.index(member_name)
|
|
643
|
+
raise "No member named '#{member_name}'" if idx.nil?
|
|
644
|
+
|
|
645
|
+
@member_types[idx]
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
# does this struct have any members whose type depends on a runtime parameter?
|
|
649
|
+
def runtime?
|
|
650
|
+
@member_types.any?(&:runtime?)
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
class EnumerationType < Type
|
|
655
|
+
extend T::Sig
|
|
656
|
+
|
|
657
|
+
# @return [Integer] The bit width of the enumeration elements
|
|
658
|
+
sig { returns(Integer) }
|
|
659
|
+
def width = T.cast(@width, Integer)
|
|
660
|
+
|
|
661
|
+
# @return [Array<String>] The names of the enumeration elements, in the same order as element_values
|
|
662
|
+
sig { returns(T::Array[String]) }
|
|
663
|
+
attr_reader :element_names
|
|
664
|
+
|
|
665
|
+
# @return [Array<Integer>] The values of the enumeration elements, in the same order as element_names
|
|
666
|
+
sig { returns(T::Array[Integer]) }
|
|
667
|
+
attr_reader :element_values
|
|
668
|
+
|
|
669
|
+
# @return [Type] The type of an reference to this Enumeration class
|
|
670
|
+
sig { returns(Type) }
|
|
671
|
+
attr_reader :ref_type
|
|
672
|
+
|
|
673
|
+
# @param type_name [String] The name of the enum class
|
|
674
|
+
# @param element_names [Array<String>] The names of the elements, in the same order as +element_values+
|
|
675
|
+
# @param element_values [Array<Integer>] The values of the elements, in the same order as +element_names+
|
|
676
|
+
sig {
|
|
677
|
+
params(
|
|
678
|
+
type_name: String,
|
|
679
|
+
element_names: T::Array[String],
|
|
680
|
+
element_values: T::Array[Integer],
|
|
681
|
+
builtin: T::Boolean
|
|
682
|
+
).void
|
|
683
|
+
}
|
|
684
|
+
def initialize(type_name, element_names, element_values, builtin: false)
|
|
685
|
+
width = T.must(element_values.max).bit_length
|
|
686
|
+
width = 1 if width.zero? # can happen if only enum member has value 0
|
|
687
|
+
super(:enum, width:)
|
|
688
|
+
|
|
689
|
+
@name = type_name.freeze
|
|
690
|
+
@element_names = element_names.freeze
|
|
691
|
+
@element_values = element_values.freeze
|
|
692
|
+
raise "names and values aren't the same size" unless element_names.size == element_values.size
|
|
693
|
+
|
|
694
|
+
@ref_type = Type.new(:enum_ref, enum_class: self).freeze
|
|
695
|
+
@builtin = builtin.freeze
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
sig { returns(T::Boolean) }
|
|
699
|
+
def builtin? = @builtin
|
|
700
|
+
|
|
701
|
+
sig { returns(EnumerationType) }
|
|
702
|
+
def clone
|
|
703
|
+
EnumerationType.new(T.must(@name), @element_names, @element_values)
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
sig { params(element_name: String).returns(T.nilable(Integer)) }
|
|
707
|
+
def value(element_name)
|
|
708
|
+
i = @element_names.index(element_name)
|
|
709
|
+
return nil if i.nil?
|
|
710
|
+
|
|
711
|
+
@element_values[i]
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
sig { params(element_value: Integer).returns(T.nilable(String)) }
|
|
715
|
+
def element_name(element_value)
|
|
716
|
+
i = @element_values.index(element_value)
|
|
717
|
+
raise "? #{element_value}" if i.nil?
|
|
718
|
+
return nil if i.nil?
|
|
719
|
+
|
|
720
|
+
@element_names[i]
|
|
721
|
+
end
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
class BitfieldType < Type
|
|
725
|
+
def width = @field_ranges.map(&:size).reduce(&:+)
|
|
726
|
+
def initialize(type_name, width, field_names, field_ranges)
|
|
727
|
+
super(:bitfield, name: type_name, width:)
|
|
728
|
+
|
|
729
|
+
@field_names = field_names
|
|
730
|
+
@field_ranges = field_ranges
|
|
731
|
+
raise "unexpected" unless field_names.is_a?(Array)
|
|
732
|
+
raise "unexpected" unless field_ranges.is_a?(Array) && field_names.length == field_ranges.length
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
def range(field_name)
|
|
736
|
+
i = @field_names.index(field_name)
|
|
737
|
+
raise "Could not find #{field_name} in #{@name}" if i.nil?
|
|
738
|
+
|
|
739
|
+
@field_ranges[i]
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
def field_names
|
|
743
|
+
@field_names
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
def clone
|
|
747
|
+
BitfieldType.new(
|
|
748
|
+
name,
|
|
749
|
+
width,
|
|
750
|
+
field_names,
|
|
751
|
+
@field_ranges
|
|
752
|
+
)
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
# represents a CSR register
|
|
758
|
+
class CsrType < Type
|
|
759
|
+
extend T::Sig
|
|
760
|
+
|
|
761
|
+
sig { returns(Csr) }
|
|
762
|
+
attr_reader :csr
|
|
763
|
+
|
|
764
|
+
sig { params(csr: Csr, qualifiers: T::Array[Symbol]).void }
|
|
765
|
+
def initialize(csr, qualifiers: [])
|
|
766
|
+
super(:csr, name: csr.name, csr: csr, width: csr.max_length, qualifiers: qualifiers)
|
|
767
|
+
end
|
|
768
|
+
|
|
769
|
+
sig { returns(T::Array[CsrField]) }
|
|
770
|
+
def fields
|
|
771
|
+
raise "fields are unknown" if @csr == :unknown
|
|
772
|
+
|
|
773
|
+
@csr.fields
|
|
774
|
+
end
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
class FunctionType < Type
|
|
778
|
+
attr_reader :func_def_ast
|
|
779
|
+
|
|
780
|
+
sig {
|
|
781
|
+
params(
|
|
782
|
+
func_name: String,
|
|
783
|
+
func_def_ast: FunctionDefAst,
|
|
784
|
+
symtab: SymbolTable
|
|
785
|
+
)
|
|
786
|
+
.void
|
|
787
|
+
}
|
|
788
|
+
def initialize(func_name, func_def_ast, symtab)
|
|
789
|
+
super(:function, name: func_name)
|
|
790
|
+
@func_def_ast = func_def_ast
|
|
791
|
+
@symtab = symtab
|
|
792
|
+
|
|
793
|
+
raise "symtab should be at level 1" unless symtab.levels == 1
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
def argument_nodes = @func_def_ast.argument_nodes
|
|
797
|
+
|
|
798
|
+
sig {
|
|
799
|
+
returns(FunctionType)
|
|
800
|
+
}
|
|
801
|
+
def clone
|
|
802
|
+
FunctionType.new(name, @func_def_ast, @symtab)
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
sig { returns(T::Boolean) }
|
|
806
|
+
def builtin? = @func_def_ast.builtin?
|
|
807
|
+
|
|
808
|
+
sig { returns(T::Boolean) }
|
|
809
|
+
def generated? = @func_def_ast.generated?
|
|
810
|
+
|
|
811
|
+
sig { returns(T::Boolean) }
|
|
812
|
+
def external? = @func_def_ast.external?
|
|
813
|
+
|
|
814
|
+
sig { returns(Integer) }
|
|
815
|
+
def num_args = @func_def_ast.num_args
|
|
816
|
+
|
|
817
|
+
# apply the arguments as Vars.
|
|
818
|
+
# then add the value to the Var
|
|
819
|
+
sig {
|
|
820
|
+
params(
|
|
821
|
+
symtab: SymbolTable, # global symbol table
|
|
822
|
+
argument_nodes: T::Array[Rvalue], # arguments
|
|
823
|
+
call_site_symtab: SymbolTable, # symbol table at the function call site
|
|
824
|
+
func_call_ast: FunctionCallExpressionAst
|
|
825
|
+
).returns(T::Array[T.any(Integer, Symbol)])
|
|
826
|
+
}
|
|
827
|
+
def apply_arguments(symtab, argument_nodes, call_site_symtab, func_call_ast)
|
|
828
|
+
idx = 0
|
|
829
|
+
values = []
|
|
830
|
+
@func_def_ast.arguments(symtab).each do |atype, aname|
|
|
831
|
+
func_call_ast.type_error "Missing argument #{idx}" if idx >= argument_nodes.size
|
|
832
|
+
value_result = Idl::AstNode.value_try do
|
|
833
|
+
value = argument_nodes.fetch(idx).value(call_site_symtab)
|
|
834
|
+
symtab.add(aname, Var.new(aname, atype, value))
|
|
835
|
+
values << value
|
|
836
|
+
end
|
|
837
|
+
Idl::AstNode.value_else(value_result) do
|
|
838
|
+
symtab.add(aname, Var.new(aname, atype))
|
|
839
|
+
values << :unknown
|
|
840
|
+
end
|
|
841
|
+
idx += 1
|
|
842
|
+
end
|
|
843
|
+
values
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
# @return [Array<Integer,Boolean>] Array of argument values, if known
|
|
847
|
+
# @return [nil] if at least one argument value is not known
|
|
848
|
+
sig {
|
|
849
|
+
params(
|
|
850
|
+
symtab: SymbolTable, # global symbol table
|
|
851
|
+
argument_nodes: T::Array[Rvalue], # arguments
|
|
852
|
+
call_site_symtab: SymbolTable, # symbol table at the function call site
|
|
853
|
+
func_call_ast: FunctionCallExpressionAst
|
|
854
|
+
).returns(T.nilable(T::Array[T.any(Integer, T::Boolean, Symbol)]))
|
|
855
|
+
}
|
|
856
|
+
def argument_values(symtab, argument_nodes, call_site_symtab, func_call_ast)
|
|
857
|
+
idx = 0
|
|
858
|
+
values = []
|
|
859
|
+
@func_def_ast.arguments(symtab).each do |atype, aname|
|
|
860
|
+
func_call_ast.type_error "Missing argument #{idx}" if idx >= argument_nodes.size
|
|
861
|
+
value_result = Idl::AstNode.value_try do
|
|
862
|
+
values << argument_nodes.fetch(idx).value(call_site_symtab)
|
|
863
|
+
end
|
|
864
|
+
Idl::AstNode.value_else(value_result) do
|
|
865
|
+
return nil
|
|
866
|
+
end
|
|
867
|
+
idx += 1
|
|
868
|
+
end
|
|
869
|
+
values
|
|
870
|
+
end
|
|
871
|
+
|
|
872
|
+
# @param func_call_ast [FunctionCallExpressionAst] The function call interested in the return type
|
|
873
|
+
# return [Type] type of the call return
|
|
874
|
+
sig {
|
|
875
|
+
params(
|
|
876
|
+
argument_nodes: T::Array[Rvalue],
|
|
877
|
+
func_call_ast: FunctionCallExpressionAst
|
|
878
|
+
).returns(Type)
|
|
879
|
+
}
|
|
880
|
+
def return_type(argument_nodes, func_call_ast)
|
|
881
|
+
rtype =
|
|
882
|
+
begin
|
|
883
|
+
symtab = @symtab.global_clone
|
|
884
|
+
symtab.push(func_call_ast)
|
|
885
|
+
@func_def_ast.return_type(symtab)
|
|
886
|
+
ensure
|
|
887
|
+
symtab.pop
|
|
888
|
+
symtab.release
|
|
889
|
+
end
|
|
890
|
+
|
|
891
|
+
T.must(rtype)
|
|
892
|
+
end
|
|
893
|
+
|
|
894
|
+
sig {
|
|
895
|
+
params(
|
|
896
|
+
argument_nodes: T::Array[Rvalue], # arguments
|
|
897
|
+
call_site_symtab: SymbolTable, # symbol table at the function call site
|
|
898
|
+
func_call_ast: FunctionCallExpressionAst
|
|
899
|
+
).returns(T.nilable(T.any(Integer, T::Boolean, Symbol, T::Hash[String, T.untyped])))
|
|
900
|
+
}
|
|
901
|
+
def return_value(argument_nodes, call_site_symtab, func_call_ast)
|
|
902
|
+
symtab = @symtab.global_clone
|
|
903
|
+
symtab.push(func_call_ast)
|
|
904
|
+
apply_arguments(symtab, argument_nodes, call_site_symtab, func_call_ast)
|
|
905
|
+
|
|
906
|
+
begin
|
|
907
|
+
value = @func_def_ast.body.return_value(symtab)
|
|
908
|
+
ensure
|
|
909
|
+
symtab.pop
|
|
910
|
+
symtab.release
|
|
911
|
+
end
|
|
912
|
+
raise "?" if value.is_a?(SymbolTable)
|
|
913
|
+
value
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
sig {
|
|
917
|
+
params(
|
|
918
|
+
index: Integer,
|
|
919
|
+
argument_nodes: T::Array[Rvalue], # arguments
|
|
920
|
+
call_site_symtab: SymbolTable, # symbol table at the function call site
|
|
921
|
+
func_call_ast: FunctionCallExpressionAst
|
|
922
|
+
).returns(T.nilable(Type))
|
|
923
|
+
}
|
|
924
|
+
def argument_type(index, argument_nodes, call_site_symtab, func_call_ast)
|
|
925
|
+
return nil if index >= @func_def_ast.num_args
|
|
926
|
+
|
|
927
|
+
symtab = @symtab.global_clone
|
|
928
|
+
symtab.push(func_call_ast)
|
|
929
|
+
|
|
930
|
+
begin
|
|
931
|
+
arguments = @func_def_ast.arguments(symtab)
|
|
932
|
+
ensure
|
|
933
|
+
symtab.pop
|
|
934
|
+
symtab.release
|
|
935
|
+
end
|
|
936
|
+
arguments[index][0]
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
sig {
|
|
940
|
+
params(
|
|
941
|
+
index: Integer,
|
|
942
|
+
func_call_ast: FunctionCallExpressionAst
|
|
943
|
+
).returns(T.nilable(String))
|
|
944
|
+
}
|
|
945
|
+
def argument_name(index, func_call_ast)
|
|
946
|
+
return nil if index >= @func_def_ast.num_args
|
|
947
|
+
|
|
948
|
+
symtab = @symtab.global_clone
|
|
949
|
+
symtab.push(func_call_ast)
|
|
950
|
+
|
|
951
|
+
begin
|
|
952
|
+
arguments = @func_def_ast.arguments(symtab)
|
|
953
|
+
ensure
|
|
954
|
+
symtab.pop
|
|
955
|
+
symtab.release
|
|
956
|
+
end
|
|
957
|
+
arguments[index][1]
|
|
958
|
+
end
|
|
959
|
+
|
|
960
|
+
sig {
|
|
961
|
+
returns(FunctionBodyAst)
|
|
962
|
+
}
|
|
963
|
+
def body = @func_def_ast.body
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
# XReg is really a Bits<> type, so we override it just to get
|
|
967
|
+
# prettier prints
|
|
968
|
+
class XregType < Type
|
|
969
|
+
def initialize(xlen)
|
|
970
|
+
super(:bits, width: xlen, max_width: 64)
|
|
971
|
+
end
|
|
972
|
+
|
|
973
|
+
def to_s
|
|
974
|
+
"XReg"
|
|
975
|
+
end
|
|
976
|
+
|
|
977
|
+
def to_cxx
|
|
978
|
+
"XReg"
|
|
979
|
+
end
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
# pre-define some common types
|
|
983
|
+
Bits1Type = Type.new(:bits, width: 1).freeze
|
|
984
|
+
Bits32Type = Type.new(:bits, width: 32).freeze
|
|
985
|
+
Bits64Type = Type.new(:bits, width: 64).freeze
|
|
986
|
+
BitsUnknownType = Type.new(:bits, width: :unknown).freeze
|
|
987
|
+
ConstBitsUnknownType = Type.new(:bits, width: :unknown, qualifiers: [:const]).freeze
|
|
988
|
+
ConstBoolType = Type.new(:boolean, qualifiers: [:const]).freeze
|
|
989
|
+
BoolType = Type.new(:boolean).freeze
|
|
990
|
+
VoidType = Type.new(:void).freeze
|
|
991
|
+
StringType = Type.new(:string).freeze
|
|
992
|
+
end
|