ipxact-tools 0.2.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 (102) hide show
  1. data/config/detector.yml +63 -0
  2. data/lib/ipxact_tools.rb +287 -0
  3. data/lib/ipxact_tools/graph_pathfinder.rb +191 -0
  4. data/lib/ipxact_tools/interrupt_line_detector.rb +98 -0
  5. data/spec/integration/integration_spec.rb +254 -0
  6. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_initiator_port.h +135 -0
  7. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_initiator_port.tpp +247 -0
  8. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_initiator_port_base.h +189 -0
  9. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_router.h +205 -0
  10. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_router.tpp +278 -0
  11. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_slave_base.h +115 -0
  12. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_slave_base.tpp +126 -0
  13. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_target_port.h +168 -0
  14. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_target_port_base.h +133 -0
  15. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_tlm_if.h +280 -0
  16. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/user_types.h +38 -0
  17. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/Leon2Platform/Leon2Platform.xml +77 -0
  18. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/Leon2Platform/design_Leon2Platform.xml +156 -0
  19. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/Leon2Platform/tlmsrc/Leon2Platform.h +149 -0
  20. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/apbSubSystem/apbSubSystem.xml +406 -0
  21. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/apbSubSystem/design_apbSubSystem.xml +135 -0
  22. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/apbSubSystem/tlmsrc/apbSubSystem.h +133 -0
  23. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/Leon2Platform/Leon2Platform.xml +77 -0
  24. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/Leon2Platform/design_Leon2Platform.xml +157 -0
  25. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/Leon2Platform/tlmsrc/Leon2Platform.h +150 -0
  26. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/apbSubSystem.xml +422 -0
  27. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/designConfig_apbSubSystem.xml +79 -0
  28. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/design_apbSubSystem.xml +184 -0
  29. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/tlmsrc/apbSubSystem.h +164 -0
  30. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/Leon2Platform/Leon2Platform.xml +105 -0
  31. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/Leon2Platform/design_Leon2Platform.xml +157 -0
  32. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/Leon2Platform/tlmsrc/Leon2Platform.h +152 -0
  33. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/apbSubSystem.xml +429 -0
  34. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/designConfig_apbSubSystem.xml +64 -0
  35. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/design_apbSubSystem.xml +150 -0
  36. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/tlmsrc/apbSubSystem.h +167 -0
  37. data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbbus/1.4/ahbbus22.xml +236 -0
  38. data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbbus/1.4/tlmsrc/ahbbus.h +52 -0
  39. data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbram/1.4/ahbram.xml +184 -0
  40. data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbram/1.4/tlmsrc/ahbram.cc +93 -0
  41. data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbram/1.4/tlmsrc/ahbram.h +77 -0
  42. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbbus/1.4/apbbus8.xml +544 -0
  43. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbbus/1.4/tlmsrc/apbbus.h +55 -0
  44. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbmst/1.4/apbmst.xml +209 -0
  45. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbmst/1.4/tlmsrc/apbmst.h +53 -0
  46. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/apbram.xml +395 -0
  47. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.cc +89 -0
  48. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.h +69 -0
  49. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.v +82 -0
  50. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.vhd +132 -0
  51. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.4/cgu.xml +686 -0
  52. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.4/tlmsrc/cgu.cc +121 -0
  53. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.4/tlmsrc/cgu.h +81 -0
  54. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.5/cgu.xml +707 -0
  55. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.5/tlmsrc/cgu.cc +121 -0
  56. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.5/tlmsrc/cgu.h +81 -0
  57. data/spec/test_data/spiritconsortium.org/Leon2TLM/dma/1.4/dma.xml +272 -0
  58. data/spec/test_data/spiritconsortium.org/Leon2TLM/dma/1.4/tlmsrc/dma.cc +230 -0
  59. data/spec/test_data/spiritconsortium.org/Leon2TLM/dma/1.4/tlmsrc/dma.h +116 -0
  60. data/spec/test_data/spiritconsortium.org/Leon2TLM/irqctrl/1.4/irqctrl.xml +530 -0
  61. data/spec/test_data/spiritconsortium.org/Leon2TLM/irqctrl/1.4/tlmsrc/irqctrl.cc +211 -0
  62. data/spec/test_data/spiritconsortium.org/Leon2TLM/irqctrl/1.4/tlmsrc/irqctrl.h +108 -0
  63. data/spec/test_data/spiritconsortium.org/Leon2TLM/processor/1.4/processor.xml +423 -0
  64. data/spec/test_data/spiritconsortium.org/Leon2TLM/processor/1.4/tlmsrc/processor.cc +331 -0
  65. data/spec/test_data/spiritconsortium.org/Leon2TLM/processor/1.4/tlmsrc/processor.h +121 -0
  66. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2apb/1.0/pv2apb.xml +240 -0
  67. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2apb/1.0/tlmsrc/pv2apb.cc +153 -0
  68. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2apb/1.0/tlmsrc/pv2apb.h +77 -0
  69. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2tac/1.0/pv2tac.xml +154 -0
  70. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2tac/1.0/tlmsrc/pv2tac.cc +114 -0
  71. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2tac/1.0/tlmsrc/pv2tac.h +67 -0
  72. data/spec/test_data/spiritconsortium.org/Leon2TLM/rgu/1.4/rgu.xml +766 -0
  73. data/spec/test_data/spiritconsortium.org/Leon2TLM/rgu/1.4/tlmsrc/rgu.cc +126 -0
  74. data/spec/test_data/spiritconsortium.org/Leon2TLM/rgu/1.4/tlmsrc/rgu.h +105 -0
  75. data/spec/test_data/spiritconsortium.org/Leon2TLM/scmlAdaptor/1.0/scmlAdaptor.xml +154 -0
  76. data/spec/test_data/spiritconsortium.org/Leon2TLM/scmlAdaptor/1.0/tlmsrc/scmladaptor.cc +100 -0
  77. data/spec/test_data/spiritconsortium.org/Leon2TLM/scmlAdaptor/1.0/tlmsrc/scmladaptor.h +62 -0
  78. data/spec/test_data/spiritconsortium.org/Leon2TLM/serial_device/1.0/serial_device.xml +151 -0
  79. data/spec/test_data/spiritconsortium.org/Leon2TLM/serial_device/1.0/tlmsrc/serial_device.h +85 -0
  80. data/spec/test_data/spiritconsortium.org/Leon2TLM/timers/1.4/timers.xml +460 -0
  81. data/spec/test_data/spiritconsortium.org/Leon2TLM/timers/1.4/tlmsrc/timers.cc +201 -0
  82. data/spec/test_data/spiritconsortium.org/Leon2TLM/timers/1.4/tlmsrc/timers.h +102 -0
  83. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart.h +152 -0
  84. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart_fifo.h +113 -0
  85. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart_memory_map.h +96 -0
  86. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart_types.h +60 -0
  87. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart.cc +125 -0
  88. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart_interrupt_handler.cc +136 -0
  89. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart_register_bank.cc +129 -0
  90. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart_serial_tx_rx.cc +145 -0
  91. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/uart_scml.xml +372 -0
  92. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/Leon2_uart.h +216 -0
  93. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/def_Leon2_uart.h +34 -0
  94. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/tlm_field.h +72 -0
  95. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/tlm_register.h +129 -0
  96. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/tlmreg_Leon2_uart.h +133 -0
  97. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/src/Leon2_uart.cc +316 -0
  98. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/src/tlmreg_Leon2_uart.cc +197 -0
  99. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/src/user_specific_Leon2_uart.cc +146 -0
  100. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/uart_tac.xml +222 -0
  101. data/spec/unit/graph_pathfinder_spec.rb +128 -0
  102. metadata +272 -0
