Coverage for pyEDAA/IPXACT/Component.py: 50%

369 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-05-30 22:17 +0000

1# ==================================================================================================================== # 

2# _____ ____ _ _ ___ ______ __ _ ____ _____ # 

3# _ __ _ _| ____| _ \ / \ / \ |_ _| _ \ \/ / / \ / ___|_ _| # 

4# | '_ \| | | | _| | | | |/ _ \ / _ \ | || |_) \ / / _ \| | | | # 

5# | |_) | |_| | |___| |_| / ___ \ / ___ \ _ | || __// \ / ___ \ |___ | | # 

6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)___|_| /_/\_\/_/ \_\____| |_| # 

7# |_| |___/ # 

8# ==================================================================================================================== # 

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

13# ==================================================================================================================== # 

14# Copyright 2017-2025 Patrick Lehmann - Bötzingen, Germany # 

15# Copyright 2016-2016 Patrick Lehmann - Dresden, Germany # 

16# # 

17# Licensed under the Apache License, Version 2.0 (the "License"); # 

18# you may not use this file except in compliance with the License. # 

19# You may obtain a copy of the License at # 

20# # 

21# http://www.apache.org/licenses/LICENSE-2.0 # 

22# # 

23# Unless required by applicable law or agreed to in writing, software # 

24# distributed under the License is distributed on an "AS IS" BASIS, # 

25# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

26# See the License for the specific language governing permissions and # 

27# limitations under the License. # 

28# # 

29# SPDX-License-Identifier: Apache-2.0 # 

30# ==================================================================================================================== # 

31# 

32from pathlib import Path 

33from sys import version_info 

34from textwrap import dedent 

35from typing import List, Optional as Nullable, ClassVar, Dict, Union 

36 

37from lxml.etree import _Element, QName, _Comment 

38from pyTooling.Decorators import export, readonly 

39from pyTooling.Common import getFullyQualifiedName 

40 

41from pyEDAA.IPXACT import __DEFAULT_SCHEMA__, RootElement, VLNV, IPXACTSchema, Element, IPXACTException 

42 

43 

44@export 

45class BusInterface(Element): 

46 """Represents an IP-XACT bus interface.""" 

47 

48 def __init__(self, vlnv: VLNV) -> None: 

49 super().__init__(vlnv) 

50 

51 @classmethod 

52 def FromXml(cls, element: _Element) -> "BusInterface": 

53 pass 

54 

55 def ToXml(self, indent=0): 

56 """Converts the object's data into XML format.""" 

57 

58 return "" 

59 

60 

61@export 

62class IndirectInterface(Element): 

63 """Represents an IP-XACT indirect interface.""" 

64 

65 def __init__(self, vlnv: VLNV) -> None: 

66 super().__init__(vlnv) 

67 

68 def ToXml(self, indent=0): 

69 """Converts the object's data into XML format.""" 

70 

71 return "" 

72 

73 

74@export 

75class Channel(Element): 

76 """Represents an IP-XACT channel.""" 

77 

78 def __init__(self, vlnv: VLNV) -> None: 

79 super().__init__(vlnv) 

80 

81 def ToXml(self, indent=0): 

82 """Converts the object's data into XML format.""" 

83 

84 return "" 

85 

86 

87@export 

88class RemapState(Element): 

89 """Represents an IP-XACT remap state.""" 

90 

91 def __init__(self, vlnv: VLNV) -> None: 

92 super().__init__(vlnv) 

93 

94 def ToXml(self, indent=0): 

95 """Converts the object's data into XML format.""" 

96 

97 return "" 

98 

99 

100@export 

101class AddressSpace(Element): 

102 """Represents an IP-XACT address space.""" 

103 

104 def __init__(self, vlnv: VLNV) -> None: 

105 super().__init__(vlnv) 

106 

107 def ToXml(self, indent=0): 

108 """Converts the object's data into XML format.""" 

109 

110 return "" 

111 

112 

113@export 

114class MemoryMap(Element): 

115 """Represents an IP-XACT memory map.""" 

116 

117 def __init__(self, vlnv: VLNV) -> None: 

118 super().__init__(vlnv) 

119 

120 def ToXml(self, indent=0): 

121 """Converts the object's data into XML format.""" 

122 

123 return "" 

124 

125 

126@export 

127class Model(Element): 

