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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +127 -0
- data/lib/systemrdl/error.rb +55 -0
- data/lib/systemrdl/evaluator/address_allocation.rb +126 -0
- data/lib/systemrdl/evaluator/address_operation.rb +103 -0
- data/lib/systemrdl/evaluator/addrmap.rb +67 -0
- data/lib/systemrdl/evaluator/array_component.rb +42 -0
- data/lib/systemrdl/evaluator/builtin_properties.rb +400 -0
- data/lib/systemrdl/evaluator/common.rb +22 -0
- data/lib/systemrdl/evaluator/component_definition.rb +185 -0
- data/lib/systemrdl/evaluator/component_insts.rb +106 -0
- data/lib/systemrdl/evaluator/container_component.rb +16 -0
- data/lib/systemrdl/evaluator/field.rb +245 -0
- data/lib/systemrdl/evaluator/instance.rb +120 -0
- data/lib/systemrdl/evaluator/list.rb +26 -0
- data/lib/systemrdl/evaluator/literal.rb +173 -0
- data/lib/systemrdl/evaluator/operation.rb +241 -0
- data/lib/systemrdl/evaluator/processor.rb +166 -0
- data/lib/systemrdl/evaluator/property.rb +116 -0
- data/lib/systemrdl/evaluator/property_assignment.rb +220 -0
- data/lib/systemrdl/evaluator/reference.rb +135 -0
- data/lib/systemrdl/evaluator/reg.rb +156 -0
- data/lib/systemrdl/evaluator/regfile.rb +33 -0
- data/lib/systemrdl/evaluator/root.rb +39 -0
- data/lib/systemrdl/evaluator/value.rb +13 -0
- data/lib/systemrdl/evaluator.rb +14 -0
- data/lib/systemrdl/model/instance.rb +194 -0
- data/lib/systemrdl/model/value.rb +54 -0
- data/lib/systemrdl/model.rb +11 -0
- data/lib/systemrdl/parser/generated_parser.rb +2808 -0
- data/lib/systemrdl/parser/node.rb +17 -0
- data/lib/systemrdl/parser/parser.rb +86 -0
- data/lib/systemrdl/parser/scanner.rb +251 -0
- data/lib/systemrdl/parser/systemrdl.y +448 -0
- data/lib/systemrdl/parser/token.rb +58 -0
- data/lib/systemrdl/parser.rb +11 -0
- data/lib/systemrdl/version.rb +5 -0
- data/lib/systemrdl.rb +90 -0
- metadata +96 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: ef8e253b49ef4971248d9e4ad7b1938ff69952613de40fb985e993653ebd37f2
|
|
4
|
+
data.tar.gz: f7c11c7334b79e9c93e81a5b2ccc211d15c3e7991ca514385f3525deb9316bd8
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 60382cdccb4df5c4d9df37a988e0d62d0986c7d2bb7de98add2f706f93349f57e4b0783f2f1660ccb039c7f463c3cfb03b439c2d5429a535063f8344743a152f
|
|
7
|
+
data.tar.gz: 766461e671109a8813e5a39a4f5a4cdd640ebdc2c32de76a31969404317a709aa7a52fbc580ec42229317ecae4fe98f1c7c9ac326c686df70eb4cf42e6146acc
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Taichi Ishitani
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
[](https://badge.fury.io/rb/systemrdl)
|
|
2
|
+
[](https://github.com/taichi-ishitani/systemrdl/actions/workflows/regression.yml)
|
|
3
|
+
|
|
4
|
+
[](https://ko-fi.com/A0A231E3I)
|
|
5
|
+
|
|
6
|
+
# SystemRDL
|
|
7
|
+
|
|
8
|
+
A SystemRDL 2.0 front-end for Ruby.
|
|
9
|
+
It parses SystemRDL source, elaborates the described register model, and exposes it as plain Ruby objects so that back-end tools can generate RTL, documentation, software headers, and so on.
|
|
10
|
+
|
|
11
|
+
SystemRDL is a register description language standardized by [Accellera](https://www.accellera.org/activities/working-groups/systemrdl).
|
|
12
|
+
This gem targets the [SystemRDL 2.0 specification](https://www.accellera.org/images/downloads/standards/systemrdl/SystemRDL_2.0_Jan2018.pdf).
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
Install the gem and add it to the application's Gemfile by executing:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
bundle add systemrdl
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
gem install systemrdl
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Compiling SystemRDL
|
|
31
|
+
|
|
32
|
+
Use the methods below to compile SystemRDL into an elaborated model.
|
|
33
|
+
Each method returns a list of the top-level address maps.
|
|
34
|
+
|
|
35
|
+
* Compile SystemRDL read from the given file path(s)
|
|
36
|
+
* `SystemRDL.compile`
|
|
37
|
+
* Compile SystemRDL read from the given input stream(s)
|
|
38
|
+
* `SystemRDL.compile_streams`
|
|
39
|
+
* Compile the given SystemRDL source string
|
|
40
|
+
* `SystemRDL.compile_source`
|
|
41
|
+
|
|
42
|
+
`SystemRDL.compile` and `SystemRDL.compile_streams` accept multiple inputs.
|
|
43
|
+
The inputs are compiled in the given order and share their component definitions, so a component defined in an earlier input can be instantiated in a later one.
|
|
44
|
+
Note that this sharing is one-directional; an earlier input cannot refer to a component defined in a later one.
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
require 'systemrdl'
|
|
48
|
+
|
|
49
|
+
# Compile files
|
|
50
|
+
address_maps = SystemRDL.compile('gpio.rdl', 'pwm.rdl')
|
|
51
|
+
|
|
52
|
+
# Compile a source string
|
|
53
|
+
address_maps = SystemRDL.compile_source(<<~'RDL')
|
|
54
|
+
addrmap my_map {
|
|
55
|
+
reg {
|
|
56
|
+
field { sw = rw; hw = r; reset = 0x0; } value[32];
|
|
57
|
+
} data;
|
|
58
|
+
};
|
|
59
|
+
RDL
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Accessing the model
|
|
63
|
+
|
|
64
|
+
An elaborated model is a tree of address maps, registers, and fields.
|
|
65
|
+
Each element carries the properties assigned to it in the source.
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
require 'systemrdl'
|
|
69
|
+
|
|
70
|
+
address_map = SystemRDL.compile_source(<<~'RDL').first
|
|
71
|
+
addrmap gpio {
|
|
72
|
+
name = "GPIO";
|
|
73
|
+
desc = "Simple general purpose I/O controller";
|
|
74
|
+
|
|
75
|
+
default sw = rw;
|
|
76
|
+
default hw = r;
|
|
77
|
+
|
|
78
|
+
reg {
|
|
79
|
+
name = "Port Direction";
|
|
80
|
+
field { desc = "0: input, 1: output"; reset = 0x0; } dir[32];
|
|
81
|
+
} direction;
|
|
82
|
+
|
|
83
|
+
reg {
|
|
84
|
+
name = "Input Data";
|
|
85
|
+
field { sw = r; hw = w; } value[32];
|
|
86
|
+
} data_in;
|
|
87
|
+
};
|
|
88
|
+
RDL
|
|
89
|
+
|
|
90
|
+
# GPIO: Simple general purpose I/O controller
|
|
91
|
+
puts "#{address_map.display_name}: #{address_map.desc}"
|
|
92
|
+
|
|
93
|
+
address_map.regs.each do |reg|
|
|
94
|
+
# direction @ 0x0
|
|
95
|
+
# data_in @ 0x4
|
|
96
|
+
puts "#{reg.name} @ 0x#{reg.address.to_s(16)}"
|
|
97
|
+
|
|
98
|
+
reg.fields.each do |field|
|
|
99
|
+
# dir [31:0] sw=rw hw=r
|
|
100
|
+
# value [31:0] sw=r hw=w
|
|
101
|
+
puts " #{field.name} [#{field.msb}:#{field.lsb}] sw=#{field.sw} hw=#{field.hw}"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Scope
|
|
107
|
+
|
|
108
|
+
This gem currently supports only the basic syntax needed to describe register maps that consist of address maps, registers, and fields.
|
|
109
|
+
More advanced constructs of the SystemRDL language are not supported yet.
|
|
110
|
+
|
|
111
|
+
## Design notes
|
|
112
|
+
|
|
113
|
+
The design decisions behind this implementation, along with their rationale, are documented under the [`notes`](notes) directory.
|
|
114
|
+
These notes focus on parts of the SystemRDL specification that are open to interpretation or left unspecified, and explain how this implementation resolves them.
|
|
115
|
+
|
|
116
|
+
## Contributing
|
|
117
|
+
|
|
118
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/taichi-ishitani/systemrdl.
|
|
119
|
+
|
|
120
|
+
* [Issue Tracker](https://github.com/taichi-ishitani/systemrdl/issues)
|
|
121
|
+
* [Pull Request](https://github.com/taichi-ishitani/systemrdl/pulls)
|
|
122
|
+
* [Discussion](https://github.com/taichi-ishitani/systemrdl/discussions)
|
|
123
|
+
|
|
124
|
+
## Copyright & License
|
|
125
|
+
|
|
126
|
+
Copyright © 2026 Taichi Ishitani.
|
|
127
|
+
SystemRDL is licensed under the terms of the [MIT License](https://opensource.org/licenses/MIT), see [LICENSE.txt](LICENSE.txt) for further details.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SystemRDL
|
|
4
|
+
class Error < StandardError
|
|
5
|
+
def initialize(message)
|
|
6
|
+
super
|
|
7
|
+
@error_message = message
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
attr_reader :error_message
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class ParseError < Error
|
|
14
|
+
def initialize(message, position)
|
|
15
|
+
super(message)
|
|
16
|
+
@position = position
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
attr_reader :position
|
|
20
|
+
|
|
21
|
+
def to_s
|
|
22
|
+
(@position && "#{super} -- #{@position}") || super
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
module RaiseParseError
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def raise_parse_error(message, position)
|
|
30
|
+
raise ParseError.new(message, position)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class EvaluationError < Error
|
|
35
|
+
def initialize(message, *token_ranges)
|
|
36
|
+
super(message)
|
|
37
|
+
@token_ranges = token_ranges.compact
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
attr_reader :token_ranges
|
|
41
|
+
|
|
42
|
+
def to_s
|
|
43
|
+
position = token_ranges.first&.head&.position
|
|
44
|
+
(position && "#{super} -- #{position}") || super
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
module RaiseEvaluationError
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def raise_evaluation_error(message, *token_ranges)
|
|
52
|
+
raise EvaluationError.new(message, *token_ranges)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SystemRDL
|
|
4
|
+
module Evaluator
|
|
5
|
+
module AddressAllocation
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def allocate_addresses(instance)
|
|
9
|
+
address = 0
|
|
10
|
+
instance.instances.each do |child_inst|
|
|
11
|
+
# For now, support reg only
|
|
12
|
+
next unless child_inst.reg?
|
|
13
|
+
|
|
14
|
+
assign_address(address, instance, child_inst)
|
|
15
|
+
address = calc_next_address(child_inst)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def assign_address(current_address, inst, child_inst)
|
|
20
|
+
if child_inst.first_element?
|
|
21
|
+
child_inst.address ||= begin
|
|
22
|
+
alignment = calc_alignment(inst, child_inst)
|
|
23
|
+
address = roundup(current_address, alignment)
|
|
24
|
+
Value.new(address, :bit, 64, nil)
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
# Array non-head elements carry a copy of the head's @ address at this point;
|
|
28
|
+
# overwrite with the stride-accumulated address for this element.
|
|
29
|
+
child_inst.address = Value.new(current_address, :bit, 64, nil)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def calc_alignment(inst, child_inst)
|
|
34
|
+
inst_alignment = child_inst.alignment&.value
|
|
35
|
+
return inst_alignment if inst_alignment
|
|
36
|
+
|
|
37
|
+
alignments = [
|
|
38
|
+
inst.property_value(:alignment)&.value || 0,
|
|
39
|
+
child_inst.accesswidth / 8,
|
|
40
|
+
alignment_by_addressing(inst, child_inst)
|
|
41
|
+
]
|
|
42
|
+
alignments.max
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def alignment_by_addressing(inst, child_inst)
|
|
46
|
+
addressing = inst.property_value(:addressing).value
|
|
47
|
+
case addressing
|
|
48
|
+
when :compact then child_inst.accesswidth / 8
|
|
49
|
+
when :regalign then aligned_size(child_inst)
|
|
50
|
+
when :fullalign then calc_fullalign_alignment(child_inst)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def calc_fullalign_alignment(child_inst)
|
|
55
|
+
return aligned_size(child_inst) unless child_inst.array?
|
|
56
|
+
|
|
57
|
+
array_size = calc_occupied_size(child_inst)
|
|
58
|
+
if power_of_2?(array_size, 1)
|
|
59
|
+
array_size
|
|
60
|
+
else
|
|
61
|
+
2**array_size.bit_length
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def calc_next_address(child_inst)
|
|
66
|
+
delta =
|
|
67
|
+
if child_inst.last_element?
|
|
68
|
+
child_inst.size
|
|
69
|
+
else
|
|
70
|
+
element_stride(child_inst)
|
|
71
|
+
end
|
|
72
|
+
child_inst.address.value + delta
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def check_overlapping_regs(instance)
|
|
76
|
+
# For now, support reg only but not regfile
|
|
77
|
+
regs = instance.instances.select { |reg| reg.reg? && reg.first_element? }
|
|
78
|
+
regs.combination(2).each do |(reg_a, reg_b)|
|
|
79
|
+
next unless overlapping_pair?(reg_a, reg_b)
|
|
80
|
+
|
|
81
|
+
message = 'overlapping regs not allowed'
|
|
82
|
+
raise_evaluation_error message, reg_a.token_range, reg_b.token_range
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def overlapping_pair?(reg_a, reg_b)
|
|
87
|
+
range_a = calc_address_range(reg_a)
|
|
88
|
+
range_b = calc_address_range(reg_b)
|
|
89
|
+
return false unless range_a.include?(range_b.begin) || range_b.include?(range_a.begin)
|
|
90
|
+
|
|
91
|
+
r_a = reg_a.sw_readable?
|
|
92
|
+
w_a = reg_a.sw_writable?
|
|
93
|
+
r_b = reg_b.sw_readable?
|
|
94
|
+
w_b = reg_b.sw_writable?
|
|
95
|
+
(r_a && r_b) || (w_a && w_b)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def calc_address_range(child_inst)
|
|
99
|
+
base = child_inst.address.value
|
|
100
|
+
size = calc_occupied_size(child_inst)
|
|
101
|
+
base...(base + size)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def roundup(dividend, divisor)
|
|
105
|
+
divisor * dividend.ceildiv(divisor)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def aligned_size(child_inst)
|
|
109
|
+
roundup(child_inst.size, child_inst.accesswidth / 8)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def calc_occupied_size(child_inst)
|
|
113
|
+
if child_inst.array?
|
|
114
|
+
n_elements = child_inst.array_info.n_elements
|
|
115
|
+
((n_elements - 1) * element_stride(child_inst)) + child_inst.size
|
|
116
|
+
else
|
|
117
|
+
child_inst.size
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def element_stride(child_inst)
|
|
122
|
+
child_inst.stride&.value || aligned_size(child_inst)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SystemRDL
|
|
4
|
+
module Evaluator
|
|
5
|
+
module AddressOperation
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def apply_explicit_address(instance, inst_values)
|
|
9
|
+
address = inst_values[:address_assignment]
|
|
10
|
+
return unless address
|
|
11
|
+
|
|
12
|
+
instance.address = address
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def apply_stride(instance, inst_values)
|
|
16
|
+
stride = inst_values[:address_stride]
|
|
17
|
+
return unless stride
|
|
18
|
+
|
|
19
|
+
unless instance.array?
|
|
20
|
+
message = "address stride not allowed for scalar #{layer} instance"
|
|
21
|
+
raise_evaluation_error message, stride.token_range
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
instance.stride = stride
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def apply_alignment(instance, inst_values)
|
|
28
|
+
alignment = inst_values[:address_alignment]
|
|
29
|
+
return unless alignment
|
|
30
|
+
|
|
31
|
+
instance.alignment = alignment
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def apply_address_operations(instance, inst_values)
|
|
35
|
+
apply_explicit_address(instance, inst_values)
|
|
36
|
+
apply_stride(instance, inst_values)
|
|
37
|
+
apply_alignment(instance, inst_values)
|
|
38
|
+
|
|
39
|
+
return unless instance.address && instance.alignment
|
|
40
|
+
|
|
41
|
+
message = '@ and %= address operations are mutually exclusive'
|
|
42
|
+
raise_evaluation_error message, instance.address.token_range, instance.alignment.token_range
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def check_range(inst_values)
|
|
46
|
+
range = inst_values[:range]
|
|
47
|
+
return unless range
|
|
48
|
+
|
|
49
|
+
message = "range not allowed for #{layer} instance"
|
|
50
|
+
raise_evaluation_error message, range.token_range
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def check_accesswidth_boundary(instance, label, value)
|
|
54
|
+
return unless value
|
|
55
|
+
|
|
56
|
+
accesswidth = instance.accesswidth
|
|
57
|
+
return if (value.value % (accesswidth / 8)) == 0
|
|
58
|
+
|
|
59
|
+
message =
|
|
60
|
+
"#{label} not aligned to accesswidth: " \
|
|
61
|
+
"#{label} 0x#{value.value.to_s(16)} accesswidth #{accesswidth}"
|
|
62
|
+
raise_evaluation_error message, value.token_range
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def check_address(instance)
|
|
66
|
+
check_accesswidth_boundary(instance, :address, instance.address)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def check_stride(instance)
|
|
70
|
+
stride = instance.stride
|
|
71
|
+
return unless stride
|
|
72
|
+
|
|
73
|
+
check_accesswidth_boundary(instance, :stride, stride)
|
|
74
|
+
|
|
75
|
+
size = instance.size
|
|
76
|
+
return if stride.value >= size
|
|
77
|
+
|
|
78
|
+
message =
|
|
79
|
+
"stride less than #{instance.layer} size: " \
|
|
80
|
+
"stride 0x#{stride.value.to_s(16)} #{instance.layer} size #{size}"
|
|
81
|
+
raise_evaluation_error message, stride.token_range
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def check_alignment(instance)
|
|
85
|
+
alignment = instance.alignment
|
|
86
|
+
return unless alignment
|
|
87
|
+
|
|
88
|
+
check_accesswidth_boundary(instance, :alignment, alignment)
|
|
89
|
+
|
|
90
|
+
return if alignment.value > 0
|
|
91
|
+
|
|
92
|
+
message = 'alignment must be positive'
|
|
93
|
+
raise_evaluation_error message, alignment.token_range
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def check_address_operations(instance)
|
|
97
|
+
check_address(instance)
|
|
98
|
+
check_stride(instance)
|
|
99
|
+
check_alignment(instance)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SystemRDL
|
|
4
|
+
module Evaluator
|
|
5
|
+
class AddrMapDefinition < ComponentDefinition
|
|
6
|
+
include AddressAllocation
|
|
7
|
+
include ContainerComponent
|
|
8
|
+
|
|
9
|
+
def evaluate(instance, **optargs)
|
|
10
|
+
if instance.root?
|
|
11
|
+
create_instance(instance, @id, nil, nil, nil, **optargs)
|
|
12
|
+
else
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def validate(instance)
|
|
18
|
+
check_structural_component_instances(instance)
|
|
19
|
+
check_alignment(instance)
|
|
20
|
+
check_endianness_exclusivity(instance)
|
|
21
|
+
check_rsvdset_exclusivity(instance)
|
|
22
|
+
check_bit_ordering_exclusivity(instance)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def finalize(instance)
|
|
26
|
+
allocate_addresses(instance)
|
|
27
|
+
check_overlapping_regs(instance)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def layer
|
|
31
|
+
:addrmap
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def instance_class
|
|
37
|
+
AddrMapInstance
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def check_alignment(instance)
|
|
41
|
+
check_power_of_2(instance, :alignment, 1)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def check_endianness_exclusivity(instance)
|
|
45
|
+
check_property_exclusivity(instance, [:bigendian, :littleendian])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def check_rsvdset_exclusivity(instance)
|
|
49
|
+
check_property_exclusivity(instance, [:rsvdset, :rsvdsetX])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def check_bit_ordering_exclusivity(instance)
|
|
53
|
+
check_property_exclusivity(instance, [:msb0, :lsb0])
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class AddrMapInstance < Instance
|
|
58
|
+
def definable?(definition)
|
|
59
|
+
definition.layer in :addrmap | :regfile | :reg | :field
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def instantiable?(definition)
|
|
63
|
+
definition.layer in :addrmap | :regfile | :reg
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SystemRDL
|
|
4
|
+
module Evaluator
|
|
5
|
+
ArrayInfo = Data.define(:id, :indices, :sizes, :first, :last) do
|
|
6
|
+
def n_elements
|
|
7
|
+
sizes.inject(:*)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ArrayComponent
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def eval_array(inst_values)
|
|
15
|
+
array = inst_values[:array]
|
|
16
|
+
return super unless array
|
|
17
|
+
|
|
18
|
+
sizes = array.elements.map do |size|
|
|
19
|
+
next size.value if size.value > 0
|
|
20
|
+
|
|
21
|
+
message = 'array size must be positive'
|
|
22
|
+
raise_evaluation_error message, size.token_range
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
index_list =
|
|
26
|
+
sizes
|
|
27
|
+
.map { |size| size.times.to_a }
|
|
28
|
+
.then { |list| list[0].product(*list[1..]) }
|
|
29
|
+
id = array_id
|
|
30
|
+
index_list.each.with_index(1) do |indices, i|
|
|
31
|
+
info = ArrayInfo.new(id, indices, sizes, i == 1, i == index_list.size)
|
|
32
|
+
yield(info)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def array_id
|
|
37
|
+
@array_id ||= - 1
|
|
38
|
+
@array_id += 1
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|