systemrdl 0.1.0

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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +127 -0
  4. data/lib/systemrdl/error.rb +55 -0
  5. data/lib/systemrdl/evaluator/address_allocation.rb +126 -0
  6. data/lib/systemrdl/evaluator/address_operation.rb +103 -0
  7. data/lib/systemrdl/evaluator/addrmap.rb +67 -0
  8. data/lib/systemrdl/evaluator/array_component.rb +42 -0
  9. data/lib/systemrdl/evaluator/builtin_properties.rb +400 -0
  10. data/lib/systemrdl/evaluator/common.rb +22 -0
  11. data/lib/systemrdl/evaluator/component_definition.rb +185 -0
  12. data/lib/systemrdl/evaluator/component_insts.rb +106 -0
  13. data/lib/systemrdl/evaluator/container_component.rb +16 -0
  14. data/lib/systemrdl/evaluator/field.rb +245 -0
  15. data/lib/systemrdl/evaluator/instance.rb +120 -0
  16. data/lib/systemrdl/evaluator/list.rb +26 -0
  17. data/lib/systemrdl/evaluator/literal.rb +173 -0
  18. data/lib/systemrdl/evaluator/operation.rb +241 -0
  19. data/lib/systemrdl/evaluator/processor.rb +166 -0
  20. data/lib/systemrdl/evaluator/property.rb +116 -0
  21. data/lib/systemrdl/evaluator/property_assignment.rb +220 -0
  22. data/lib/systemrdl/evaluator/reference.rb +135 -0
  23. data/lib/systemrdl/evaluator/reg.rb +156 -0
  24. data/lib/systemrdl/evaluator/regfile.rb +33 -0
  25. data/lib/systemrdl/evaluator/root.rb +39 -0
  26. data/lib/systemrdl/evaluator/value.rb +13 -0
  27. data/lib/systemrdl/evaluator.rb +14 -0
  28. data/lib/systemrdl/model/instance.rb +194 -0
  29. data/lib/systemrdl/model/value.rb +54 -0
  30. data/lib/systemrdl/model.rb +11 -0
  31. data/lib/systemrdl/parser/generated_parser.rb +2808 -0
  32. data/lib/systemrdl/parser/node.rb +17 -0
  33. data/lib/systemrdl/parser/parser.rb +86 -0
  34. data/lib/systemrdl/parser/scanner.rb +251 -0
  35. data/lib/systemrdl/parser/systemrdl.y +448 -0
  36. data/lib/systemrdl/parser/token.rb +58 -0
  37. data/lib/systemrdl/parser.rb +11 -0
  38. data/lib/systemrdl/version.rb +5 -0
  39. data/lib/systemrdl.rb +90 -0
  40. metadata +96 -0
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ module PropertyAssignmentCommon
6
+ def initialize(value, token_range)
7
+ super(token_range)
8
+ @value = value
9
+ end
10
+
11
+ def evaluate(instance, **optargs)
12
+ properties = find_properties(instance)
13
+ check_properties(instance, properties)
14
+
15
+ properties.each do |property|
16
+ value = eval_value(instance, property, **optargs)
17
+ assign_property(instance, property, value)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def check_properties(_instance, _properties)
24
+ end
25
+
26
+ def eval_value(instance, property, **optargs)
27
+ value =
28
+ if @value
29
+ @value.evaluate(instance, **optargs)
30
+ else
31
+ # true value is implicitly applied
32
+ # when the assignment value is omitted.
33
+ Value.new(true, :boolean, 1, @token_range)
34
+ end
35
+ check_value(property, value)
36
+
37
+ if match_integral_type?(property, value)
38
+ cast_integral_value(property, value)
39
+ else
40
+ value
41
+ end
42
+ end
43
+
44
+ def check_value(property, value)
45
+ check_type_compatibility(property, value)
46
+ end
47
+
48
+ def check_type_compatibility(property, value)
49
+ return if property.types.include?(value.type) || match_integral_type?(property, value)
50
+
51
+ message =
52
+ "#{value.type} type not supported by #{property.name} property: " \
53
+ "expected #{type_label(property)}"
54
+ raise_evaluation_error message, @token_range
55
+ end
56
+
57
+ def type_label(property)
58
+ types = property.types
59
+ if types.size == 1
60
+ types[0]
61
+ else
62
+ [types[..-2].join(', '), types[-1]].join(' or ')
63
+ end
64
+ end
65
+
66
+ def match_integral_type?(property, value)
67
+ integral_types = [:bit, :longint, :boolean]
68
+ return false unless integral_types.include?(value.type)
69
+
70
+ (integral_types & property.types).any?
71
+ end
72
+
73
+ def cast_integral_value(property, value)
74
+ if property.types.include?(:bit)
75
+ to_bit(value)
76
+ elsif property.types.include?(:longint)
77
+ to_longint(value)
78
+ else
79
+ to_boolean(value)
80
+ end
81
+ end
82
+
83
+ def to_bit(value)
84
+ return value if value.type == :bit
85
+
86
+ if value.type == :longint
87
+ Value.new(value.value, :bit, 64, value.token_range)
88
+ elsif value.value
89
+ Value.new(1, :bit, 1, value.token_range)
90
+ else
91
+ Value.new(0, :bit, 1, value.token_range)
92
+ end
93
+ end
94
+
95
+ def to_longint(value)
96
+ return value if value.type == :longint
97
+
98
+ if value.type == :bit
99
+ v = value.value & 0xFFFF_FFFF_FFFF_FFFF
100
+ Value.new(v, :longint, 64, value.token_range)
101
+ elsif value.value
102
+ Value.new(1, :longint, 64, value.token_range)
103
+ else
104
+ Value.new(0, :longint, 64, value.token_range)
105
+ end
106
+ end
107
+
108
+ def to_boolean(value)
109
+ return value if value.type == :boolean
110
+
111
+ Value.new(value.value != 0, :boolean, 1, value.token_range)
112
+ end
113
+ end
114
+
115
+ class PropertyAssignment
116
+ include Common
117
+ include PropertyAssignmentCommon
118
+
119
+ def initialize(prop_ref, value, token_range)
120
+ super(value, token_range)
121
+ @prop_ref = prop_ref
122
+ end
123
+
124
+ private
125
+
126
+ def find_properties(instance)
127
+ @prop_ref.find(instance, allow_array_ref: false)
128
+ end
129
+
130
+ def check_properties(_instance, properties)
131
+ property = properties[0]
132
+ return unless property&.assigned?
133
+
134
+ message = "#{property.name} already assigned in this scope"
135
+ raise_evaluation_error message, token_range
136
+ end
137
+
138
+ def assign_property(_instance, property, value)
139
+ property.assign(value)
140
+ end
141
+ end
142
+
143
+ class PostPropertyAssignment
144
+ include Common
145
+ include PropertyAssignmentCommon
146
+
147
+ def initialize(prop_ref, value, token_range)
148
+ super(value, token_range)
149
+ @prop_ref = prop_ref
150
+ end
151
+
152
+ private
153
+
154
+ def check_value(property, value)
155
+ super
156
+
157
+ check_ref_target(value)
158
+ end
159
+
160
+ def check_ref_target(value)
161
+ return if value.type != :property_reference
162
+
163
+ property = value.value
164
+ return if property.ref_target?
165
+
166
+ message = "reference to #{property.name} property not allowed"
167
+ raise_evaluation_error message, @token_range
168
+ end
169
+
170
+ def find_properties(instance)
171
+ @prop_ref.find(instance, allow_array_ref: true)
172
+ end
173
+
174
+ def check_properties(_instance, properties)
175
+ properties.each do |property|
176
+ next unless property
177
+
178
+ unless property.dynamic_assign?
179
+ message = "dynamic assignment to #{property.name} property not allowed"
180
+ raise_evaluation_error message, token_range
181
+ end
182
+
183
+ if !property.per_element_assign? && @prop_ref.array_select?
184
+ message = "element assignment to #{property.name} property not allowed"
185
+ raise_evaluation_error message, token_range
186
+ end
187
+ end
188
+ end
189
+
190
+ def assign_property(_instance, property, value)
191
+ property.assign(value)
192
+ end
193
+ end
194
+
195
+ class DefaultPropertyAssignment
196
+ include Common
197
+ include PropertyAssignmentCommon
198
+
199
+ def initialize(prop_name, value, token_range)
200
+ super(value, token_range)
201
+ @prop_name = prop_name
202
+ end
203
+
204
+ private
205
+
206
+ def find_properties(_instance)
207
+ prop_def = BuiltinProperties.find(@prop_name.value)
208
+ return [prop_def] if prop_def
209
+
210
+ message = "undefined property: #{@prop_name.value}"
211
+ raise_evaluation_error message, token_range
212
+ end
213
+
214
+ def assign_property(instance, _property, value)
215
+ definition = instance.definition
216
+ definition.assign_default_property(@prop_name.value, value, token_range)
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ class InstanceRefElement
6
+ include Common
7
+
8
+ def initialize(id, array, token_range)
9
+ super(token_range)
10
+ @id = id
11
+ @array = array
12
+ end
13
+
14
+ attr_reader :id
15
+ attr_reader :array
16
+
17
+ def find(base)
18
+ result = find_instance(base)
19
+ return result unless result.empty?
20
+
21
+ inst_name =
22
+ if array_select?
23
+ array
24
+ .elements
25
+ .inject([id.value]) { |elements, select| elements << "[#{select.value}]" }
26
+ .join
27
+ else
28
+ id.value.to_s
29
+ end
30
+ raise_evaluation_error "unresolvable instance: #{inst_name}", token_range
31
+ end
32
+
33
+ def array_select?
34
+ !array.nil?
35
+ end
36
+
37
+ private
38
+
39
+ def find_instance(base)
40
+ base.instances.select do |inst|
41
+ inst.name == id.value && match_array_indices?(inst)
42
+ end
43
+ end
44
+
45
+ def match_array_indices?(instance)
46
+ # non array instance && array select
47
+ return false if !instance.array? && array_select?
48
+
49
+ # non array instance or whole array
50
+ return true unless array_select?
51
+
52
+ # check size
53
+ return false if instance.array_indices.size != array.size
54
+
55
+ instance
56
+ .array_indices
57
+ .zip(array.elements)
58
+ .all? { |index, select| index == select.value }
59
+ end
60
+ end
61
+
62
+ class InstanceRef
63
+ include Common
64
+
65
+ def initialize(elements, token_range)
66
+ super(token_range)
67
+ @elements = elements
68
+ end
69
+
70
+ attr_reader :elements
71
+
72
+ def evaluate(instance, **_optargs)
73
+ find(instance, allow_array_ref: false)[0].to_value(token_range)
74
+ end
75
+
76
+ def find(instance, allow_array_ref: false)
77
+ result = @elements.inject([instance]) do |instances, element|
78
+ process_instance_ref_element(instances, element)
79
+ end
80
+
81
+ return result if allow_array_ref || result.size <= 1
82
+
83
+ message = 'reference to array instance not allowed'
84
+ raise_evaluation_error message, token_range
85
+ end
86
+
87
+ def array_select?
88
+ elements.any?(&:array_select?)
89
+ end
90
+
91
+ private
92
+
93
+ def process_instance_ref_element(instances, element)
94
+ instances.flat_map { |inst| element.find(inst) }
95
+ end
96
+ end
97
+
98
+ class PropRef
99
+ include Common
100
+
101
+ def initialize(instance_ref, prop, token_range)
102
+ super(token_range)
103
+ @instance_ref = instance_ref
104
+ @prop = prop
105
+ end
106
+
107
+ attr_reader :instance_ref
108
+ attr_reader :prop
109
+
110
+ def evaluate(instance, **_optargs)
111
+ find(instance, allow_array_ref: false)[0].to_value(token_range)
112
+ end
113
+
114
+ def find(instance, allow_array_ref: false)
115
+ insts =
116
+ if @instance_ref
117
+ @instance_ref.find(instance, allow_array_ref:)
118
+ else
119
+ [instance]
120
+ end
121
+
122
+ insts.map do |inst|
123
+ prop = inst.property(@prop.value)
124
+ next prop if prop
125
+
126
+ raise_evaluation_error "undefined property: #{@prop.value}", token_range
127
+ end
128
+ end
129
+
130
+ def array_select?
131
+ @instance_ref&.array_select? || false
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ class RegDefinition < ComponentDefinition
6
+ include AddressOperation
7
+ include ArrayComponent
8
+ include ContainerComponent
9
+
10
+ def validate(instance)
11
+ check_structural_component_instances(instance)
12
+ check_regwidth(instance)
13
+ check_accesswidth(instance)
14
+ check_overlapping_fields(instance)
15
+ check_fields_out_of_register(instance)
16
+ check_fields_spanning_sub_word_boundary(instance)
17
+ check_address_operations(instance)
18
+ end
19
+
20
+ def revalidate(instance)
21
+ check_accesswidth(instance)
22
+ check_fields_spanning_sub_word_boundary(instance)
23
+ check_address_operations(instance)
24
+ end
25
+
26
+ def layer
27
+ :reg
28
+ end
29
+
30
+ private
31
+
32
+ def instance_class
33
+ RegInstance
34
+ end
35
+
36
+ def apply_inst_values(instance, inst_values)
37
+ apply_address_operations(instance, inst_values)
38
+ check_range(inst_values)
39
+ end
40
+
41
+ def post_build(instance)
42
+ apply_default_accesswidth(instance)
43
+ end
44
+
45
+ def apply_default_accesswidth(instance)
46
+ property = instance.property(:accesswidth)
47
+ return if property.value
48
+
49
+ regwidth = instance.property_value(:regwidth)
50
+ property.assign(regwidth)
51
+ end
52
+
53
+ def check_regwidth(instance)
54
+ check_power_of_2(instance, :regwidth, 8)
55
+ end
56
+
57
+ def check_accesswidth(instance)
58
+ check_power_of_2(instance, :accesswidth, 8)
59
+
60
+ regwidth = instance.property_value(:regwidth)
61
+ accesswidth = instance.property_value(:accesswidth)
62
+ return if accesswidth.value <= regwidth.value
63
+
64
+ message = "accesswidth exceeds regwidth: accesswidth = #{accesswidth} regwidth = #{regwidth}"
65
+ raise_evaluation_error message, accesswidth.token_range, regwidth.token_range
66
+ end
67
+
68
+ def check_overlapping_fields(instance)
69
+ instance.instances.combination(2).each do |(field_a, field_b)|
70
+ next unless overlapping_field_pair?(field_a, field_b)
71
+
72
+ message = 'overlapping fields not allowed'
73
+ raise_evaluation_error message, field_a.token_range, field_b.token_range
74
+ end
75
+ end
76
+
77
+ def overlapping_field_pair?(field_a, field_b)
78
+ range_a = (field_a.lsb.value..field_a.msb.value)
79
+ range_b = (field_b.lsb.value..field_b.msb.value)
80
+ return false unless range_a.include?(range_b.begin) || range_b.include?(range_a.begin)
81
+
82
+ r_a = field_a.sw_readable?
83
+ w_a = field_a.sw_writable?
84
+ r_b = field_b.sw_readable?
85
+ w_b = field_b.sw_writable?
86
+ (r_a && r_b) || (w_a && w_b)
87
+ end
88
+
89
+ def check_fields_out_of_register(instance)
90
+ regwidth = instance.property_value(:regwidth).value
91
+ instance.instances.each do |field|
92
+ msb = field.msb.value
93
+ lsb = field.lsb.value
94
+ next if msb < regwidth
95
+
96
+ message = "field out of register: bit position [#{msb}:#{lsb}] regwidth #{regwidth}"
97
+ raise_evaluation_error message, field.token_range
98
+ end
99
+ end
100
+
101
+ def check_fields_spanning_sub_word_boundary(instance)
102
+ accesswidth = instance.property_value(:accesswidth).value
103
+ instance.instances.each do |field|
104
+ next unless field_with_side_effect?(field)
105
+
106
+ msb = field.msb.value
107
+ lsb = field.lsb.value
108
+ next if (msb / accesswidth) == (lsb / accesswidth)
109
+
110
+ message =
111
+ 'field spanning sub-word boundary not allowed: ' \
112
+ "bit position [#{msb}:#{lsb}] accesswidth #{accesswidth}"
113
+ raise_evaluation_error message, field.token_range
114
+ end
115
+ end
116
+
117
+ def field_with_side_effect?(field)
118
+ sw = field.property_value(:sw).value
119
+ return true if sw in :rw | :w
120
+
121
+ [:onread, :rclr, :rset]
122
+ .any? { |prop| field.property_value(prop)&.value }
123
+ end
124
+ end
125
+
126
+ class RegInstance < Instance
127
+ attr_accessor :address
128
+ attr_accessor :stride
129
+ attr_accessor :alignment
130
+
131
+ def definable?(definition)
132
+ definition.layer in :field
133
+ end
134
+
135
+ def instantiable?(definition)
136
+ definable?(definition)
137
+ end
138
+
139
+ def accesswidth
140
+ property_value(:accesswidth).value
141
+ end
142
+
143
+ def size
144
+ property_value(:regwidth).value / 8
145
+ end
146
+
147
+ def sw_readable?
148
+ instances.any?(&:sw_readable?)
149
+ end
150
+
151
+ def sw_writable?
152
+ instances.any?(&:sw_writable?)
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ class RegFileDefinition < ComponentDefinition
6
+ include ContainerComponent
7
+
8
+ def validate(instance)
9
+ check_structural_component_instances(instance)
10
+ end
11
+
12
+ def layer
13
+ :regfile
14
+ end
15
+
16
+ private
17
+
18
+ def instance_class
19
+ RegFileInstance
20
+ end
21
+ end
22
+
23
+ class RegFileInstance < Instance
24
+ def definable?(definition)
25
+ definition.layer in :regfile | :reg | :field
26
+ end
27
+
28
+ def instantiable?(definition)
29
+ definition.layer in :regfile | :reg
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ class Root < ComponentDefinition
6
+ def layer
7
+ :root
8
+ end
9
+
10
+ def initialize(elements, token_range)
11
+ super(Value.new(:root, nil, nil, nil), elements, nil, token_range)
12
+ connect(nil, nil)
13
+ end
14
+
15
+ def evaluate(instance, **optargs)
16
+ inherit(instance) if instance&.root?
17
+ root = create_instance(nil, :root, nil, nil, nil, **optargs)
18
+ root.finalize
19
+ root
20
+ end
21
+
22
+ private
23
+
24
+ def instance_class
25
+ RootInstance
26
+ end
27
+
28
+ def inherit(instance)
29
+ definitions.merge!(instance.definition.definitions)
30
+ end
31
+ end
32
+
33
+ class RootInstance < Instance
34
+ def definable?(_definition)
35
+ true
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ Value = Data.define(:value, :type, :width, :token_range) do
6
+ def to_s
7
+ value.to_s
8
+ end
9
+ end
10
+
11
+ Values = Data.define(:values, :token_range)
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ def self.evaluate(ast, root = nil, **optargs)
6
+ evaluator = build_evaluator(ast)
7
+ evaluator.evaluate(root, **optargs)
8
+ end
9
+
10
+ def self.build_evaluator(ast)
11
+ Processor.new.process(ast)
12
+ end
13
+ end
14
+ end