128 """Represents an IP-XACT model.""" 

129 

130 def __init__(self, vlnv: VLNV) -> None: 

131 super().__init__(vlnv) 

132 

133 def ToXml(self, indent=0): 

134 """Converts the object's data into XML format.""" 

135 

136 return "" 

137 

138 

139@export 

140class ComponentGenerator: 

141 """Represents an IP-XACT component generator.""" 

142 

143 def __init__(self, vlnv: VLNV) -> None: 

144 super().__init__(vlnv) 

145 

146 def ToXml(self, indent=0): 

147 """Converts the object's data into XML format.""" 

148 

149 return "" 

150 

151 

152@export 

153class Choice(Element): 

154 """Represents an IP-XACT choice.""" 

155 

156 def __init__(self, vlnv: VLNV) -> None: 

157 super().__init__(vlnv) 

158 

159 def ToXml(self, indent=0): 

160 """Converts the object's data into XML format.""" 

161 

162 return "" 

163 

164 

165@export 

166class File(Element): 

167 _path: Path 

168 

169 def __init__(self, path: Path) -> None: 

170 self._path = Path 

171 

172 @readonly 

173 def Path(self) -> Path: 

174 return self._path 

175 

176 @classmethod 

177 def FromXml(cls, fileElement: _Element) -> "FileSet": 

178 fileName = None 

179 fileType = None 

180 for element in fileElement: 

181 if isinstance(element, _Comment): 181 ↛ 182line 181 didn't jump to line 182 because the condition on line 181 was never true

182 continue 

183 

184 elementLocalname = QName(element).localname 

185 if elementLocalname == "name": 

186 fileName = element.text 

187 elif elementLocalname == "fileType": 

188 fileType = element.text 

189 elif elementLocalname == "isStructural": 189 ↛ 192line 189 didn't jump to line 192 because the condition on line 189 was always true

190 pass 

191 else: 

192 raise IPXACTException(f"Unsupported tag '{elementLocalname}' at component → fileSets → fileSet → file.") 

193 

194 return cls(Path(fileName)) 

195 

196 def ToXml(self, indent=0): 

197 """Converts the object's data into XML format.""" 

198 

199 return "" 

200 

201 def __str__(self) -> str: 

202 return str(self._path) 

203 

204 

205@export 

206class FileSet(Element): 

207 """Represents an IP-XACT fileset.""" 

208 

209 _name: str 

210 _files: List[File] 

211 

212 def __init__(self, name: str, files: List[File]) -> None: 

213 self._name = name 

214 self._files = [file for file in files] 

215 

216 @readonly 

217 def Name(self) -> str: 

218 return self._name 

219 

220 @readonly 

221 def Files(self) -> List[File]: 

222 return self._files 

223 

224 @readonly 

225 def FileCount(self) -> int: 

226 return len(self._files) 

227 

228 @classmethod 

229 def FromXml(cls, fileSetElement: _Element) -> "FileSet": 

230 files = [] 

231 fileSetName = None 

232 for element in fileSetElement: 

233 if isinstance(element, _Comment): 

234 continue 

235 

236 elementLocalname = QName(element).localname 

237 if elementLocalname == "name": 

238 fileSetName = element.text 

239 elif elementLocalname == "file": 239 ↛ 242line 239 didn't jump to line 242 because the condition on line 239 was always true

240 files.append(File.FromXml(element)) 

241 else: 

242 raise IPXACTException(f"Unsupported tag '{elementLocalname}' at component → fileSets → fileSet.") 

243 

244 return cls(fileSetName, files) 

245 

246 def ToXml(self, indent=0): 

247 """Converts the object's data into XML format.""" 

248 

249 return "" 

250 

251 def __str__(self) -> str: 

252 return f"FileSet {self._name} ({len(self._files)})" 

253 

254 

255@export 

256class WhiteboxElement(Element): 

257 """Represents an IP-XACT whitebos element.""" 

258 

259 def __init__(self, vlnv: VLNV) -> None: 

260 super().__init__(vlnv) 

261 

262 def ToXml(self, indent=0): 

263 """Converts the object's data into XML format.""" 

264 

265 return "" 

266 

267 

268@export 

269class Cpu(Element): 

270 """Represents an IP-XACT cpu.""" 

271 

272 def __init__(self, vlnv: VLNV) -> None: 

