ipxact-tools 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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