/*************************************************************************** * Copyright (C) 2005-2007 Nicolas Hadacek * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "device_xml_to_data.h" #include #include #include #include bool Device::XmlToDataBase::getFrequencyRange(OperatingCondition oc, Special special, TQDomElement element) { TQDomElement range; for (TQDomNode child=element.firstChild(); !child.isNull(); child=child.nextSibling()) { if ( child.nodeName()!="frequency_range" ) continue; if ( !child.isElement() ) tqFatal("\"frequency_range\" should be an element"); if ( child.toElement().attribute("name")!=oc.key() ) continue; Special s = Special::fromKey(child.toElement().attribute("special")); if ( s==Special::Nb_Types ) tqFatal("Unrecognized special"); if ( special!=s ) continue; if ( !range.isNull() ) tqFatal("Duplicated \"frequency_range\""); range = child.toElement(); } if ( range.isNull() ) return false; FrequencyRange frange; frange.operatingCondition = oc; frange.special = special; for (TQDomNode child=range.firstChild(); !child.isNull(); child=child.nextSibling()) { if ( child.nodeName()=="frequency" ) { if ( !child.isElement() ) tqFatal("Frequency is not an element"); TQDomElement frequency = child.toElement(); bool ok1, ok2, ok3, ok4; RangeBox box; box.start.x = frequency.attribute("start").toDouble(&ok1); box.end.x = frequency.attribute("end").toDouble(&ok2); box.start.yMin = frequency.attribute("vdd_min").toDouble(&ok3); box.start.yMax = frequency.attribute("vdd_max").toDouble(&ok4); box.end.yMax = box.start.yMax; if ( !ok1 || !ok2 || !ok3 || !ok4 || box.start.x<0.0 || box.start.x>box.end.x || box.start.yMin<0.0 || box.start.yMin>box.start.yMax ) tqFatal("Malformed frequency element"); if ( frequency.attribute("vdd_min_end").isEmpty() ) box.end.yMin = box.start.yMin; else { box.end.yMin = frequency.attribute("vdd_min_end").toDouble(&ok1); if ( !ok1 || box.end.yMin>box.end.yMax ) tqFatal("Malformed frequency element"); } box.mode = frequency.attribute("mode"); box.osc = frequency.attribute("osc"); box.special = frequency.attribute("special"); for (uint i=0; ifrange.vdds[i].start.x ) { if ( box.mode.isEmpty() && box.osc.isEmpty() && box.special.isEmpty() ) tqFatal("Overlapping frequency ranges"); continue; // #### FIXME: ignore additionnal mode } // tqDebug("add Freq Range: %s %s %f=[%f %f] %f=[%f %f]", // Device::FrequencyRange::TYPE_LABELS[type], Device::FrequencyRange::SPECIAL_LABELS[type], // box.start.x, box.start.yMin, box.start.yMax, // box.end.x, box.end.yMin, box.end.yMax); frange.vdds.append(box); } } if ( frange.vdds.count()==0 ) tqFatal("Empty frequency range"); _data->_frequencyRanges.append(frange); return true; } bool Device::XmlToDataBase::getMemoryTechnology(TQDomElement element) { TQString s = element.attribute("memory_technology"); _data->_memoryTechnology = MemoryTechnology::fromKey(s); if ( _data->_memoryTechnology!=MemoryTechnology::Nb_Types ) return true; if ( !s.isNull() ) tqFatal("Unrecognized memory technology"); return false; } void Device::XmlToDataBase::processDevice(TQDomElement device) { TQString name = device.attribute("name").upper(); if ( name.isEmpty() ) tqFatal("Device has no name"); if ( _map.contains(name) ) tqFatal(TQString("Device \"%1\" already defined").arg(name)); _data = createData(); _map[name] = _data; _data->_name = name; _data->_alternatives = TQStringList::split(' ', device.attribute("alternative")); if ( _data->_alternatives.count() ) _alternatives[name] = _data->_alternatives; _data->_status = Status::fromKey(device.attribute("status")); switch (_data->_status.type()) { case Status::Nb_Types: tqFatal("Unrecognized or absent device status"); break; case Status::Future: if ( _data->_alternatives.count() ) tqFatal("Future device has alternative"); break; case Status::NotRecommended: case Status::Mature: if ( _data->_alternatives.count()==0 ) warning("Not-recommended/mature device has no alternative"); break; case Status::InProduction: case Status::EOL: case Status::Unknown: break; } // document _data->_documents.webpage = device.attribute("document"); // ### REMOVE ME TQDomElement documents = findUniqueElement(device, "documents", TQString(), TQString()); if ( documents.isNull() ) { if ( _data->_documents.webpage.isEmpty() ) tqFatal("Missing \"documents\" element"); } else { if ( !_data->_documents.webpage.isEmpty() ) tqFatal("document should be removed from root element"); _data->_documents.webpage = documents.attribute("webpage"); if ( _data->_documents.webpage.isEmpty() ) tqFatal("Missing webpage"); _data->_documents.datasheet = documents.attribute("datasheet"); TQRegExp rexp("\\d{5}"); if ( _data->_documents.datasheet=="?" ) warning("No datasheet specified"); if ( !rexp.exactMatch(_data->_documents.datasheet) ) tqFatal(TQString("Malformed datasheet \"%1\" (5 digits)").arg(_data->_documents.datasheet)); _data->_documents.progsheet = documents.attribute("progsheet"); if ( _data->_documents.progsheet=="?" ) warning("No progsheet specified"); if ( !rexp.exactMatch(_data->_documents.datasheet) ) tqFatal(TQString("Malformed progsheet \"%1\" (5 digits)").arg(_data->_documents.progsheet)); _data->_documents.erratas = TQStringList::split(" ", documents.attribute("erratas")); for (uint i=0; i_documents.erratas.count()); i++) { TQString errata = _data->_documents.erratas[i]; if ( !rexp.exactMatch(errata) ) { TQRegExp rexp2("\\d{5}e\\d"); if ( !rexp2.exactMatch(errata) && !errata.startsWith("er") && errata.mid(2)!=_data->_name.lower() ) tqFatal(TQString("Malformed erratas \"%1\" (5 digits or 5 digits + e + 1 digit or \"er\" + name)").arg(errata)); } } } if ( _data->_documents.webpage=="?" ) warning("No webpage specified"); else { TQRegExp rexp("\\d{6}"); if ( !rexp.exactMatch(_data->_documents.webpage) ) tqFatal(TQString("Malformed webpage \"%1\" (6 digits)").arg(_data->_documents.webpage)); if ( _documents.contains(_data->_documents.webpage) ) tqFatal(TQString("webpage duplicated (already used for %1)").arg(_documents[_data->_documents.webpage])); _documents[_data->_documents.webpage] = name; } // frequency ranges TQStringList names; bool ok = false; FOR_EACH(OperatingCondition, oc) { names += oc.key(); FOR_EACH(Special, special) if ( getFrequencyRange(oc, special, device) && special==Special::Normal ) ok = true; } if ( !ok ) tqWarning("No normal frequency range defined"); checkTagNames(device, "frequency_range", names); // memory technology if ( !getMemoryTechnology(device) ) tqFatal("Memory technology not defined"); // packages for (TQDomNode child=device.firstChild(); !child.isNull(); child=child.nextSibling()) { if ( !child.isElement() || child.nodeName()!="package" ) continue; Package p = processPackage(child.toElement()); TQMap pinLabels; for (uint i=0; i_packages.count()); k++) for (uint l=0; l_packages[k].types.count()); j++) if ( _data->_packages[k].types[j]==p.types[l] && _data->_packages[k].pins.count()==p.pins.count() ) tqFatal("Duplicated package type"); if ( !pinLabels.isEmpty() ) checkPins(pinLabels); _data->_packages.append(p); } } Device::Package Device::XmlToDataBase::processPackage(TQDomElement element) { Package package; // nb pins bool ok; uint nb = element.attribute("nb_pins").toUInt(&ok); if ( !ok || nb==0 ) tqFatal("Malformed \"nb_pins\""); package.pins.resize(nb); // types TQStringList types = TQStringList::split(" ", element.attribute("types")); if ( types.isEmpty() ) tqFatal("No package types specified"); for (uint k=0; k found(nb); found.fill(false); TQDomNode child = element.firstChild(); while ( !child.isNull() ) { if ( child.nodeName()=="pin" ) { if ( !child.isElement() ) tqFatal("\"pin\" is not an element"); TQDomElement pin = child.toElement(); bool ok; uint i = pin.attribute("index").toUInt(&ok); if ( !ok || i==0 || i>nb ) tqFatal("Malformed pin index"); if (found[i-1]) tqFatal("Duplicated pin index"); found[i-1] = true; TQString name = pin.attribute("name"); if ( !name.isEmpty() && name!="N/C" ) { TQStringList labels = TQStringList::split("/", name); if ( name.contains(" ") || labels.count()==0 ) tqFatal("Malformed pin name"); if ( name!=name.upper() ) tqFatal("Pin name should be uppercase"); } package.pins[i-1] = name; have_pins = true; } child = child.nextSibling(); } if ( !have_pins ) ;//warning("Pins not specified"); // #### REMOVE ME !! else for (uint i=0; i::const_iterator ait = _alternatives.begin(); for (; ait!=_alternatives.end(); ++ait) { TQStringList::const_iterator lit = ait.data().begin(); for (; lit!=ait.data().end(); ++lit) if ( !_map.contains(*lit) ) tqFatal(TQString("Unknown alternative %1 for device %2").arg((*lit)).arg(ait.key())); } }