273 super().__init__(vlnv) 

274 

275 def ToXml(self, indent=0): 

276 """Converts the object's data into XML format.""" 

277 

278 return "" 

279 

280 

281@export 

282class OtherClockDriver(Element): 

283 """Represents an IP-XACT *other* clock driver.""" 

284 

285 def __init__(self, vlnv: VLNV) -> None: 

286 super().__init__(vlnv) 

287 

288 def ToXml(self, indent=0): 

289 """Converts the object's data into XML format.""" 

290 

291 return "" 

292 

293 

294@export 

295class ResetType(Element): 

296 """Represents an IP-XACT reset type.""" 

297 

298 def __init__(self, vlnv: VLNV) -> None: 

299 super().__init__(vlnv) 

300 

301 def ToXml(self, indent=0): 

302 """Converts the object's data into XML format.""" 

303 

304 return "" 

305 

306 

307@export 

308class Parameter(Element): 

309 """Represents an IP-XACT parameter.""""""Represents an IP-XACT assertion.""" 

310 

311 def __init__(self, vlnv: VLNV) -> None: 

312 super().__init__(vlnv) 

313 

314 def ToXml(self, indent=0): 

315 """Converts the object's data into XML format.""" 

316 

317 return "" 

318 

319 

320@export 

321class Assertion(Element): 

322 """Represents an IP-XACT assertion.""" 

323 

324 def __init__(self, vlnv: VLNV) -> None: 

325 super().__init__(vlnv) 

326 

327 def ToXml(self, indent=0): 

328 """Converts the object's data into XML format.""" 

329 

330 return "" 

331 

332 

333@export 

334class Component(RootElement): 

335 """Represents an IP-XACT components.""" 

336 

337 _rootTagName: ClassVar[str] = "component" 

338 

339 _busInterfaces: List 

340 _indirectInterfaces: List 

341 _channels: List 

342 _remapStates: List 

343 _addressSpaces: List 

344 _memoryMaps: List 

345 _model: Nullable[Model] 

346 _componentGenerators: List 

347 _choices: List 

348 _fileSets: Dict[str, FileSet] 

349 _whiteboxElements: List 

350 _cpus: List 

351 _otherClockDrivers: List 

352 _resetTypes: List 

353 _parameters: List 

354 _assertions: List 

355 

356 def __init__( 

357 self, 

358 componentFile: Nullable[Path] = None, 

359 parse: bool = False, 

360 vlnv: Nullable[VLNV] = None, 

361 description: Nullable[str] = None 

362 ): 

363 self._busInterfaces = [] 

364 self._indirectInterfaces = [] 

365 self._channels = [] 

366 self._remapStates = [] 

367 self._addressSpaces = [] 

368 self._memoryMaps = [] 

369 self._model = None 

370 self._componentGenerators = [] 

371 self._choices = [] 

372 self._fileSets = {} 

373 self._whiteboxElements = [] 

374 self._cpus = [] 

375 self._otherClockDrivers = [] 

376 self._resetTypes = [] 

377 self._parameters = [] 

378 self._assertions = [] 

379 

380 super().__init__(componentFile, parse, vlnv, description) 

381 

382 @readonly 

383 def FileSets(self) -> Dict[str, FileSet]: 

384 return self._fileSets 

385 

386 def Parse(self, element: _Element) -> None: 

387 elementLocalname = QName(element).localname 

388 if elementLocalname == "busInterfaces": 

389 pass 

390 # for busInterfaceElement in element: 

391 # self.AddItem(BusInterface.FromXml(busInterfaceElement)) 

392 elif elementLocalname == "indirectInterfaces": 

393 pass 

394 elif elementLocalname == "channels": 

395 pass 

396 elif elementLocalname == "remapStates": 

397 pass 

398 elif elementLocalname == "addressSpaces": 

399 pass 

400 elif elementLocalname == "memoryMaps": 

401 pass 

402 elif elementLocalname == "model": 

403 pass 

404 elif elementLocalname == "componentGenerators": 

405 pass 

406 elif elementLocalname == "choices": 

407 pass 

408 elif elementLocalname == "fileSets": 

409 for fileSetElement in element: 

410 if isinstance(fileSetElement, _Comment): 

411 continue 

412 

413 self.AddFileSet(FileSet.FromXml(fileSetElement)) 

