ipxact-ruby 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/.autotest +15 -0
  2. data/.gitignore +2 -0
  3. data/README.html +89 -0
  4. data/README.mdown +91 -0
  5. data/Rakefile +31 -0
  6. data/VERSION +1 -0
  7. data/autotest/discover.rb +17 -0
  8. data/lib/ipxact.rb +263 -0
  9. data/lib/ipxact/component.rb +235 -0
  10. data/lib/ipxact/parser.rb +27 -0
  11. data/lib/ipxact/parser/bus_data_parser.rb +229 -0
  12. data/lib/ipxact/parser/component_data_parser.rb +309 -0
  13. data/lib/ipxact/parser/platform_data_parser.rb +63 -0
  14. data/lib/ipxact/pathfinder/graph_pathfinder.rb +191 -0
  15. data/lib/ipxact/platform.rb +43 -0
  16. data/schemas/abstractionDefinition.xsd +332 -0
  17. data/schemas/abstractor.xsd +156 -0
  18. data/schemas/autoConfigure.xsd +226 -0
  19. data/schemas/busDefinition.xsd +99 -0
  20. data/schemas/busInterface.xsd +640 -0
  21. data/schemas/commonStructures.xsd +189 -0
  22. data/schemas/component.xsd +253 -0
  23. data/schemas/configurable.xsd +82 -0
  24. data/schemas/constraints.xsd +283 -0
  25. data/schemas/design.xsd +105 -0
  26. data/schemas/designConfig.xsd +144 -0
  27. data/schemas/file.xsd +560 -0
  28. data/schemas/fileType.xsd +86 -0
  29. data/schemas/generator.xsd +240 -0
  30. data/schemas/identifier.xsd +93 -0
  31. data/schemas/index.xsd +67 -0
  32. data/schemas/memoryMap.xsd +1007 -0
  33. data/schemas/model.xsd +291 -0
  34. data/schemas/port.xsd +441 -0
  35. data/schemas/signalDrivers.xsd +220 -0
  36. data/schemas/simpleTypes.xsd +90 -0
  37. data/schemas/subInstances.xsd +256 -0
  38. data/spec/integration/bus_data_extraction_spec.rb +105 -0
  39. data/spec/integration/data_calculation_spec.rb +133 -0
  40. data/spec/integration/data_construction_spec.rb +52 -0
  41. data/spec/integration/general_spec.rb +121 -0
  42. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_initiator_port.h +135 -0
  43. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_initiator_port.tpp +247 -0
  44. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_initiator_port_base.h +189 -0
  45. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_router.h +205 -0
  46. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_router.tpp +278 -0
  47. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_slave_base.h +115 -0
  48. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_slave_base.tpp +126 -0
  49. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_target_port.h +168 -0
  50. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_target_port_base.h +133 -0
  51. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/pv_tlm_if.h +280 -0
  52. data/spec/test_data/spiritconsortium.org/Leon2TLM/PV/user_types.h +38 -0
  53. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/Leon2Platform/Leon2Platform.xml +77 -0
  54. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/Leon2Platform/design_Leon2Platform.xml +156 -0
  55. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/Leon2Platform/tlmsrc/Leon2Platform.h +149 -0
  56. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/apbSubSystem/apbSubSystem.xml +406 -0
  57. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/apbSubSystem/design_apbSubSystem.xml +135 -0
  58. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM1/apbSubSystem/tlmsrc/apbSubSystem.h +133 -0
  59. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/Leon2Platform/Leon2Platform.xml +77 -0
  60. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/Leon2Platform/design_Leon2Platform.xml +157 -0
  61. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/Leon2Platform/tlmsrc/Leon2Platform.h +150 -0
  62. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/apbSubSystem.xml +422 -0
  63. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/designConfig_apbSubSystem.xml +79 -0
  64. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/design_apbSubSystem.xml +184 -0
  65. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM2/apbSubSystem/tlmsrc/apbSubSystem.h +164 -0
  66. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/Leon2Platform/Leon2Platform.xml +105 -0
  67. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/Leon2Platform/design_Leon2Platform.xml +157 -0
  68. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/Leon2Platform/tlmsrc/Leon2Platform.h +152 -0
  69. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/apbSubSystem.xml +429 -0
  70. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/designConfig_apbSubSystem.xml +64 -0
  71. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/design_apbSubSystem.xml +150 -0
  72. data/spec/test_data/spiritconsortium.org/Leon2TLM/SystemTLM3/apbSubSystem/tlmsrc/apbSubSystem.h +167 -0
  73. data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbbus/1.4/ahbbus22.xml +236 -0
  74. data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbbus/1.4/tlmsrc/ahbbus.h +52 -0
  75. data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbram/1.4/ahbram.xml +184 -0
  76. data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbram/1.4/tlmsrc/ahbram.cc +93 -0
  77. data/spec/test_data/spiritconsortium.org/Leon2TLM/ahbram/1.4/tlmsrc/ahbram.h +77 -0
  78. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbbus/1.4/apbbus8.xml +544 -0
  79. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbbus/1.4/tlmsrc/apbbus.h +55 -0
  80. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbmst/1.4/apbmst.xml +209 -0
  81. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbmst/1.4/tlmsrc/apbmst.h +53 -0
  82. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/apbram.xml +395 -0
  83. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.cc +89 -0
  84. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.h +69 -0
  85. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.v +82 -0
  86. data/spec/test_data/spiritconsortium.org/Leon2TLM/apbram/1.0/hdlsrc/apbram.vhd +132 -0
  87. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.4/cgu.xml +686 -0
  88. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.4/tlmsrc/cgu.cc +121 -0
  89. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.4/tlmsrc/cgu.h +81 -0
  90. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.5/cgu.xml +707 -0
  91. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.5/tlmsrc/cgu.cc +121 -0
  92. data/spec/test_data/spiritconsortium.org/Leon2TLM/cgu/1.5/tlmsrc/cgu.h +81 -0
  93. data/spec/test_data/spiritconsortium.org/Leon2TLM/dma/1.4/dma.xml +272 -0
  94. data/spec/test_data/spiritconsortium.org/Leon2TLM/dma/1.4/tlmsrc/dma.cc +230 -0
  95. data/spec/test_data/spiritconsortium.org/Leon2TLM/dma/1.4/tlmsrc/dma.h +116 -0
  96. data/spec/test_data/spiritconsortium.org/Leon2TLM/irqctrl/1.4/irqctrl.xml +530 -0
  97. data/spec/test_data/spiritconsortium.org/Leon2TLM/irqctrl/1.4/tlmsrc/irqctrl.cc +211 -0
  98. data/spec/test_data/spiritconsortium.org/Leon2TLM/irqctrl/1.4/tlmsrc/irqctrl.h +108 -0
  99. data/spec/test_data/spiritconsortium.org/Leon2TLM/processor/1.4/processor.xml +423 -0
  100. data/spec/test_data/spiritconsortium.org/Leon2TLM/processor/1.4/tlmsrc/processor.cc +331 -0
  101. data/spec/test_data/spiritconsortium.org/Leon2TLM/processor/1.4/tlmsrc/processor.h +121 -0
  102. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2apb/1.0/pv2apb.xml +240 -0
  103. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2apb/1.0/tlmsrc/pv2apb.cc +153 -0
  104. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2apb/1.0/tlmsrc/pv2apb.h +77 -0
  105. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2tac/1.0/pv2tac.xml +154 -0
  106. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2tac/1.0/tlmsrc/pv2tac.cc +114 -0
  107. data/spec/test_data/spiritconsortium.org/Leon2TLM/pv2tac/1.0/tlmsrc/pv2tac.h +67 -0
  108. data/spec/test_data/spiritconsortium.org/Leon2TLM/rgu/1.4/rgu.xml +766 -0
  109. data/spec/test_data/spiritconsortium.org/Leon2TLM/rgu/1.4/tlmsrc/rgu.cc +126 -0
  110. data/spec/test_data/spiritconsortium.org/Leon2TLM/rgu/1.4/tlmsrc/rgu.h +105 -0
  111. data/spec/test_data/spiritconsortium.org/Leon2TLM/scmlAdaptor/1.0/scmlAdaptor.xml +154 -0
  112. data/spec/test_data/spiritconsortium.org/Leon2TLM/scmlAdaptor/1.0/tlmsrc/scmladaptor.cc +100 -0
  113. data/spec/test_data/spiritconsortium.org/Leon2TLM/scmlAdaptor/1.0/tlmsrc/scmladaptor.h +62 -0
  114. data/spec/test_data/spiritconsortium.org/Leon2TLM/serial_device/1.0/serial_device.xml +151 -0
  115. data/spec/test_data/spiritconsortium.org/Leon2TLM/serial_device/1.0/tlmsrc/serial_device.h +85 -0
  116. data/spec/test_data/spiritconsortium.org/Leon2TLM/timers/1.4/timers.xml +460 -0
  117. data/spec/test_data/spiritconsortium.org/Leon2TLM/timers/1.4/tlmsrc/timers.cc +201 -0
  118. data/spec/test_data/spiritconsortium.org/Leon2TLM/timers/1.4/tlmsrc/timers.h +102 -0
  119. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart.h +152 -0
  120. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart_fifo.h +113 -0
  121. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart_memory_map.h +96 -0
  122. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/inc/uart_types.h +60 -0
  123. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart.cc +125 -0
  124. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart_interrupt_handler.cc +136 -0
  125. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart_register_bank.cc +129 -0
  126. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/tlmsrc/src/uart_serial_tx_rx.cc +145 -0
  127. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_scml/1.0/uart_scml.xml +372 -0
  128. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/Leon2_uart.h +216 -0
  129. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/def_Leon2_uart.h +34 -0
  130. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/tlm_field.h +72 -0
  131. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/tlm_register.h +129 -0
  132. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/include/tlmreg_Leon2_uart.h +133 -0
  133. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/src/Leon2_uart.cc +316 -0
  134. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/src/tlmreg_Leon2_uart.cc +197 -0
  135. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/tlmsrc/src/user_specific_Leon2_uart.cc +146 -0
  136. data/spec/test_data/spiritconsortium.org/Leon2TLM/uart_tac/1.0/uart_tac.xml +222 -0
  137. data/spec/unit/component_spec.rb +98 -0
  138. data/spec/unit/graph_pathfinder_spec.rb +128 -0
  139. data/spec/unit/interconnect_spec.rb +177 -0
  140. data/spec/unit/ipxact_spec.rb +69 -0
  141. data/spec/unit/platform_spec.rb +34 -0
  142. 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