ipxact-ruby 0.11.1
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/.autotest +15 -0
- data/.gitignore +2 -0
- data/README.html +89 -0
- data/README.mdown +91 -0
- data/Rakefile +31 -0
- data/VERSION +1 -0
- data/autotest/discover.rb +17 -0
- data/lib/ipxact.rb +263 -0
- data/lib/ipxact/component.rb +235 -0
- data/lib/ipxact/parser.rb +27 -0
- data/lib/ipxact/parser/bus_data_parser.rb +229 -0
- data/lib/ipxact/parser/component_data_parser.rb +309 -0
- data/lib/ipxact/parser/platform_data_parser.rb +63 -0
- data/lib/ipxact/pathfinder/graph_pathfinder.rb +191 -0
- data/lib/ipxact/platform.rb +43 -0
- data/schemas/abstractionDefinition.xsd +332 -0
- data/schemas/abstractor.xsd +156 -0
- data/schemas/autoConfigure.xsd +226 -0
- data/schemas/busDefinition.xsd +99 -0
- data/schemas/busInterface.xsd +640 -0
- data/schemas/commonStructures.xsd +189 -0
- data/schemas/component.xsd +253 -0
- data/schemas/configurable.xsd +82 -0
- data/schemas/constraints.xsd +283 -0
- data/schemas/design.xsd +105 -0
- data/schemas/designConfig.xsd +144 -0
- data/schemas/file.xsd +560 -0
- data/schemas/fileType.xsd +86 -0
- data/schemas/generator.xsd +240 -0
- data/schemas/identifier.xsd +93 -0
- data/schemas/index.xsd +67 -0
- data/schemas/memoryMap.xsd +1007 -0
- data/schemas/model.xsd +291 -0
- data/schemas/port.xsd +441 -0
- data/schemas/signalDrivers.xsd +220 -0
- data/schemas/simpleTypes.xsd +90 -0
- data/schemas/subInstances.xsd +256 -0
- data/spec/integration/bus_data_extraction_spec.rb +105 -0
- data/spec/integration/data_calculation_spec.rb +133 -0
- data/spec/integration/data_construction_spec.rb +52 -0
- data/spec/integration/general_spec.rb +121 -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/component_spec.rb +98 -0
- data/spec/unit/graph_pathfinder_spec.rb +128 -0
- data/spec/unit/interconnect_spec.rb +177 -0
- data/spec/unit/ipxact_spec.rb +69 -0
- data/spec/unit/platform_spec.rb +34 -0
- metadata +225 -0
|
@@ -0,0 +1,309 @@
|
|
|
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
|
+
# Module for parsing IPXACT XML data and creating component objects.
|
|
18
|
+
#
|
|
19
|
+
# @author Guillaume Godet-Bar
|
|
20
|
+
#
|
|
21
|
+
module IPXACT::Parser::ComponentData
|
|
22
|
+
|
|
23
|
+
# The list of authorized connections (between two component instances in an
|
|
24
|
+
# interconnection).
|
|
25
|
+
#
|
|
26
|
+
AUTHORIZED_CONNECTIONS = [
|
|
27
|
+
{
|
|
28
|
+
:from => :mirrored_slave,
|
|
29
|
+
:to => :slave
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
:from => :master,
|
|
33
|
+
:to => :mirrored_master
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
:from => :master,
|
|
37
|
+
:to => :slave
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
# Parses the component identified by +component_id+, assigns the +variables+
|
|
42
|
+
# associated to +instance_name+, and produces a {IPXACT::Component} object.
|
|
43
|
+
#
|
|
44
|
+
# @param [Array<String>,String] component_id the component identifier, which
|
|
45
|
+
# should appear in one of the component_docs. This
|
|
46
|
+
# identifier can either be a String (in which
|
|
47
|
+
# circumstance the most recent component with the
|
|
48
|
+
# given name will be returned, if any) or an Array of
|
|
49
|
+
# 2 elements, composed as follows:
|
|
50
|
+
# [<component_identifier>, <component_version>]
|
|
51
|
+
# @param [String] instance_name the name of the component instance (if any)
|
|
52
|
+
# that is being parsed.
|
|
53
|
+
# @param [Array<Hash>] variables the variables associated with the
|
|
54
|
+
# +instance_name+.
|
|
55
|
+
# @param [Hash<String, Nokogiri::Node>] component_docs the Hash of Nokogiri
|
|
56
|
+
# component documents that was extracted from the
|
|
57
|
+
# platform's IPXACT specification.
|
|
58
|
+
# @param [Hash<String, Nokogiri::Node>] design_docs the Hash of Nokogiri
|
|
59
|
+
# design documents that was extracted from the platform's
|
|
60
|
+
# IPXACT specification.
|
|
61
|
+
# @param [Array<String>] contraints an Array of constraints imposed on
|
|
62
|
+
# components. A constraint is an Array of 2 elements,
|
|
63
|
+
# composed as follows:
|
|
64
|
+
# [<component_identifier>, <component_version>]
|
|
65
|
+
# For each component instanciated during the parsing of the
|
|
66
|
+
# platform, the parser will verify if any of the
|
|
67
|
+
# constraints may apply and then select the appropriate
|
|
68
|
+
# component.
|
|
69
|
+
#
|
|
70
|
+
# @return [Component] the corresponding component
|
|
71
|
+
#
|
|
72
|
+
def self.parse_component(component_id, instance_name, variables, component_docs, design_docs, constraints)
|
|
73
|
+
component_name, component_version = select_component(component_id, component_docs)
|
|
74
|
+
|
|
75
|
+
root_component = component_docs[[component_name, component_version]]
|
|
76
|
+
component_vendor = root_component.xpath("./spirit:component/spirit:vendor").text
|
|
77
|
+
views = root_component.xpath("//spirit:model/spirit:views/spirit:view")
|
|
78
|
+
|
|
79
|
+
instances, interconnections, hierconnections = parse_design_views(views, component_docs, design_docs, constraints)
|
|
80
|
+
|
|
81
|
+
ports = root_component.xpath(".//spirit:busInterface").collect do |a_bus_interface|
|
|
82
|
+
IPXACT::Parser::BusData.parse_bus(a_bus_interface, root_component, variables)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
component = IPXACT::Component.new(instance_name, component_name, component_vendor, component_version)
|
|
86
|
+
component.interconnections = interconnections
|
|
87
|
+
component.hierconnections = hierconnections
|
|
88
|
+
component.subcomponents = instances
|
|
89
|
+
component.ports = ports
|
|
90
|
+
component
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Selects from the component_docs the component that corresponds to the
|
|
94
|
+
# +component_id+.
|
|
95
|
+
# @param [String, Array<String>] component_id the component identifier, which
|
|
96
|
+
# should appear in one of the +component_docs+. This
|
|
97
|
+
# identifier can either be a String (in which circumstance
|
|
98
|
+
# the most recent component with the given name will be
|
|
99
|
+
# returned, if any) or an Array of 2 elements, composed as
|
|
100
|
+
# follows:
|
|
101
|
+
# [<component_identifier>, <component_version>]
|
|
102
|
+
# @param [Hash<String, Nokogiri::Node>] component_docs the Hash of Nokogiri
|
|
103
|
+
# component documents that was extracted from the
|
|
104
|
+
# platform's IPXACT specification.
|
|
105
|
+
#
|
|
106
|
+
# @return [Component] the component identified by +component_id+.
|
|
107
|
+
# @raise [ArgumentError] if no component could be found.
|
|
108
|
+
#
|
|
109
|
+
def self.select_component(component_id, component_docs)
|
|
110
|
+
if component_id.kind_of?(Array) && component_id.size == 2
|
|
111
|
+
# A version must have been specified
|
|
112
|
+
raise ArgumentError, 'Component could not be found!' unless component_docs.has_key? component_id
|
|
113
|
+
component_name, component_version = component_id
|
|
114
|
+
else
|
|
115
|
+
component_name = component_id
|
|
116
|
+
component_version = component_docs.keys.select{|name, version| name == component_name} \
|
|
117
|
+
.collect{|name, version| version} \
|
|
118
|
+
.sort{|a, b|
|
|
119
|
+
1 if IPXACT::is_most_recent_version?(a,b)
|
|
120
|
+
0 if IPXACT::is_same_version?(a,b)
|
|
121
|
+
-1
|
|
122
|
+
}.last
|
|
123
|
+
end
|
|
124
|
+
[component_name, component_version]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Scans the given views for a hierarchical view. If such a view is found, the
|
|
128
|
+
# method loads the referenced design document, and parses all component
|
|
129
|
+
# instances, interconnections and hierconnections that are described by the
|
|
130
|
+
# view.
|
|
131
|
+
#
|
|
132
|
+
# @param [Array<Nokogiri::Node>] views the views from an IPXACT XML that
|
|
133
|
+
# should be scanned for a hierarchical view.
|
|
134
|
+
# @param [Hash<String, Nokogiri::Node>] component_docs the Nokogiri component
|
|
135
|
+
# documents that were extracted from the platform's IPXACT
|
|
136
|
+
# specification.
|
|
137
|
+
# @param [Hash<String, Nokogiri::Node>] design_docs the design documents that
|
|
138
|
+
# were extracted from the platform's IPXACT specification.
|
|
139
|
+
# @param [Array<Array>] constraints an Array of constraints imposed on
|
|
140
|
+
# components. A constraint is an Array of 2 elements,
|
|
141
|
+
# composed as follows:
|
|
142
|
+
# [<component_identifier>, <component_version>]
|
|
143
|
+
# For each component instanciated during the parsing of the
|
|
144
|
+
# platform, the parser will verify if any of the constraints
|
|
145
|
+
# may apply and then select the appropriate component.
|
|
146
|
+
#
|
|
147
|
+
# @return [Array<Hash>] an Array containing 3 Hashes, respectively: the
|
|
148
|
+
# component instances Hash, the interconnections Hash and the
|
|
149
|
+
# hierconnections Hash. Empty hashes are returned by default.
|
|
150
|
+
# @raise an exception if any duplicate interconnection is found.
|
|
151
|
+
#
|
|
152
|
+
def self.parse_design_views(views, component_docs, design_docs, constraints)
|
|
153
|
+
design_view = views.select{|view| view.xpath("./spirit:name").text == 'spirit-design' && view.xpath("./spirit:envIdentifier").text == '::Hierarchy'}
|
|
154
|
+
if design_view.size == 1
|
|
155
|
+
design_ref = IPXACT::parse_reference(design_view.first.xpath("./spirit:hierarchyRef").first)
|
|
156
|
+
|
|
157
|
+
design_doc = design_docs[[design_ref[:name], design_ref[:version]]]
|
|
158
|
+
|
|
159
|
+
instances_map = parse_component_instances(design_doc)
|
|
160
|
+
instances = instances_map.inject({}) do |acc, entry|
|
|
161
|
+
local_instance_name = entry[0]
|
|
162
|
+
component_reference = entry[1][:reference]
|
|
163
|
+
local_variables = entry[1][:variables]
|
|
164
|
+
|
|
165
|
+
constraint = constraints.select{|constraint| constraint[0] == component_reference[:name]}.first
|
|
166
|
+
if constraint.nil?
|
|
167
|
+
acc[local_instance_name] = parse_component([component_reference[:name], component_reference[:version]], local_instance_name, local_variables, component_docs, design_docs, constraints)
|
|
168
|
+
else
|
|
169
|
+
acc[local_instance_name] = parse_component(constraint, local_instance_name, local_variables, component_docs, design_docs, constraints)
|
|
170
|
+
end
|
|
171
|
+
acc
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
interconnections = parse_interconnections(design_doc, instances)
|
|
175
|
+
interconnection_sources = interconnections.values.collect{|v| v[0]}
|
|
176
|
+
interconnection_targets = interconnections.values.collect{|v| v[1]}
|
|
177
|
+
raise 'Duplicate connections!' \
|
|
178
|
+
if interconnection_sources.size != interconnection_sources.uniq.size ||
|
|
179
|
+
interconnection_targets.size != interconnection_targets.uniq.size
|
|
180
|
+
|
|
181
|
+
hierconnections = parse_hierconnections(design_doc, instances)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
[(instances || {}), (interconnections || {}), (hierconnections || {})]
|
|
185
|
+
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Parses the IPXACT's design document for constructing the corresponding
|
|
189
|
+
# component instance interconnection.
|
|
190
|
+
#
|
|
191
|
+
# @param [Nokogiri::Node] design_doc the IPXACT design document that should
|
|
192
|
+
# be parsed for extracting the interconnection's
|
|
193
|
+
# data.
|
|
194
|
+
# @param [Array<Component>] component_instances the list of Component
|
|
195
|
+
# instances (i.e. parsed components) that correspond to
|
|
196
|
+
# the +design_doc+'s root component's subcomponents.
|
|
197
|
+
# @return [Hash] a Hash that associates the interconnection's name with an
|
|
198
|
+
# ordered Array (see {ComponentData#reorder_connection}) of
|
|
199
|
+
# Hashes, composed as follows:
|
|
200
|
+
# :port_name - The subcomponent's port name.
|
|
201
|
+
# :port_type - The subcomponent's port type.
|
|
202
|
+
# :component_instance - The subcomponent instance.
|
|
203
|
+
#
|
|
204
|
+
def self.parse_interconnections(design_doc, component_instances)
|
|
205
|
+
design_doc.xpath("//spirit:interconnection").inject({}) do |acc, inter|
|
|
206
|
+
unordered_connection = inter.xpath("./spirit:activeInterface").collect do |active_interface|
|
|
207
|
+
component_instance = component_instances[active_interface['componentRef']]
|
|
208
|
+
port = component_instance.ports.select{|port| port[:name] == active_interface['busRef']}.first
|
|
209
|
+
{
|
|
210
|
+
:port_name => port[:name],
|
|
211
|
+
:port_type => port[:type],
|
|
212
|
+
:component_instance => active_interface['componentRef']
|
|
213
|
+
}
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
ordered_connection = reorder_connection(unordered_connection)
|
|
217
|
+
|
|
218
|
+
acc[inter.xpath("./spirit:name").first.text] = ordered_connection
|
|
219
|
+
acc
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Parses a design document's hierconnections. A hierconnection corresponds to
|
|
224
|
+
# a connection between a port from the outside interface of the component
|
|
225
|
+
# instanciated by the design document with one of the component's
|
|
226
|
+
# subcomponents' ports.
|
|
227
|
+
#
|
|
228
|
+
# @param [Nokogiri::Node] design_doc the IPXACT design document that
|
|
229
|
+
# should be parsed for extracting the
|
|
230
|
+
# hierconnections.
|
|
231
|
+
# @param [Array<Component>] component_instances the list of Component
|
|
232
|
+
# instances (i.e. parsed components) that
|
|
233
|
+
# correspond to the +design_doc+ design document's
|
|
234
|
+
# root component's subcomponents.
|
|
235
|
+
#
|
|
236
|
+
# @return [Hash] a Hash that associates the outside port's name with the
|
|
237
|
+
# the following Hash:
|
|
238
|
+
# :port_name - The corresponding subcomponent's port name.
|
|
239
|
+
# :port_type - The corresponding subcomponent's port type.
|
|
240
|
+
# :component_instance - The subcomponent's instance.
|
|
241
|
+
#
|
|
242
|
+
def self.parse_hierconnections(design_doc, component_instances)
|
|
243
|
+
design_doc.xpath("//spirit:hierConnection").inject({}) do |acc, hier|
|
|
244
|
+
interface = hier.xpath("./spirit:interface").first
|
|
245
|
+
port = component_instances[interface['componentRef']].ports.select{|port| port[:name] == interface['busRef']}.first
|
|
246
|
+
acc[hier['interfaceRef']] = {
|
|
247
|
+
:port_name => interface['busRef'],
|
|
248
|
+
:port_type => port[:type],
|
|
249
|
+
:component_instance => interface['componentRef']
|
|
250
|
+
}
|
|
251
|
+
acc
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Extracts relevant data from an IPXACT design document (i.e., variable
|
|
256
|
+
# configurations)
|
|
257
|
+
#
|
|
258
|
+
# @param [Nokogiri::Node] design_doc a valid IPXACT design document.
|
|
259
|
+
#
|
|
260
|
+
# @return [Hash] a Hash that associates the component instance names with
|
|
261
|
+
# variable configurations. A variable configuration is composed of:
|
|
262
|
+
# :variables - The list of variables (name - value associations)
|
|
263
|
+
# :reference - The component type of the instance to which the variables
|
|
264
|
+
# should be affected.
|
|
265
|
+
#
|
|
266
|
+
def self.parse_component_instances(design_doc)
|
|
267
|
+
design_doc.xpath("//spirit:componentInstance").inject({}) do |acc, instance|
|
|
268
|
+
|
|
269
|
+
variables = instance.xpath(".//spirit:configurableElementValue").inject({}) do |acc, value|
|
|
270
|
+
acc[value['referenceId']] = value.text
|
|
271
|
+
acc
|
|
272
|
+
end
|
|
273
|
+
acc[instance.xpath("./spirit:instanceName").text] =
|
|
274
|
+
{
|
|
275
|
+
:reference => IPXACT::parse_reference(instance.xpath("./spirit:componentRef").first),
|
|
276
|
+
:variables => variables
|
|
277
|
+
}
|
|
278
|
+
acc
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Reorders IPXACT connections (which are not oriented in IPXACT
|
|
283
|
+
# specifications), following the list of authorized connections described in
|
|
284
|
+
# +AUTHORIZED_CONNECTIONS+.
|
|
285
|
+
#
|
|
286
|
+
# @param [Array<Hash>] connection a connection Array, that should contain 2
|
|
287
|
+
# elements. Each element must be a Hash with at least one
|
|
288
|
+
# +:port_type+ key.
|
|
289
|
+
#
|
|
290
|
+
# @return [Array] the connection Array, reversed if necessary.
|
|
291
|
+
# @raise an exception if no permutation of the connection elements corresponds
|
|
292
|
+
# to an authorized connection.
|
|
293
|
+
#
|
|
294
|
+
def self.reorder_connection(connection)
|
|
295
|
+
if AUTHORIZED_CONNECTIONS.include?({
|
|
296
|
+
:from => connection[0][:port_type],
|
|
297
|
+
:to => connection[1][:port_type]
|
|
298
|
+
})
|
|
299
|
+
connection
|
|
300
|
+
elsif AUTHORIZED_CONNECTIONS.include?({
|
|
301
|
+
:from => connection[1][:port_type],
|
|
302
|
+
:to => connection[0][:port_type]
|
|
303
|
+
})
|
|
304
|
+
connection.reverse
|
|
305
|
+
else
|
|
306
|
+
raise 'Invalid interconnect list!'
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
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
|
+
# Module for parsing IPXACT XML data and creating a platform object. Only this
|
|
18
|
+
# parser module should be used for working with IPXACT data.
|
|
19
|
+
#
|
|
20
|
+
# @author Guillaume Godet-Bar
|
|
21
|
+
#
|
|
22
|
+
module IPXACT::Parser::PlatformData
|
|
23
|
+
|
|
24
|
+
# Parses the +component_docs+ and +design_docs+ for creating a new
|
|
25
|
+
# {Platform} instance.
|
|
26
|
+
#
|
|
27
|
+
# @param [String, Array<String>] platform_id the platform identifier, which
|
|
28
|
+
# should appear in one of the +design_docs+.
|
|
29
|
+
# This identifier can either be a String (in
|
|
30
|
+
# which circumstance the most recent component
|
|
31
|
+
# with the given name will be returned, if
|
|
32
|
+
# any) or an Array of 2 elements, composed as
|
|
33
|
+
# follows:
|
|
34
|
+
# [<platform_identifier>, <platform_version>]
|
|
35
|
+
# @param [Hash<String, Nokogiri::Node>] component_docs the Hash of Nokogiri
|
|
36
|
+
# component documents that was
|
|
37
|
+
# extracted from the platform's IPXACT
|
|
38
|
+
# specification.
|
|
39
|
+
# @param [Hash<String, Nokogiri::Node>] design_docs the Hash of Nokogiri
|
|
40
|
+
# design documents that was extracted
|
|
41
|
+
# from the platform's IPXACT
|
|
42
|
+
# specification.
|
|
43
|
+
# @param [Array<String>] constraints the constraints imposed on components. A
|
|
44
|
+
# constraint is an Array of 2 elements, composed as
|
|
45
|
+
# follows:
|
|
46
|
+
# [<component_identifier>, <component_version>]
|
|
47
|
+
# For each component instanciated during the parsing
|
|
48
|
+
# of the platform, the parser will verify if any of
|
|
49
|
+
# the constraints may apply and then select the
|
|
50
|
+
# appropriate component.
|
|
51
|
+
#
|
|
52
|
+
# @return [Platform] the {Platform} instance. All the design documents
|
|
53
|
+
# related to the platform or any platform component are used for completing
|
|
54
|
+
# the {Platform} object. Additionally, all the variable elements, if any, are
|
|
55
|
+
# applied where appropriate.
|
|
56
|
+
#
|
|
57
|
+
def self.parse_platform(platform_id, component_docs, design_docs, constraints=[])
|
|
58
|
+
base_component = IPXACT::Parser::ComponentData.parse_component(
|
|
59
|
+
platform_id, "", {}, component_docs,
|
|
60
|
+
design_docs, constraints)
|
|
61
|
+
IPXACT::Platform.new(base_component)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -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::GraphPathFinder} instances are used by {IPXACT::Component} instances
|
|
18
|
+
# for handling Branch-And-Bound type data path searches within a given IPXACT
|
|
19
|
+
# architecture. The {IPXACT::Component} is responsible for translating the IPXACT
|
|
20
|
+
# architecture into a list of connections and transition weights, which may
|
|
21
|
+
# then be queried for optimal paths between two nodes from the connection
|
|
22
|
+
# graph. As such, even though the path finder is pretty generic, it should not
|
|
23
|
+
# be used directly for IPXACT-related work.
|
|
24
|
+
#
|
|
25
|
+
# @example
|
|
26
|
+
# @pathfinder = IPXACT::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::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
|