414 elif elementLocalname == "whiteboxElements": 

415 pass 

416 elif elementLocalname == "cpus": 

417 pass 

418 elif elementLocalname == "otherClockDrivers": 

419 pass 

420 elif elementLocalname == "resetTypes": 

421 pass 

422 elif elementLocalname == "parameters": 

423 pass 

424 elif elementLocalname == "assertions": 424 ↛ 427line 424 didn't jump to line 427 because the condition on line 424 was always true

425 pass 

426 else: 

427 raise IPXACTException(f"Unsupported tag '{elementLocalname}' at root-level.") 

428 

429 def SetItem(self, item): 

430 if isinstance(item, Model): 

431 self._model = item 

432 else: 

433 raise ValueError() 

434 

435 def AddItem(self, item) -> None: 

436 if isinstance(item, BusInterface): 

437 self._busInterfaces.append(item) 

438 elif isinstance(item, IndirectInterface): 

439 self._indirectInterfaces.append(item) 

440 elif isinstance(item, Channel): 

441 self._channels.append(item) 

442 elif isinstance(item, RemapState): 

443 self._remapStates.append(item) 

444 elif isinstance(item, AddressSpace): 

445 self._addressSpaces.append(item) 

446 elif isinstance(item, MemoryMap): 

447 self._memoryMaps.append(item) 

448 elif isinstance(item, ComponentGenerator): 

449 self._componentGenerators.append(item) 

450 elif isinstance(item, Choice): 

451 self._choices.append(item) 

452 elif isinstance(item, FileSet): 

453 self.AddFileSet(item) 

454 elif isinstance(item, WhiteboxElement): 

455 self._whiteboxElements.append(item) 

456 elif isinstance(item, Cpu): 

457 self._cpus.append(item) 

458 elif isinstance(item, OtherClockDriver): 

459 self._otherClockDrivers.append(item) 

460 elif isinstance(item, ResetType): 

461 self._resetTypes.append(item) 

462 elif isinstance(item, Parameter): 

463 self._parameters.append(item) 

464 elif isinstance(item, Assertion): 

465 self._assertions.append(item) 

466 else: 

467 ex = TypeError("Parameter 'item' is not a BusInterface, IndirectInterface, Channel, RemapState, AddressSpace, MemoryMap, ComponentGenerator, Choice, FileSet, WhiteboxElement, Cpu, OtherClockDriver, ResetType, Parameter, or Assertion.") 

468 if version_info >= (3, 11): # pragma: no cover 

469 ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") 

470 raise ex 

471 

472 def AddFileSet(self, fileset: FileSet): 

473 if not isinstance(fileset, FileSet): 473 ↛ 474line 473 didn't jump to line 474 because the condition on line 473 was never true

474 ex = TypeError("Parameter 'fileset' is not a FileSet.") 

475 if version_info >= (3, 11): # pragma: no cover 

476 ex.add_note(f"Got type '{getFullyQualifiedName(fileset)}'.") 

477 raise ex 

478 

479 if fileset._name in self._fileSets: 479 ↛ 480line 479 didn't jump to line 480 because the condition on line 479 was never true

480 raise ValueError(f"Duplicate fileset '{fileset._name}'.") 

481 

482 self._fileSets[fileset._name] = fileset 

483 

484 def ToXml(self, schema: IPXACTSchema = __DEFAULT_SCHEMA__) -> str: 

485 """Converts the object's data into XML format.""" 

486 

487 xmlns = schema.NamespacePrefix 

488 buffer = dedent(f"""\ 

489 <?xml version="1.0" encoding="UTF-8" ?> 

490 <{xmlns}:component 

491 \txmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

492 \txmlns:{xmlns}="{schema.SchemaUri}" 

493 \txsi:schemaLocation="{schema.SchemaUri} {schema.SchemaUrl}"> 

494 {self._vlnv.ToXml(schema, isVersionedIdentifier=True)} 

495 \t<{xmlns}:description>{self._description}</{xmlns}:description> 

496 """) 

497 

498 if self._busInterfaces: 

499 buffer += f"\t<{xmlns}:busInterfaces>\n" 

500 for busInterface in self._busInterfaces: 

501 buffer += busInterface.ToXml(2, schema) 

502 buffer += f"\t</{xmlns}:busInterfaces>\n" 

503 

504 if self._indirectInterfaces: 

