1 #include "ReferenceBlock.h"
3 #include "ReferenceInterface.h"
4 #include "BlockParameter.h"
5 #include "BlockParameterUser.h"
6 #include "BlockParameterGeneric.h"
7 #include "BlockParameterPort.h"
8 #include "BlockParameterWishbone.h"
9 #include "Parameters.h"
11 ReferenceBlock::ReferenceBlock(const QString _xmlFile) : AbstractBlock() {
15 void ReferenceBlock::addCategory(int id) {
16 categories.append(id);
19 void ReferenceBlock::setBriefDescription(const QString& str) {
21 descriptionBrief = str;
24 void ReferenceBlock::setDetailedDescription(const QString& str) {
26 descriptionDetail = str;
29 void ReferenceBlock::addImplementation(BlockImplementation *impl) {
30 implementations.append(impl);
33 void ReferenceBlock::setHashMd5() {
35 if (file.open(QIODevice::ReadOnly)) {
36 QByteArray fileData = file.readAll();
37 QByteArray hashData = QCryptographicHash::hash(fileData, QCryptographicHash::Md5);
38 hashMd5 = QString(hashData.toHex());
39 cout << qPrintable(xmlFile) << " has md5 hash : " << qPrintable(hashMd5) << endl;
46 void ReferenceBlock::load(QDomElement &elt) throw(Exception) {
49 cout << "Block : get informations" << endl;
50 QDomElement eltInfo = elt.firstChildElement("informations");
52 loadInformations(eltInfo);
58 cout << "Block : get params" << endl;
59 QDomElement eltParams = eltInfo.nextSiblingElement("parameters");
61 loadParameters(eltParams);
67 cout << "Block : get interfaces" << endl;
68 QDomElement eltInter = eltParams.nextSiblingElement("interfaces");
70 loadInterfaces(eltInter);
76 // create interfaces that correspond to a wishbone parameter, if any.
78 createInterfaceForParameters();
85 void ReferenceBlock::loadInformations(QDomElement &elt) throw(Exception) {
88 if ((elt.isNull()) || (elt.tagName() != "informations")) throw (Exception(BLOCKFILE_CORRUPTED));
90 cout << "Block info : get name" << endl;
91 QDomNode nodeName = elt.firstChild();
92 QDomNode nodeNameTxt = nodeName.firstChild();
93 if (nodeNameTxt.isNull()) {
97 QDomText txtName = nodeNameTxt.toText();
98 name = Parameters::normalizeName(txtName.data().trimmed());
99 cout<< "block name : " << qPrintable(name) << endl;
102 // getting categories
103 cout << "Block info : get categories" << endl;
104 QDomElement eltCat = nodeName.nextSiblingElement("category");
106 QString idsStr = eltCat.attribute("ids","none");
107 if (idsStr == "none") throw (Exception(BLOCKFILE_CORRUPTED));
108 if (idsStr.isEmpty()) {
109 categories.append(99);
112 QStringList listCat = idsStr.split(",");
113 foreach(QString str, listCat)
115 int idCat = str.toInt(&ok);
116 categories.append(idCat);
120 // getting description
121 cout << "Block info : get description" << endl;
122 QDomElement eltDesc = eltCat.nextSiblingElement("description");
124 QDomElement eltBrief = eltDesc.firstChildElement("brief");
125 QDomNode nodeBriefTxt = eltBrief.firstChild();
126 if (nodeBriefTxt.isNull()) {
127 descriptionBrief = "no brief description";
130 QDomText txtBrief = nodeBriefTxt.toText();
131 descriptionBrief = txtBrief.data().trimmed();
132 cout << "block brief desc : " << qPrintable(descriptionBrief) << endl;
135 QDomElement eltDetail = eltBrief.nextSiblingElement("detailed");
136 QDomNode nodeDetailTxt = eltDetail.firstChild();
137 if (nodeDetailTxt.isNull()) {
138 descriptionDetail = "no detailed description";
141 QDomText txtDetail = nodeDetailTxt.toText();
142 descriptionDetail = txtDetail.data().trimmed();
143 cout << "block detail desc : " << qPrintable(descriptionDetail) << endl;
147 void ReferenceBlock::loadParameters(QDomElement &elt) throw(Exception) {
149 if ((elt.isNull()) || (elt.tagName() != "parameters")) throw (Exception(BLOCKFILE_CORRUPTED));
151 QDomNodeList listNodeParam = elt.elementsByTagName("parameter");
152 for(int i=0; i<listNodeParam.size(); i++) {
153 QDomNode node = listNodeParam.at(i);
154 QDomElement elt = node.toElement();
155 QString nameStr = elt.attribute("name","none");
156 QString contextStr = elt.attribute("context","none");
157 QString typeStr = elt.attribute("type","none");
158 QString valueStr = elt.attribute("value","none");
159 BlockParameter *param = NULL;
161 if(valueStr == "none"){
162 if (contextStr == "generic") throw (Exception(BLOCKFILE_CORRUPTED)); // set is required for generics
165 if (contextStr == "user") {
166 param = new BlockParameterUser(this,nameStr,typeStr,valueStr);
168 else if (contextStr == "generic") {
169 param = new BlockParameterGeneric(this,nameStr,typeStr,valueStr);
171 else if (contextStr == "wb") {
172 QString widthStr = elt.attribute("width","none");
173 QString wbStr = elt.attribute("wishbone","none");
176 QString wbValue = "";
177 QStringList listWb = wbStr.split(",");
178 cout << "wb param has:";
179 foreach(QString s, listWb) {
180 cout << qPrintable(s) << " | ";
184 if (listWb.at(0) == "r") {
185 access = BlockParameter::Read;
187 else if (listWb.at(0) == "w") {
188 access = BlockParameter::Write;
190 wbValue = listWb.at(1).toInt(&ok);
192 if(listWb.at(1) == "true" || listWb.at(1) == "false"){
193 wbValue = listWb.at(1);
198 if(listWb.at(2) == "trigger") {
199 duration = BlockParameter::Trigger;
201 else if(listWb.at(2) == "perm") {
202 duration = BlockParameter::Permanent;
205 param = new BlockParameterWishbone(this,nameStr,typeStr,widthStr,valueStr,access,wbValue,duration);
207 else if (contextStr == "port") {
208 QString ifaceStr = elt.attribute("iface","none");
209 param = new BlockParameterPort(this,nameStr,valueStr,ifaceStr);
213 throw (Exception(BLOCKFILE_CORRUPTED));
215 params.append(param);
219 void ReferenceBlock::loadInterfaces(QDomElement &elt) throw(Exception) {
230 AbstractInterface* inter;
232 if ((elt.isNull()) || (elt.tagName() != "interfaces")) throw (Exception(BLOCKFILE_CORRUPTED));
234 QDomElement eltInputs = elt.firstChildElement("inputs");
235 // getting each input
236 QDomNodeList listNodeInputs = eltInputs.elementsByTagName("input");
238 // find all input clocks
239 QList<AbstractInterface*> clocks;
240 for(int i=0;i<listNodeInputs.size();i++) {
241 QDomNode node = listNodeInputs.at(i);
242 QDomElement eltInput = node.toElement();
243 purposeStr = eltInput.attribute("purpose","none");
244 if (purposeStr == "clock") {
245 nameStr = eltInput.attribute("name","none");
246 inter = new ReferenceInterface(this,nameStr,AbstractInterface::Input, AbstractInterface::Clock, "boolean", "1", AbstractInterface::LittleEndian, 1);
247 inputs.append(inter);
248 clocks.append(inter);
251 cout << "number of clocks: " << clocks.size() << endl;
254 for(int i=0;i<listNodeInputs.size();i++) {
255 QDomNode node = listNodeInputs.at(i);
256 QDomElement eltInput = node.toElement();
257 purposeStr = eltInput.attribute("purpose","none");
258 purpose = ReferenceInterface::translatePurpose(purposeStr);
259 if (purpose != AbstractInterface::Clock) {
260 cout << "translated purpose : " << purpose << endl;
261 nameStr = eltInput.attribute("name","none");
262 typeStr = eltInput.attribute("type","none");
263 widthStr = eltInput.attribute("width","none");
264 endianStr = eltInput.attribute("endian","none");
265 clockStr = eltInput.attribute("clock","none");
267 if ((endianStr == "none") || (endianStr == "little")) {
268 endianess = AbstractInterface::LittleEndian;
270 else if (endianStr == "big") {
271 endianess = AbstractInterface::BigEndian;
274 throw (Exception(BLOCKFILE_CORRUPTED));
277 multStr = eltInput.attribute("multiplicity","none");
278 mult = ReferenceInterface::translateMultiplicity(multStr);
280 inter = new ReferenceInterface(this,nameStr, AbstractInterface::Input, purpose, typeStr, widthStr, endianess, mult);
281 if (clockStr == "none") {
282 // no clock given, take the first one (hope that there is a single one !)
283 clockStr = clocks.at(0)->getName();
285 if (! inter->setClockIface(clockStr)) {
286 throw (Exception(BLOCKFILE_CORRUPTED));
288 inputs.append(inter);
291 // getting each control
292 QDomNodeList listNodeInCtl = eltInputs.elementsByTagName("control");
293 for(int i=0;i<listNodeInCtl.size();i++) {
294 QDomNode node = listNodeInCtl.at(i);
295 QDomElement eltInput = node.toElement();
296 nameStr = eltInput.attribute("iface","none");
297 AbstractInterface* dataIface = getIfaceFromName(nameStr);
298 if (dataIface == NULL) throw (Exception(BLOCKFILE_CORRUPTED));
299 nameStr = dataIface->getName()+"_enb";
300 inter = new ReferenceInterface(this,nameStr,AbstractInterface::Input, AbstractInterface::Control,"boolean","1", AbstractInterface::LittleEndian, 1);
301 if (!inter->setAssociatedIface(dataIface)) {
302 throw (Exception(BLOCKFILE_CORRUPTED));
304 cout << "created a control input named " << qPrintable(inter->getName()) << endl;
305 inputs.append(inter);
307 QDomElement eltOutputs = eltInputs.nextSiblingElement("outputs");
308 QDomNodeList listNodeOutputs = eltOutputs.elementsByTagName("output");
309 for(int i=0;i<listNodeOutputs.size();i++) {
310 QDomNode node = listNodeOutputs.at(i);
311 QDomElement eltOutput = node.toElement();
313 nameStr = eltOutput.attribute("name","none");
314 typeStr = eltOutput.attribute("type","none");
315 widthStr = eltOutput.attribute("width","none");
316 endianStr = eltOutput.attribute("endian","none");
317 clockStr = eltOutput.attribute("clock","none");
319 if ((endianStr == "none") || (endianStr == "little")) {
320 endianess = AbstractInterface::LittleEndian;
322 else if (endianStr == "big") {
323 endianess = AbstractInterface::BigEndian;
326 throw (Exception(BLOCKFILE_CORRUPTED));
328 purposeStr = eltOutput.attribute("purpose","none");
329 purpose = ReferenceInterface::translatePurpose(purposeStr);
330 multStr = eltOutput.attribute("multiplicity","none");
331 mult = ReferenceInterface::translateMultiplicity(multStr);
333 inter = new ReferenceInterface(this,nameStr,AbstractInterface::Output, purpose,typeStr,widthStr, endianess, mult);
334 if (clockStr == "none") {
335 // no clock given, take the first one (hope that there is a single one !)
336 clockStr = clocks.at(0)->getName();
338 if (! inter->setClockIface(clockStr)) {
339 throw (Exception(BLOCKFILE_CORRUPTED));
341 outputs.append(inter);
343 // getting each control
344 QDomNodeList listNodeOutCtl = eltOutputs.elementsByTagName("control");
345 for(int i=0;i<listNodeOutCtl.size();i++) {
346 QDomNode node = listNodeOutCtl.at(i);
347 QDomElement eltOutput = node.toElement();
348 nameStr = eltOutput.attribute("iface","none");
349 AbstractInterface* dataIface = getIfaceFromName(nameStr);
350 if (dataIface == NULL) throw (Exception(BLOCKFILE_CORRUPTED));
351 nameStr = dataIface->getName()+"_enb";
352 inter = new ReferenceInterface(this,nameStr,AbstractInterface::Output, AbstractInterface::Control,"boolean","1",AbstractInterface::LittleEndian, 1);
353 if (!inter->setAssociatedIface(dataIface)) {
354 throw (Exception(BLOCKFILE_CORRUPTED));
356 cout << "created a control output named " << qPrintable(inter->getName()) << endl;
357 outputs.append(inter);
360 QDomElement eltBidirs = eltInputs.nextSiblingElement("bidirs");
361 QDomNodeList listNodeBidirs = eltBidirs.elementsByTagName("bidir");
362 for(int i=0;i<listNodeBidirs.size();i++) {
363 QDomNode node = listNodeBidirs.at(i);
364 QDomElement eltBidir = node.toElement();
365 nameStr = eltBidir.attribute("name","none");
366 typeStr = eltBidir.attribute("type","none");
367 widthStr = eltBidir.attribute("width","none");
368 endianStr = eltBidir.attribute("endian","none");
369 clockStr = eltBidir.attribute("clock","none");
371 if ((endianStr == "none") || (endianStr == "little")) {
372 endianess = AbstractInterface::LittleEndian;
374 else if (endianStr == "big") {
375 endianess = AbstractInterface::BigEndian;
378 throw (Exception(BLOCKFILE_CORRUPTED));
380 purposeStr = eltBidir.attribute("purpose","none");
381 purpose = ReferenceInterface::translatePurpose(purposeStr);
382 multStr = eltBidir.attribute("multiplicity","none");
383 mult = ReferenceInterface::translateMultiplicity(multStr);
385 inter = new ReferenceInterface(this,nameStr,AbstractInterface::InOut, purpose,typeStr,widthStr, endianess, mult);
386 if (clockStr == "none") {
387 // no clock given, take the first one (hope that there is a single one !)
388 clockStr = clocks.at(0)->getName();
390 if (! inter->setClockIface(clockStr)) {
391 throw (Exception(BLOCKFILE_CORRUPTED));
393 bidirs.append(inter);
397 void ReferenceBlock::createInterfaceForParameters() throw(Exception){
398 ReferenceInterface* iface = NULL;
399 foreach(BlockParameter* param, params) {
401 if (param->isWishboneParameter()) {
403 BlockParameterWishbone* p = (BlockParameterWishbone*)param;
404 cout << "creating interface for parameter wb " << qPrintable(p->getName()) << endl;
406 if (p->getWBAccess() == BlockParameter::Read) {
407 iface = new ReferenceInterface(this,p->getName(), AbstractInterface::Output, AbstractInterface::Wishbone, p->getTypeString(),p->getWidth(), AbstractInterface::LittleEndian, 1);
408 outputs.append(iface);
410 else if (p->getWBAccess() == BlockParameter::Write) {
411 iface = new ReferenceInterface(this,p->getName(), AbstractInterface::Input, AbstractInterface::Wishbone,p->getTypeString(),p->getWidth(),AbstractInterface::LittleEndian,1);
412 inputs.append(iface);
415 throw (Exception(BLOCKFILE_CORRUPTED));
421 void ReferenceBlock::parametersValidation(QList<AbstractBlock *> *checkedBlocks, QList<AbstractBlock *> *blocksToConfigure) {
426 only used to save all ReferenceBlock in a library in binary format, so that reference blocks
427 are read very fast at application startup.
430 QDataStream& operator<<(QDataStream &out, const ReferenceBlock &b) {
432 out.setVersion(QDataStream::Qt_5_0);
434 QByteArray blockData;
435 QDataStream toWrite(&blockData, QIODevice::WriteOnly);
438 toWrite << b.xmlFile;
439 toWrite << b.descriptionBrief;
440 toWrite << b.descriptionDetail;
441 toWrite << b.categories;
442 toWrite << b.hashMd5;
443 toWrite << b.params.size();
445 for(int i=0;i<b.params.size();i++) {
447 toWrite << p->getContext();
448 toWrite << p->getName();
449 toWrite << p->getTypeString();
450 toWrite << p->getValue().toString();
451 if (p->isPortParameter()) {
452 toWrite << ((BlockParameterPort*)p)->getIfaceName();
454 else if (p->isWishboneParameter()) {
455 BlockParameterWishbone* pwb = (BlockParameterWishbone*)p;
456 toWrite << pwb->getWidth();
457 toWrite << pwb->getWBAccess();
458 toWrite << pwb->getWBValue();
459 toWrite << pwb->getWBDuration();
464 toWrite << b.inputs.size();
465 // firstly write clock ifaces
466 for(int i=0; i<b.inputs.size(); i++){
467 ReferenceInterface *iface = (ReferenceInterface *)(b.inputs.at(i));
468 if (iface->getPurpose() == AbstractInterface::Clock) {
469 toWrite << iface->getName();
470 toWrite << iface->getType();
471 toWrite << iface->getWidthString();
472 toWrite << iface->getPurpose();
473 toWrite << iface->getDirection();
474 toWrite << iface->getMultiplicity();
475 toWrite << iface->getClockIfaceType();
476 toWrite << iface->getClockIfaceString();
479 // secondly write control ifaces
480 for(int i=0; i<b.inputs.size(); i++){
481 ReferenceInterface *iface = (ReferenceInterface *)(b.inputs.at(i));
482 if (iface->getPurpose() == AbstractInterface::Control) {
483 toWrite << iface->getName();
484 toWrite << iface->getType();
485 toWrite << iface->getWidthString();
486 toWrite << iface->getPurpose();
487 toWrite << iface->getDirection();
488 toWrite << iface->getMultiplicity();
489 toWrite << iface->getClockIfaceType();
490 toWrite << iface->getClockIfaceString();
493 // secondly, write other ifaces
494 for(int i=0; i<b.inputs.size(); i++){
495 ReferenceInterface *iface = (ReferenceInterface *)(b.inputs.at(i));
496 if ((iface->getPurpose() != AbstractInterface::Control) && (iface->getPurpose() != AbstractInterface::Clock)) {
497 toWrite << iface->getName();
498 toWrite << iface->getType();
499 toWrite << iface->getWidthString();
500 toWrite << iface->getPurpose();
501 toWrite << iface->getDirection();
502 toWrite << iface->getMultiplicity();
503 toWrite << iface->getClockIfaceType();
504 toWrite << iface->getClockIfaceString();
507 toWrite << b.outputs.size();
508 // firstly write control ifaces
509 for(int i=0; i<b.outputs.size(); i++){
510 ReferenceInterface *iface = (ReferenceInterface *)(b.outputs.at(i));
511 if (iface->getPurpose() == AbstractInterface::Control) {
512 toWrite << iface->getName();
513 toWrite << iface->getType();
514 toWrite << iface->getWidthString();
515 toWrite << iface->getPurpose();
516 toWrite << iface->getDirection();
517 toWrite << iface->getMultiplicity();
518 toWrite << iface->getClockIfaceType();
519 toWrite << iface->getClockIfaceString();
522 // secondly, write other ifaces
523 for(int i=0; i<b.outputs.size(); i++){
524 ReferenceInterface *iface = (ReferenceInterface *)(b.outputs.at(i));
525 if (iface->getPurpose() != AbstractInterface::Control) {
526 toWrite << iface->getName();
527 toWrite << iface->getType();
528 toWrite << iface->getWidthString();
529 toWrite << iface->getPurpose();
530 toWrite << iface->getDirection();
531 toWrite << iface->getMultiplicity();
532 toWrite << iface->getClockIfaceType();
533 toWrite << iface->getClockIfaceString();
536 toWrite << b.bidirs.size();
537 for(int i=0; i<b.bidirs.size(); i++){
538 ReferenceInterface *iface = (ReferenceInterface *)(b.bidirs.at(i));
539 toWrite << iface->getName();
540 toWrite << iface->getType();
541 toWrite << iface->getWidthString();
542 toWrite << iface->getPurpose();
543 toWrite << iface->getDirection();
544 toWrite << iface->getMultiplicity();
545 toWrite << iface->getClockIfaceType();
546 toWrite << iface->getClockIfaceString();
554 QDataStream& operator>>(QDataStream &in, ReferenceBlock &b) {
557 ReferenceInterface* iface;
562 in.setVersion(QDataStream::Qt_5_0);
568 in >> b.descriptionBrief;
569 in >> b.descriptionDetail;
575 cout << qPrintable(b.name) << " has " << nb << " parameters" << endl;
576 for(int i=0;i<nb;i++) {
577 QString contextStr = "";
579 QString typeStr = "";
580 QString valueStr = "";
586 if (contextStr == "user") {
587 p = new BlockParameterUser(&b,nameStr,typeStr,valueStr);
589 else if (contextStr == "generic") {
590 p = new BlockParameterGeneric(&b,nameStr,typeStr,valueStr);
592 else if (contextStr == "port") {
593 QString ifaceStr = "";
595 p = new BlockParameterPort(&b,nameStr,valueStr,ifaceStr);
597 else if (contextStr == "wb") {
598 QString widthStr = "";
606 p = new BlockParameterWishbone(&b,nameStr,typeStr,widthStr,valueStr,wbAccess,wbValue,wbDuration);
613 for(int i=0;i<nb;i++) {
614 iface = new ReferenceInterface(&b);
619 iface->setType(type);
621 iface->setWidth(txt);
623 iface->setPurpose(val);
625 iface->setDirection(val);
627 iface->setMultiplicity(val);
632 if (clkType == AbstractInterface::ParameterName) {
635 if (! iface->setClockIface(clk)) {
636 cerr << "Abnormal case while reading a reference block in library: cannot set ref clock for an interface" << endl;
639 b.inputs.append(iface);
640 if (iface->getPurpose() == AbstractInterface::Data) {
641 QString ctlRefName = iface->getName()+"_enb";
642 ReferenceInterface* ctlRefIface = AI_TO_REF(b.getIfaceFromName(ctlRefName));
643 if (ctlRefIface != NULL) {
644 if (! ctlRefIface->setAssociatedIface(iface)) {
645 cerr << "Abnormal case while reading a reference block in library: cannot set associated control interface for data interface" << endl;
653 for(int i=0;i<nb;i++) {
654 iface = new ReferenceInterface(&b);
659 iface->setType(type);
661 iface->setWidth(txt);
663 iface->setPurpose(val);
665 iface->setDirection(val);
667 iface->setMultiplicity(val);
672 if (clkType == AbstractInterface::ParameterName) {
675 if (! iface->setClockIface(clk)) {
676 cerr << "Abnormal case while reading a reference block in library: cannot set ref clock for an interface" << endl;
678 b.outputs.append(iface);
679 if (iface->getPurpose() == AbstractInterface::Data) {
680 QString ctlRefName = iface->getName()+"_enb";
681 ReferenceInterface* ctlRefIface = AI_TO_REF(b.getIfaceFromName(ctlRefName));
682 if (ctlRefIface != NULL) {
683 if (! ctlRefIface->setAssociatedIface(iface)) {
684 cerr << "Abnormal case while reading a reference block in library" << endl;
692 for(int i=0;i<nb;i++) {
693 iface = new ReferenceInterface(&b);
698 iface->setType(type);
700 iface->setWidth(txt);
702 iface->setPurpose(val);
704 iface->setDirection(val);
706 iface->setMultiplicity(val);
711 if (clkType == AbstractInterface::ParameterName) {
714 if (! iface->setClockIface(clk)) {
715 cerr << "Abnormal case while reading a reference block in library: cannot set ref clock for an interface" << endl;
717 b.bidirs.append(iface);
723 void ReferenceBlock::checkInputPatternCompatibility() throw(Exception){
724 throw(Exception(INVALID_REFBLOCK_USE));
727 void ReferenceBlock::computeOutputPattern(int nbExec) throw(Exception) {
728 // does strictly nothing
729 throw(Exception(INVALID_REFBLOCK_USE));
732 void ReferenceBlock::computeAdmittanceDelays() throw(Exception) {
733 // does strictly nothing
734 throw(Exception(INVALID_REFBLOCK_USE));
738 void ReferenceBlock::generateVHDL(const QString& path) throw(Exception){
739 throw(Exception(INVALID_REFBLOCK_USE));
742 void ReferenceBlock::generateComments(QTextStream& out, QDomElement &elt, QString coreFile) throw(Exception) {
743 throw(Exception(INVALID_REFBLOCK_USE));
746 void ReferenceBlock::generateLibraries(QTextStream& out, QDomElement &elt) throw(Exception) {
747 throw(Exception(INVALID_REFBLOCK_USE));
750 void ReferenceBlock::generateArchitecture(QTextStream& out, QDomElement &elt ) throw(Exception) {
751 throw(Exception(INVALID_REFBLOCK_USE));
754 void ReferenceBlock::generateController(QTextStream& out) throw(Exception) {
755 throw(Exception(INVALID_REFBLOCK_USE));
758 void ReferenceBlock::generateEntityOrComponentBody(QTextStream &out, int indentLevel, bool hasController) throw(Exception) {
759 throw(Exception(INVALID_REFBLOCK_USE));
762 QList<QString> ReferenceBlock::getExternalResources() {