@@ -0,0 +1,63 @@
1
+ ---
2
+ :bus_name_regex:
3
+ -
4
+ - /INT_/i
5
+ - 0.7
6
+ -
7
+ - /INT/i
8
+ - 0.5
9
+ -
10
+ - /INTERRUPT/i
11
+ - 0.8
12
+ -
13
+ - /IRQ/i
14
+ - 0.8
15
+ -
16
+ - /FIQ/i
17
+ - 0.4
18
+ -
19
+ - /IRL_/i
20
+ - 0.4
21
+ -
22
+ - /IRL/i
23
+ - 0.3
24
+
25
+ :bus_library_regex:
26
+ -
27
+ - /INT_/i
28
+ - 0.7
29
+ -
30
+ - /INT/i
31
+ - 0.5
32
+ -
33
+ - /INTERRUPT/i
34
+ - 0.8
35
+ -
36
+ - /IRQ/i
37
+ - 0.8
38
+ -
39
+ - /FIQ/i
40
+ - 0.4
41
+ -
42
+ - /IRL_/i
43
+ - 0.4
44
+ -
45
+ - /IRL/i
46
+ - 0.3
47
+
48
+ :transition_matrix:
49
+ :not_int:
50
+ :not_int: 0.958904109589041
51
+ :int: 0.0410958904109589
52
+ :int:
53
+ :not_int: 0.5333333333333333
54
+ :int: 0.4666666666666667
55
+
56
+ :initial_state:
57
+ :not_int: 0.5042735042735043
58
+ :int: 0.49572649572649574
59
+
60
+ :states:
61
+ - :not_int
62
+ - :int
63
+
@@ -0,0 +1,287 @@
1
+ # Copyright (C) 2011 TIMA Laboratory
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+ #
16
+
17
+ require 'ipxact'
18
+
19
+ # The {IPXACT::Tools} module provides analysis tools for extracting or
20
+ # deducing relevant data from IP-Xact platforms. Three functionality are
21
+ # currently handled by the module:
22
+ # - It computes the shortest path between two component instances of a
23
+ # valid {IPXACT::Platform} instance.
24
+ # - It validates the data path by verifying that it does not contain any
25
+ # interrupt line, and emits a warning if several CPUs may contend for
26
+ # an access to the target component.
27
+ # - It deduces the target component's base address from the data path
28
+ # (handling all address remaps and IP-Xact variables).
29
+ #
30
+ # Because the IP-Xact standard does not include (yet) any formal way to
31
+ # distinguish interrupt lines from other communication channels, we try
32
+ # to identify those interrupt lines based on the different terms used
33
+ # for describing them. As a result, if the platform uses standard
34
+ # conventions for naming the interrupt line elements (esp. ports), such
35
+ # as 'INT_xxx', 'INTERRUPT_xxx', 'IRQ', 'IRL' etc., there is a high
36
+ # probability that our algorithm will be able to detect it.
37
+ #
38
+ # *NOTE* Unfortunately, there is currently no way to select an alternate
39
+ # data path if the one provided by the pathfinding algorithm happens to
40
+ # be invalid. If this is a strong requirement, drop me a mail (guillaume
41
+ # dot godetbar at gmail dot com) and I will
42
+ # try to include it ASAP.
43
+ #
44
+ # @author Guillaume Godet-Bar
45
+ #
46
+ module IPXACT
47
+ module Tools
48
+
49
+ # A simple structure for handling diagnosis messages.
50
+ #
51
+ class ValidationMessage < Struct.new(:reason, :cause_element)
52
+ def initialize(hash)
53
+ entry = hash.entries[0]
54
+ self.reason = entry[0]
55
+ self.cause_element = entry[1]
56
+ end
57
+ end
58
+
59
+ # Structure for handling validation errors.
60
+ #
61
+ class ValidationError < ValidationMessage ; end
62
+
63
+ # Structure for handling warning messages.
64
+ #
65
+ class ValidationWarning < ValidationMessage ; end
66
+
67
+ # Commodity class for handling errors and warnings produced by
68
+ # the {#validate_data_path method}.
69
+ #
70
+ class Diagnosis < Struct.new(:errors, :warnings)
71
+ def initialize
72
+ super
73
+ self.errors = []
74
+ self.warnings = []
75
+ end
76
+ end
77
+
78
+ # Validates the given data path. In particular, the method verifies
79
+ # that no interrupt line is present in the data path.
80
+ #
81
+ # @param [IPXACT::Platform] platform The reference platform
82
+ # @param [Array] data_path The data path to validate
83
+ #
84
+ # @return [Array<IPXACT::Tools::ValidationMessage>] a list of errors
85
+ # of errors and warnings, or an empty list if the data path is
86
+ # valid.
87
+ #
88
+ def self.validate_data_path(platform, data_path)
89
+ diagnosis = Diagnosis.new
90
+ path_ports = data_path.collect do |el|
91
+ platform.rec_get_subcomponent(el[0][:component_instance]).ports.select{|p|
92
+ p[:name] == el[0][:port_name]
93
+ }.first
94
+ end
95
+
96
+ if path_ports.first[:type] == :master
97
+
98
+ # Interrupt line detection
99
+ detector = IPXACT::Tools::InterruptLineDetector.new
100
+ stack = detector.viterbi(path_ports)
101
+ rendered_stack = detector.render_seq(stack)
102
+
103
+ interrupt_line_index = rendered_stack.find_index{|el| el == :int}
104
+ unless interrupt_line_index.nil?
105
+ diagnosis.errors << ValidationError.new(:probable_interrupt_line => data_path[interrupt_line_index])
106
+ end
107
+
108
+ # Concurrent access check
109
+ target_component_name = data_path.last[1][:component_instance]
110
+ target_component = platform.rec_get_subcomponent(target_component_name)
111
+ components = platform.rec_get_subcomponents.reject{|el| el == target_component}
112
+
113
+ cpu_instances = []
114
+ components.each do |instance_name, component|
115
+ if component.has_cpu?
116
+ cpu_instances << instance_name
117
+ end
118
+ end
119
+
120
+ if cpu_instances.size >= 2
121
+ diagnosis.warnings << ValidationWarning.new(:cpu_nb_causes_concurrent_access_risk => cpu_instances)
122
+ end
123
+ else
124
+ diagnosis.errors << ValidationError.new(:first_element_not_a_master => data_path.first)
125
+ end
126
+
127
+ return diagnosis
128
+ end
129
+
130
+ # Calculates an optimal path in the subcomponent graph between
131
+ # +subcomponent_start+ and +subcomponent_end+. This computation takes into
132
+ # account hierarchical subcomponents, and identifies optimal sub-paths in
133
+ # these elements as well, using hierconnections. This method is in fact the
134
+ # facade for the {IPXACT::GraphPathFinder} class. It handles the creation of
135
+ # the connection Hash, and translates the result in a IPXACT-specific format.
136
+ #
137
+ # @param [IPXACT::Platform] platform The reference platform
138
+ # @param [String] subcomponent_start The name of the component instance that
139
+ # should be the source of the data path.
140
+ # @param [String] subcomponent_end The name of the component instance that
141
+ # should be the target of the data path.
142
+ #
143
+ # @return [Array<Array<Hash>>] an Array of Arrays of Hashes that summarizes
144
+ # the component instances and the ports on the data path. Note that this
145
+ # data path may be used for calculating the target component's base
146
+ # address. The Arrays of Hashes are composed of 2 elements, the first
147
+ # element being the source of a connection step and the second element
148
+ # being the target of the connection step. Each element is a Hash, built as
149
+ # follows:
150
+ # +:component_instance+ the String name of the component instance that is
151
+ # traversed by the data path;
152
+ # +:port_name+ the String name of the port of the component instance that
153
+ # is being traversed.
154
+ # @raise several exceptions. Please refer to {IPXACT::GraphPathFinder} class
155
+ # for more details.
156
+ #
157
+ def self.resolve_data_path(platform, subcomponent_start, subcomponent_end)
158
+ nodes, connections = prepare_pathfinder_connections(platform)
159
+
160
+ pathfinder_connections = connections.collect do |connection|
161
+ {
162
+ :link => [nodes.index(connection[0][:component_instance]),
163
+ nodes.index(connection[1][:component_instance])],
164
+ :ports => [connection[0][:port_name], connection[1][:port_name]]
165
+ }
166
+ end
167
+
168
+ pathfinder_interconnect = {:nodes => nodes, :connections => pathfinder_connections}
169
+ pathfinder = IPXACT::Tools::GraphPathFinder.new(pathfinder_interconnect)
170
+ finder_result = pathfinder.resolve(subcomponent_start, subcomponent_end)
171
+
172
+ formatted_result = finder_result.collect do |res|
173
+ pathfinder_interconnect[:connections][res]
174
+ end.collect do |connection|
175
+ [
176
+ {
177
+ :component_instance => pathfinder_interconnect[:nodes][connection[:link][0]],
178
+ :port_name => connection[:ports][0]
179
+ },
180
+ {
181
+ :component_instance => pathfinder_interconnect[:nodes][connection[:link][1]],
182
+ :port_name => connection[:ports][1]
183
+ }
184
+ ]
185
+ end
186
+ end
187
+
188
+
189
+ # Computes a the base address of the last component instance mentionned in
190
+ # the +data_path+. The latter should be calculated using the
191
+ # {#resolve_data_path} method. Additionally, this method takes into account
192
+ # all subcomponents from the +data_path+, and basically adds up mirrored slave
193
+ # ports' remap addresses.
194
+ #
195
+ # @param [IPXACT::Platform] platform The reference platform
196
+ # @param [Arrray] data_path the data path from which the base address should be
197
+ # calculated. Please refer to the documentation of
198
+ # {#resolve_data_path} for more details on the structure of
199
+ # this argument.
200
+ # @param [Integer] initial_value the value that should be added to the base
201
+ # address computed by the method.
202
+ #
203
+ # Returns the base address of the target component, as an Integer.
204
+ #
205
+ def self.resolve_base_address(platform, data_path, initial_value = 0)
206
+ base_address = initial_value
207
+ data_path.each do |connection|
208
+ connection.each do |connection_step|
209
+ subcomponent = platform.rec_get_subcomponent(connection_step[:component_instance])
210
+ port = subcomponent.ports \
211
+ .select{|port| port[:name] == connection_step[:port_name]} \
212
+ .first
213
+ if port[:type] == :mirrored_slave && !port[:port_data].nil?
214
+ base_address += port[:port_data][:remap][:address].to_i(16)
215
+ end
216
+ end
217
+ end
218
+ base_address
219
+ end
220
+
221
+ private
222
+
223
+ # Executes the actual replacement of an hierarchical component's outside port
224
+ # with the attached subcomponent port.
225
+ #
226
+ # @param [IPXACT::Platform] platform The reference platform
227
+ # @param [Hash] connector The connector on which the
228
+ # replacement should be performed.
229
+ # @return [Hash] the flattened connector, i.e., a Hash built as follows:
230
+ # +:component_instance+ the String name of the component instance that is
231
+ # traversed by the data path;
232
+ # +:port_name+ the String name of the port of the component
233
+ # instance that is being traversed.
234
+ #
235
+ def self.reformat_connector(platform, connector)
236
+ instance = platform.subcomponents[connector[:component_instance]]
237
+ if instance.subcomponents.empty?
238
+ new_connector = connector
239
+ else
240
+ port = connector[:port_name]
241
+ new_connector = instance.hierconnections[port]
242
+ end
243
+ new_connector
244
+ end
245
+
246
+
247
+ # Prepares the connection structure for the {IPXACT::GraphPathFinder} class.
248
+ # Traverses the hierarchy of subcomponents in order to create a flattened
249
+ # representation of the subcomponents graph. In particular, the method
250
+ # considers hierconnections, and replaces the wrapper's interface port with
251
+ # the subcomponent's port that it is attached to.
252
+ #
253
+ # @param [IPXACT::Component] component root component from which to
254
+ # to start the formatting.
255
+ #
256
+ # @return [Array<Array,Array<Hash>>] an Array of 2 elements, composed of a
257
+ # list of nodes and a list of connections. Please refer to the
258
+ # {IPXACT::Tools::GraphPathFinder#initialize} method for more details on
259
+ # the structure of these elements (both Hashes).
260
+ #
261
+ def self.prepare_pathfinder_connections(component)
262
+ rec_prepare_pathfinder_connections(component, [], [])
263
+ end
264
+
265
+ # Recursive function for {#prepare_pathfinder_connections}.
266
+ #
267
+ def self.rec_prepare_pathfinder_connections(component, current_nodes, current_interconnections)
268
+ if component.subcomponents.empty?
269
+ [current_nodes << component.instance_name, current_interconnections]
270
+ else
271
+ component.subcomponents.each do |sub_name, subcomponent|
272
+ formatted_interconnections = component.interconnections.values.collect do |interconnect|
273
+ [reformat_connector(component, interconnect[0]), reformat_connector(component, interconnect[1])]
274
+ end
275
+ current_nodes, current_interconnections = \
276
+ rec_prepare_pathfinder_connections(subcomponent, current_nodes,
277
+ current_interconnections +
278
+ formatted_interconnections)
279
+ end
280
+ [current_nodes, current_interconnections]
281
+ end
282
+ end
283
+ end
284
+ end
285
+
286
+ require File.join File.dirname(__FILE__), 'ipxact_tools/graph_pathfinder'
287
+ require File.join File.dirname(__FILE__), 'ipxact_tools/interrupt_line_detector'
@@ -0,0 +1,191 @@
1
+ # Copyright (C) 2010 TIMA Laboratory
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+ #
16
+
17
+ # {IPXACT::Tools::GraphPathFinder} instances handle graph-based
18
+ # pathfinding requests within a given IPXACT architecture. It is
19
+ # responsible for translating the IPXACT architecture into a list of
20
+ # connections and transition weights, which may then be queried for
21
+ # optimal paths between two nodes from the connection graph. As such,
22
+ # even though the path finder is pretty generic, it should not be used
23
+ # directly for IPXACT-related work.
24
+ #
25
+ # @example
26
+ # @pathfinder = IPXACT::Tools::GraphPathFinder.new({
27
+ # :nodes => ['component_a', 'component_b', 'component_c']
28
+ # :connections =>
29
+ # [
30
+ # {:link => [0,1]},
31
+ # {:link => [1,2], :cost => 2},
32
+ # {:link => [2,0]}
33
+ # ]
34
+ # })
35
+ # @data_path = @pathfinder.resolve('component_a', 'component_b')
36
+ #
37
+ # @author Guillaume Godet-Bar
38
+ #
39
+ class IPXACT::Tools::GraphPathFinder
40
+
41
+ # The initializer is essentially used for passing a structured connection
42
+ # Hash.
43
+ #
44
+ # @param [Hash] hash the connection Hash, which should be structured as follows:
45
+ #
46
+ # :nodes - An Array of node names (String).
47
+ #
48
+ # :connections - An Array of connection elements, which are defined as
49
+ # :link - A 2-element Array, which describes an oriented
50
+ # connection between two nodes. The nodes are
51
+ # expressed using their index in the :nodes
52
+ # Array.
53
+ # :cost - A positive Integer expressing the cost of
54
+ # the transition (in the sense of a
55
+ # Branch-And-Bound algorithm) (optional,
56
+ # default: 1).
57
+ #
58
+ def initialize(hash)
59
+ @hash = hash
60
+ end
61
+
62
+ # Searches an optimal path between the start and _end elements, which
63
+ # should be defined in the Hash structured used for instanciating the
64
+ # {IPXACT::GraphPathFinder} instance. Optimal should be understood as "the
65
+ # cheapest path given the cost of each connection". Additionally, validates
66
+ # the latter Hash structure before executing the search algorithm.
67
+ #
68
+ # @param [String] start a String that corresponds to an element that was
69
+ # registered when the pathfinder was created. The latter will be used
70
+ # as the start node by the pathfinder algorithm.
71
+ # @param [String] _end a String that corresponds to an element that was
72
+ # registered when the pathfinder was created. The latter will be used
73
+ # as the target node by the pathfinder algorithm.
74
+ #
75
+ # @return [Array<Integer>] an Array of Integers corresponding to connection
76
+ # indices for the optimal data path between the +start+ and +_end+
77
+ # elements, or an empty Array if the +start+ and +_end+ elements are
78
+ # identical.
79
+ #
80
+ # @raise an exception if the Hash structure for the connections is empty.
81
+ # @raise an exception unless all the node names are unique.
82
+ # @raise an exception if the start or end element does not exist.
83
+ # @raise an exception if no optimal data path could be found.
84
+ #
85
+ def resolve(start, _end)
86
+ raise "Empty connection table!" if @hash.empty?
87
+ return [] if start == _end
88
+ raise "Duplicate connection node found!" if @hash[:nodes].uniq.size != @hash[:nodes].size
89
+ raise "The source or target node does not exist!" unless @hash[:nodes].include?(start) && @hash[:nodes].include?(_end)
90
+
91
+ @interconnect_table = (0..@hash[:nodes].size - 1).collect do |i|
92
+ (0..@hash[:nodes].size - 1).collect do |j|
93
+ result_hash = {
94
+ :connection =>
95
+ @hash[:connections].any?{|connection| connection[:link] == [j,i]},
96
+ :total => Float::INFINITY,
97
+ :previous => nil
98
+ }
99
+ if @hash[:connections].any?{|connection| connection[:link] == [j,i]}
100
+ result = @hash[:connections].select{|connection| connection[:link] == [j,i]}.first[:cost] || 1
101
+ result_hash.merge!({:cost => result})
102
+ end
103
+
104
+ result_hash
105
+ end
106
+ end
107
+
108
+ start_index = @hash[:nodes].index(start)
109
+ end_index = @hash[:nodes].index(_end)
110
+ @interconnect_table[start_index][start_index][:total] = 0
111
+
112
+
113
+ rec_resolve([start_index, start_index], end_index, 0)
114
+
115
+ last_writer_index = nil
116
+ @interconnect_table[end_index].each_with_index do |el, i|
117
+ last_writer_index = i if el[:total] < Float::INFINITY
118
+ end
119
+ raise "Destination could not be reached!" if last_writer_index.nil?
120
+
121
+
122
+ dump_trajectory(end_index).reverse
123
+
124
+ end
125
+
126
+ private
127
+
128
+ # Recursive function for the pathfinder search algorithm.
129
+ #
130
+ # @param [Array] current the current node that is being traversed by the
131
+ # algorithm.
132
+ # @param [Integer] _end the index of the target node.
133
+ # @param [Integer] current_total current Integer cost of the trajectory that
134
+ # is being explored by this branch of the algorithm.
135
+ #
136
+ def rec_resolve(current, _end, current_total)
137
+ current_writer_index = current[0]
138
+ (0..@interconnect_table.size - 1).each do |i|
139
+ if @interconnect_table[i][current_writer_index][:connection]
140
+ new_total = current_total + (@interconnect_table[i][current_writer_index][:cost] || 1)
141
+
142
+ if @interconnect_table[i][current_writer_index][:total] > new_total
143
+ @interconnect_table[i][current_writer_index] = {:total => new_total, :connection => true, :previous => current.reverse}
144
+
145
+ unless @interconnect_table[_end].any?{|el| el[:total] < new_total}
146
+ rec_resolve([i, current_writer_index], _end, new_total)
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ # Scans the interconnect table, starting with the end_index, and traces a
154
+ # trajectory back to its source, using the traceback references in each cell
155
+ # from the interconnect table. The source cell is considered as the cell for
156
+ # which there is no traceback reference.
157
+ #
158
+ # @param [Integer] end_index an Integer that corresponds to the last
159
+ # element (from the original Hash structure) for which there
160
+ # should be a trajectory calculated by the search algorithm.
161
+ #
162
+ # @return [Array<Integer>] the connection indices from the original Hash
163
+ # structure.
164
+ #
165
+ def dump_trajectory(end_index)
166
+ result = []
167
+
168
+ # Get the path with the cheapest result
169
+ min_element = @interconnect_table[end_index].min{|a,b| a[:total] <=> b[:total]}
170
+ min_index = @interconnect_table[end_index].index(min_element)
171
+
172
+ previous = [min_index, end_index]
173
+ begin
174
+ connection_index = @hash[:connections].index(@hash[:connections].detect{|el| el[:link] == previous})
175
+ result << connection_index unless connection_index.nil?
176
+ previous = @interconnect_table[previous[1]][previous[0]][:previous]
177
+ end while not previous.nil?
178
+
179
+ result
180
+ end
181
+
182
+ # Commodity method for printing the interconnect table during the execution of the search algorigthm.
183
+ #
184
+ def dump_table
185
+ @interconnect_table.inject('') do |row_acc, row|
186
+ row_acc + "\n" + row.inject('') do |col_acc, col|
187
+ col_acc + (col[:total] == Float::INFINITY ? 'I' : col[:total].to_s) + " | "
188
+ end
189
+ end
190
+ end
191
+ end