505 buffer += f"\t<{xmlns}:indirectInterfaces>\n" 

506 for indirectInterface in self._indirectInterfaces: 

507 buffer += indirectInterface.ToXml(2, schema) 

508 buffer += f"\t</{xmlns}:indirectInterfaces>\n" 

509 

510 if self._channels: 

511 buffer += f"\t<{xmlns}:channels>\n" 

512 for channel in self._channels: 

513 buffer += channel.ToXml(2, schema) 

514 buffer += f"\t</{xmlns}:channels>\n" 

515 

516 if self._remapStates: 

517 buffer += f"\t<{xmlns}:remapStates>\n" 

518 for remapState in self._remapStates: 

519 buffer += remapState.ToXml(2, schema) 

520 buffer += f"\t</{xmlns}:remapStates>\n" 

521 

522 if self._addressSpaces: 

523 buffer += f"\t<{xmlns}:addressSpaces>\n" 

524 for addressSpace in self._addressSpaces: 

525 buffer += addressSpace.ToXml(2, schema) 

526 buffer += f"\t</{xmlns}:addressSpaces>\n" 

527 

528 if self._memoryMaps: 

529 buffer += f"\t<{xmlns}:memoryMaps>\n" 

530 for memoryMap in self._memoryMaps: 

531 buffer += memoryMap.ToXml(2, schema) 

532 buffer += f"\t</{xmlns}:memoryMaps>\n" 

533 

534 if self._model: 

535 buffer += f"\t<{xmlns}:model>\n" 

536 buffer += self._model.ToXml(2, schema) 

537 buffer += f"\t</{xmlns}:model>\n" 

538 

539 if self._componentGenerators: 

540 buffer += f"\t<{xmlns}:componentGenerators>\n" 

541 for componentGenerator in self._componentGenerators: 

542 buffer += componentGenerator.ToXml(2, schema) 

543 buffer += f"\t</{xmlns}:componentGenerators>\n" 

544 

545 if self._choices: 

546 buffer += f"\t<{xmlns}:choices>\n" 

547 for choice in self._choices: 

548 buffer += choice.ToXml(2, schema) 

549 buffer += f"\t</{xmlns}:choices>\n" 

550 

551 if self._fileSets: 

552 buffer += f"\t<{xmlns}:fileSets>\n" 

553 for fileSet in self._fileSets: 

554 buffer += fileSet.ToXml(2, schema) 

555 buffer += f"\t</{xmlns}:fileSets>\n" 

556 

557 if self._whiteboxElements: 

558 buffer += f"\t<{xmlns}:whiteboxElements>\n" 

559 for whiteboxElement in self._whiteboxElements: 

560 buffer += whiteboxElement.ToXml(2, schema) 

561 buffer += f"\t</{xmlns}:whiteboxElements>\n" 

562 

563 if self._cpus: 

564 buffer += f"\t<{xmlns}:cpus>\n" 

565 for cpu in self._cpus: 

566 buffer += cpu.ToXml(2, schema) 

567 buffer += f"\t</{xmlns}:cpus>\n" 

568 

569 if self._otherClockDrivers: 

570 buffer += f"\t<{xmlns}:otherClockDrivers>\n" 

571 for otherClockDriver in self._otherClockDrivers: 

572 buffer += otherClockDriver.ToXml(2, schema) 

573 buffer += f"\t</{xmlns}:otherClockDrivers>\n" 

574 

575 if self._resetTypes: 

576 buffer += f"\t<{xmlns}:resetTypes>\n" 

577 for resetType in self._resetTypes: 

578 buffer += resetType.ToXml(2, schema) 

579 buffer += f"\t</{xmlns}:resetTypes>\n" 

580 

581 if self._parameters: 

582 buffer += f"\t<{xmlns}:parameters>\n" 

583 for parameter in self._parameters: 

584 buffer += parameter.ToXml(2, schema) 

585 buffer += f"\t</{xmlns}:parameters>\n" 

586 

587 if self._assertions: 

588 buffer += f"\t<{xmlns}:assertions>\n" 

589 for assertion in self._assertions: 

590 buffer += assertion.ToXml(2, schema) 

591 buffer += f"\t</{xmlns}:assertions>\n" 

592 

593 buffer += dedent(f"""\ 

594 </{xmlns}:component> 

595 """) 

596 

597 return buffer