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,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ module ContainerComponent
6
+ private
7
+
8
+ def check_structural_component_instances(instance)
9
+ return if instance.instances.any?(&:structural_component?)
10
+
11
+ message = "no structural component instances within #{layer}"
12
+ raise_evaluation_error message, instance.token_range
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,245 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ class FieldDefinition < ComponentDefinition
6
+ def validate(instance)
7
+ check_fieldwidth(instance)
8
+ check_reset(instance)
9
+ check_sw_hw_access_combination(instance)
10
+ check_onread_exclusivity(instance)
11
+ check_sw_read_access_required(instance)
12
+ check_onwrite_exclusivity(instance)
13
+ check_sw_write_access_required(instance)
14
+ check_swwe_swwel_exclusivity(instance)
15
+ check_we_wel_exclusivity(instance)
16
+ check_we_required(instance)
17
+ end
18
+
19
+ def revalidate(instance)
20
+ check_reset(instance)
21
+ check_sw_hw_access_combination(instance)
22
+ check_onread_exclusivity(instance)
23
+ check_sw_read_access_required(instance)
24
+ check_onwrite_exclusivity(instance)
25
+ check_sw_write_access_required(instance)
26
+ check_swwe_swwel_exclusivity(instance)
27
+ check_we_wel_exclusivity(instance)
28
+ check_we_required(instance)
29
+ end
30
+
31
+ def layer
32
+ :field
33
+ end
34
+
35
+ private
36
+
37
+ def instance_class
38
+ FieldInstance
39
+ end
40
+
41
+ def apply_inst_values(instance, inst_values)
42
+ assign_bit_pos(instance, inst_values)
43
+ apply_reset_value(instance, inst_values)
44
+ check_address_allocation_operator(inst_values)
45
+ end
46
+
47
+ def assign_bit_pos(instance, inst_values)
48
+ msb, lsb =
49
+ if (range = inst_values[:range])
50
+ range.elements
51
+ else
52
+ calc_bit_pos(instance, inst_values)
53
+ end
54
+ instance.msb = msb
55
+ instance.lsb = lsb
56
+ end
57
+
58
+ def calc_bit_pos(instance, inst_values)
59
+ width = calc_bit_width(instance, inst_values)
60
+ last_msb = instance.parent.instances.last&.msb
61
+ lsb = (last_msb&.value || -1) + 1
62
+ msb = lsb + (width&.value || 1) - 1
63
+ [msb, lsb].map { |pos| Value.new(pos, :bit, 64, width&.token_range) }
64
+ end
65
+
66
+ def calc_bit_width(instance, inst_values)
67
+ size = inst_values[:array]
68
+ return instance.property_value(:fieldwidth) unless size
69
+
70
+ if size.size >= 2
71
+ message = 'multidimensional size specification not allowed for field'
72
+ raise_evaluation_error message, size.token_range
73
+ end
74
+
75
+ size = size.elements[0]
76
+ if size.value == 0
77
+ message = 'bit width must be positive'
78
+ raise_evaluation_error message, size.token_range
79
+ end
80
+
81
+ size
82
+ end
83
+
84
+ def check_fieldwidth(instance)
85
+ fieldwidth = instance.property_value(:fieldwidth)
86
+ return unless fieldwidth
87
+
88
+ if fieldwidth.value == 0
89
+ message = 'fieldwidth must be positive'
90
+ raise_evaluation_error message, fieldwidth.token_range
91
+ end
92
+
93
+ msb = instance.msb
94
+ lsb = instance.lsb
95
+ width = msb.value - lsb.value + 1
96
+ return if width == fieldwidth.value
97
+
98
+ message = "bit width mismatch: instance width #{width} fieldwidth property #{fieldwidth}"
99
+ raise_evaluation_error message, msb.token_range, lsb.token_range
100
+ end
101
+
102
+ def apply_reset_value(instance, inst_values)
103
+ value = inst_values[:reset_value]
104
+ return unless value
105
+
106
+ property = instance.property(:reset)
107
+ property.assign(value)
108
+ end
109
+
110
+ def check_reset(instance)
111
+ reset_value = instance.property_value(:reset)
112
+ return unless reset_value
113
+
114
+ if reset_value.type in :field_reference | :property_reference
115
+ # TODO
116
+ # check width of the specified instance or property
117
+ else
118
+ check_reset_value(instance, reset_value)
119
+ end
120
+ end
121
+
122
+ def check_reset_value(instance, reset_value)
123
+ width = instance.msb.value - instance.lsb.value + 1
124
+ range = 0..((2**width) - 1)
125
+ return if range.include?(reset_value.value)
126
+
127
+ message =
128
+ format(
129
+ 'reset value out of range: value 0x%<reset_value>x range 0x%<begin>x..0x%<end>x',
130
+ reset_value: reset_value.value, begin: range.begin, end: range.end
131
+ )
132
+ raise_evaluation_error message, reset_value.token_range
133
+ end
134
+
135
+ def check_address_allocation_operator(inst_values)
136
+ [:address_assignment, :address_stride, :address_alignment].each do |op|
137
+ value = inst_values[op]
138
+ next unless value
139
+
140
+ message = 'address allocation operator not allowed for field instance'
141
+ raise_evaluation_error message, value.token_range
142
+ end
143
+ end
144
+
145
+ def check_sw_hw_access_combination(instance)
146
+ sw = instance.property_value(:sw)
147
+ hw = instance.property_value(:hw)
148
+
149
+ combination = [sw.value, hw.value]
150
+ return unless combination in [:w, :w] | [:w, :na] | [:na, *]
151
+
152
+ message = "invalid sw/hw access combination: sw = #{sw} hw = #{hw}"
153
+ raise_evaluation_error message, sw.token_range, hw.token_range
154
+ end
155
+
156
+ def check_onread_exclusivity(instance)
157
+ check_property_exclusivity(instance, [:onread, :rclr, :rset])
158
+ end
159
+
160
+ def check_sw_read_access_required(instance)
161
+ kind, onread = {
162
+ onread: instance.property_value(:onread),
163
+ rclr: instance.property_value(:rclr),
164
+ rset: instance.property_value(:rset)
165
+ }.find { |_, v| v&.value }
166
+
167
+ return unless onread
168
+
169
+ sw = instance.property_value(:sw)
170
+ return if sw.value in :rw | :r
171
+
172
+ onread_normalized = (kind == :onread && onread.value) || kind
173
+ message = "sw read access required: onread = #{onread_normalized} sw = #{sw}"
174
+ raise_evaluation_error message, onread.token_range, sw.token_range
175
+ end
176
+
177
+ def check_onwrite_exclusivity(instance)
178
+ check_property_exclusivity(instance, [:onwrite, :woset, :woclr])
179
+ end
180
+
181
+ def check_sw_write_access_required(instance)
182
+ kind, onwrite = {
183
+ onwrite: instance.property_value(:onwrite),
184
+ woset: instance.property_value(:woset),
185
+ woclr: instance.property_value(:woclr)
186
+ }.find { |(_, v)| v&.value }
187
+
188
+ return unless onwrite
189
+
190
+ sw = instance.property_value(:sw)
191
+ return if sw.value in :rw | :w
192
+
193
+ onwrite_normalized = (kind == :onwrite && onwrite.value) || kind
194
+ message = "sw write access required: onwrite = #{onwrite_normalized} sw = #{sw}"
195
+ raise_evaluation_error message, onwrite.token_range, sw.token_range
196
+ end
197
+
198
+ def check_swwe_swwel_exclusivity(instance)
199
+ check_property_exclusivity(instance, [:swwe, :swwel])
200
+ end
201
+
202
+ def check_we_wel_exclusivity(instance)
203
+ check_property_exclusivity(instance, [:we, :wel])
204
+ end
205
+
206
+ def check_we_required(instance)
207
+ sw = instance.property_value(:sw)
208
+ return if sw.value == :r
209
+
210
+ hw = instance.property_value(:hw)
211
+ return if hw.value in :r | :na
212
+
213
+ we = instance.property_value(:we)
214
+ return if we.value
215
+
216
+ wel = instance.property_value(:wel)
217
+ return if wel.value
218
+
219
+ message = "hw write enable required: sw = #{sw} hw = #{hw}"
220
+ raise_evaluation_error message, sw.token_range, hw.token_range
221
+ end
222
+ end
223
+
224
+ class FieldInstance < Instance
225
+ attr_accessor :msb
226
+ attr_accessor :lsb
227
+
228
+ def definable?(_definition)
229
+ false
230
+ end
231
+
232
+ def instantiable?(_definition)
233
+ false
234
+ end
235
+
236
+ def sw_readable?
237
+ property_value(:sw).value in :rw | :rw1 | :r
238
+ end
239
+
240
+ def sw_writable?
241
+ property_value(:sw).value in :rw | :rw1 | :w | :w1
242
+ end
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ class Instance
6
+ def initialize(definition, parent, name, array_info, token_range)
7
+ @definition = definition
8
+ @parent = parent
9
+ @name = name
10
+ @array_info = array_info
11
+ @token_range = token_range
12
+ @properties = []
13
+ @instances = []
14
+ end
15
+
16
+ attr_reader :definition
17
+ attr_reader :parent
18
+ attr_reader :name
19
+ attr_reader :array_info
20
+ attr_reader :token_range
21
+ attr_reader :properties
22
+ attr_reader :instances
23
+
24
+ def to_value(token_range)
25
+ Value.new(self, :"#{layer}_reference", nil, token_range)
26
+ end
27
+
28
+ def element_name
29
+ return name.to_s unless array?
30
+
31
+ array_info
32
+ .indices
33
+ .inject([name]) { |name_elements, index| name_elements << "[#{index}]" }
34
+ .join
35
+ end
36
+
37
+ def full_name
38
+ elements = [self]
39
+ current = parent
40
+ until current.root?
41
+ elements.unshift(current)
42
+ current = current.parent
43
+ end
44
+
45
+ elements.map(&:element_name).join('.')
46
+ end
47
+
48
+ def layer
49
+ definition.layer
50
+ end
51
+
52
+ def root?
53
+ layer == :root
54
+ end
55
+
56
+ def addrmap?
57
+ layer == :addrmap
58
+ end
59
+
60
+ def regfile?
61
+ layer == :regfile
62
+ end
63
+
64
+ def reg?
65
+ layer == :reg
66
+ end
67
+
68
+ def field?
69
+ layer == :field
70
+ end
71
+
72
+ def structural_component?
73
+ addrmap? || regfile? || reg? || field?
74
+ end
75
+
76
+ def array?
77
+ !array_info.nil?
78
+ end
79
+
80
+ def array_indices
81
+ array_info&.indices
82
+ end
83
+
84
+ def array_sizes
85
+ array_info&.sizes
86
+ end
87
+
88
+ def first_element?
89
+ !array? || array_info.first
90
+ end
91
+
92
+ def last_element?
93
+ !array? || array_info.last
94
+ end
95
+
96
+ def property(name)
97
+ properties.find { |prop| prop.name == name }
98
+ end
99
+
100
+ def property_value(name)
101
+ property(name)&.value
102
+ end
103
+
104
+ def validate
105
+ @definition.validate(self)
106
+ @instances.each(&:revalidate)
107
+ end
108
+
109
+ def revalidate
110
+ @definition.revalidate(self)
111
+ @instances.each(&:revalidate)
112
+ end
113
+
114
+ def finalize
115
+ @definition.finalize(self)
116
+ @instances.each(&:finalize)
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ class List
6
+ include Common
7
+
8
+ def initialize(elements, token_range)
9
+ @elements = elements
10
+ @token_range = token_range
11
+ end
12
+
13
+ attr_reader :elements
14
+ attr_reader :token_range
15
+
16
+ def evaluate(instance, **optargs)
17
+ elements = @elements.map { |element| element.evaluate(instance, **optargs) }
18
+ List.new(elements, @token_range)
19
+ end
20
+
21
+ def size
22
+ @elements.size
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SystemRDL
4
+ module Evaluator
5
+ class Literal
6
+ include Common
7
+
8
+ def initialize(node)
9
+ super(node.token_range)
10
+ @node = node
11
+ evaluate_literal
12
+ end
13
+
14
+ attr_reader :value
15
+
16
+ def evaluate(_instance, **_optargs)
17
+ @evaluated ||= Value.new(value, type, width, token_range)
18
+ end
19
+
20
+ def expression_width
21
+ width
22
+ end
23
+
24
+ def token_range
25
+ @node.token_range
26
+ end
27
+
28
+ private
29
+
30
+ def width
31
+ end
32
+
33
+ def token
34
+ @node.children[0]
35
+ end
36
+
37
+ def text
38
+ token.text
39
+ end
40
+ end
41
+
42
+ class Boolean < Literal
43
+ private
44
+
45
+ def type
46
+ :boolean
47
+ end
48
+
49
+ def width
50
+ 1
51
+ end
52
+
53
+ def evaluate_literal
54
+ @value = text == 'true'
55
+ end
56
+ end
57
+
58
+ class Number < Literal
59
+ private
60
+
61
+ def type
62
+ :bit
63
+ end
64
+
65
+ def width
66
+ 64
67
+ end
68
+
69
+ def evaluate_literal
70
+ @value = Integer(text)
71
+ end
72
+ end
73
+
74
+ class VerilogNumber < Literal
75
+ private
76
+
77
+ attr_reader :width
78
+
79
+ def type
80
+ :bit
81
+ end
82
+
83
+ def evaluate_literal
84
+ match_data, base =
85
+ case text.tr('_', '')
86
+ when Parser::Scanner::VERILOG_HEX_NUMBER then [Regexp.last_match, 16]
87
+ when Parser::Scanner::VERILOG_DEC_NUMBER then [Regexp.last_match, 10]
88
+ when Parser::Scanner::VERILOG_BIN_NUMBER then [Regexp.last_match, 2]
89
+ end
90
+ @width = match_data.captures[0].to_i
91
+ @value = match_data.captures[1].to_i(base)
92
+
93
+ check_bit_width(@value, @width)
94
+ end
95
+
96
+ def check_bit_width(value, width)
97
+ return if value.bit_length <= width
98
+
99
+ message = "value of number does not fit within the specified bit width: #{text}"
100
+ raise_evaluation_error(message, token_range)
101
+ end
102
+ end
103
+
104
+ class String < Literal
105
+ private
106
+
107
+ def type
108
+ :string
109
+ end
110
+
111
+ def evaluate_literal
112
+ @value = text[1..-2]
113
+ end
114
+ end
115
+
116
+ class EnumLiteral < Literal
117
+ private
118
+
119
+ def evaluate_literal
120
+ @value = text.to_sym
121
+ end
122
+ end
123
+
124
+ class AccessType < EnumLiteral
125
+ private
126
+
127
+ def type
128
+ :accesstype
129
+ end
130
+
131
+ def evaluate_literal
132
+ @value =
133
+ if ['rw', 'wr'].include?(text)
134
+ :rw
135
+ else
136
+ super
137
+ end
138
+ end
139
+ end
140
+
141
+ class OnReadType < EnumLiteral
142
+ private
143
+
144
+ def type
145
+ :onreadtype
146
+ end
147
+ end
148
+
149
+ class OnWriteType < EnumLiteral
150
+ private
151
+
152
+ def type
153
+ :onwritetype
154
+ end
155
+ end
156
+
157
+ class AddressingType < EnumLiteral
158
+ private
159
+
160
+ def type
161
+ :addressingtype
162
+ end
163
+ end
164
+
165
+ class PrecedenceType < EnumLiteral
166
+ private
167
+
168
+ def type
169
+ :precedencetype
170
+ end
171
+ end
172
+ end
173
+ end