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.
- data/config/detector.yml +63 -0
- data/lib/ipxact_tools.rb +287 -0
- data/lib/ipxact_tools/graph_pathfinder.rb +191 -0
- data/lib/ipxact_tools/interrupt_line_detector.rb +98 -0
- data/spec/integration/integration_spec.rb +254 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_initiator_port.h +135 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_initiator_port.tpp +247 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_initiator_port_base.h +189 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_router.h +205 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_router.tpp +278 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_slave_base.h +115 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_slave_base.tpp +126 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_target_port.h +168 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_target_port_base.h +133 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_tlm_if.h +280 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/user_types.h +38 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/Leon2Platform/Leon2Platform.xml +77 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/Leon2Platform/design_Leon2Platform.xml +156 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/Leon2Platform/tlmsrc/Leon2Platform.h +149 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/apbSubSystem/apbSubSystem.xml +406 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/apbSubSystem/design_apbSubSystem.xml +135 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/apbSubSystem/tlmsrc/apbSubSystem.h +133 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/Leon2Platform/Leon2Platform.xml +77 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/Leon2Platform/design_Leon2Platform.xml +157 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/Leon2Platform/tlmsrc/Leon2Platform.h +150 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/apbSubSystem.xml +422 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/designConfig_apbSubSystem.xml +79 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/design_apbSubSystem.xml +184 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/tlmsrc/apbSubSystem.h +164 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/Leon2Platform/Leon2Platform.xml +105 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/Leon2Platform/design_Leon2Platform.xml +157 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/Leon2Platform/tlmsrc/Leon2Platform.h +152 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/apbSubSystem.xml +429 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/designConfig_apbSubSystem.xml +64 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/design_apbSubSystem.xml +150 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/tlmsrc/apbSubSystem.h +167 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbbus/1.4/ahbbus22.xml +236 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbbus/1.4/tlmsrc/ahbbus.h +52 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbram/1.4/ahbram.xml +184 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbram/1.4/tlmsrc/ahbram.cc +93 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbram/1.4/tlmsrc/ahbram.h +77 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/apbbus/1.4/apbbus8.xml +544 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/apbbus/1.4/tlmsrc/apbbus.h +55 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/apbmst/1.4/apbmst.xml +209 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/apbmst/1.4/tlmsrc/apbmst.h +53 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/apbram.xml +395 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.cc +89 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.h +69 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.v +82 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.vhd +132 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.4/cgu.xml +686 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.4/tlmsrc/cgu.cc +121 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.4/tlmsrc/cgu.h +81 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.5/cgu.xml +707 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.5/tlmsrc/cgu.cc +121 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.5/tlmsrc/cgu.h +81 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/dma/1.4/dma.xml +272 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/dma/1.4/tlmsrc/dma.cc +230 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/dma/1.4/tlmsrc/dma.h +116 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/irqctrl/1.4/irqctrl.xml +530 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/irqctrl/1.4/tlmsrc/irqctrl.cc +211 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/irqctrl/1.4/tlmsrc/irqctrl.h +108 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/processor/1.4/processor.xml +423 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/processor/1.4/tlmsrc/processor.cc +331 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/processor/1.4/tlmsrc/processor.h +121 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2apb/1.0/pv2apb.xml +240 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2apb/1.0/tlmsrc/pv2apb.cc +153 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2apb/1.0/tlmsrc/pv2apb.h +77 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2tac/1.0/pv2tac.xml +154 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2tac/1.0/tlmsrc/pv2tac.cc +114 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2tac/1.0/tlmsrc/pv2tac.h +67 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/rgu/1.4/rgu.xml +766 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/rgu/1.4/tlmsrc/rgu.cc +126 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/rgu/1.4/tlmsrc/rgu.h +105 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/scmlAdaptor/1.0/scmlAdaptor.xml +154 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/scmlAdaptor/1.0/tlmsrc/scmladaptor.cc +100 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/scmlAdaptor/1.0/tlmsrc/scmladaptor.h +62 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/serial_device/1.0/serial_device.xml +151 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/serial_device/1.0/tlmsrc/serial_device.h +85 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/timers/1.4/timers.xml +460 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/timers/1.4/tlmsrc/timers.cc +201 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/timers/1.4/tlmsrc/timers.h +102 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart.h +152 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart_fifo.h +113 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart_memory_map.h +96 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart_types.h +60 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart.cc +125 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart_interrupt_handler.cc +136 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart_register_bank.cc +129 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart_serial_tx_rx.cc +145 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/uart_scml.xml +372 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/Leon2_uart.h +216 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/def_Leon2_uart.h +34 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/tlm_field.h +72 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/tlm_register.h +129 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/tlmreg_Leon2_uart.h +133 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/src/Leon2_uart.cc +316 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/src/tlmreg_Leon2_uart.cc +197 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/src/user_specific_Leon2_uart.cc +146 -0
- data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/uart_tac.xml +222 -0
- data/spec/unit/graph_pathfinder_spec.rb +128 -0
- metadata +272 -0
data/config/detector.yml
ADDED
|
@@ -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
|
+
|
data/lib/ipxact_tools.rb
ADDED
|
@@ -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
|