From f508189682b6fba62e08feeb1596f682bad5fff9 Mon Sep 17 00:00:00 2001 From: tpearson Date: Wed, 24 Feb 2010 18:42:24 +0000 Subject: Added KDE3 version of PikLab git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/piklab@1095639 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- src/devices/base/Makefile.am | 9 + src/devices/base/base.pro | 6 + src/devices/base/device_group.cpp | 362 ++++++++++++++++++++++++++++++++++++ src/devices/base/device_group.h | 87 +++++++++ src/devices/base/generic_device.cpp | 216 +++++++++++++++++++++ src/devices/base/generic_device.h | 171 +++++++++++++++++ src/devices/base/generic_memory.cpp | 48 +++++ src/devices/base/generic_memory.h | 47 +++++ src/devices/base/hex_buffer.cpp | 290 +++++++++++++++++++++++++++++ src/devices/base/hex_buffer.h | 51 +++++ src/devices/base/register.cpp | 156 ++++++++++++++++ src/devices/base/register.h | 130 +++++++++++++ 12 files changed, 1573 insertions(+) create mode 100644 src/devices/base/Makefile.am create mode 100644 src/devices/base/base.pro create mode 100644 src/devices/base/device_group.cpp create mode 100644 src/devices/base/device_group.h create mode 100644 src/devices/base/generic_device.cpp create mode 100644 src/devices/base/generic_device.h create mode 100644 src/devices/base/generic_memory.cpp create mode 100644 src/devices/base/generic_memory.h create mode 100644 src/devices/base/hex_buffer.cpp create mode 100644 src/devices/base/hex_buffer.h create mode 100644 src/devices/base/register.cpp create mode 100644 src/devices/base/register.h (limited to 'src/devices/base') diff --git a/src/devices/base/Makefile.am b/src/devices/base/Makefile.am new file mode 100644 index 0000000..836da68 --- /dev/null +++ b/src/devices/base/Makefile.am @@ -0,0 +1,9 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO + +noinst_LTLIBRARIES = libdevicebase.la +libdevicebase_la_LDFLAGS = $(all_libraries) +libdevicebase_la_SOURCES = generic_device.cpp hex_buffer.cpp generic_memory.cpp \ + register.cpp device_group.cpp + + diff --git a/src/devices/base/base.pro b/src/devices/base/base.pro new file mode 100644 index 0000000..f74efc6 --- /dev/null +++ b/src/devices/base/base.pro @@ -0,0 +1,6 @@ +STOPDIR = ../../.. +include($${STOPDIR}/lib.pro) + +TARGET = devicebase +HEADERS += generic_device.h hex_buffer.h generic_memory.h device_group.h register.h +SOURCES += generic_device.cpp hex_buffer.cpp generic_memory.cpp register.cpp diff --git a/src/devices/base/device_group.cpp b/src/devices/base/device_group.cpp new file mode 100644 index 0000000..df230d1 --- /dev/null +++ b/src/devices/base/device_group.cpp @@ -0,0 +1,362 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 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_group.h" + +#if !defined(NO_KDE) +# include +# include + +QColor Device::statusColor(Status status) +{ + switch (status.type()) { + case Status::Future: return Qt::blue; + case Status::InProduction: return Qt::green; + case Status::Mature: + case Status::NotRecommended: return QColor("orange"); + case Status::EOL: return Qt::red; + case Status::Unknown: + case Status::Nb_Types: break; + } + return Qt::black; +} + +QString coloredString(const QString &text, QColor color) +{ + return QString("" + text + ""; +} + +QString supportedString(bool supported) +{ + return coloredString(supported ? i18n("Supported") : i18n("Unsupported"), + supported ? Qt::green : Qt::red); +} + +class Tick { +public: + Tick() {} + Tick(double value, double oValue) { + s = KGlobal::locale()->formatNumber(value, 1); + min = oValue; + } + QString s; + double min; +}; + +class TickMap : public QMap +{ +public: + TickMap() {} + void add(double value, double oValue) { + insert(value, Tick(value, oValue), false); + (*this)[value].min = QMIN((*this)[value].min, oValue); + } +}; + +QPixmap drawGraph(const QValueVector &boxes) +{ + const uint w = 300, h = 200; + QPixmap pixmap(w, h); + pixmap.fill(Qt::white); + QPainter p(&pixmap); + QFontMetrics f(p.font()); + TickMap xTicks, yTicks; + xTicks.add(0.0, 0.0); + yTicks.add(0.0, 0.0); + for (uint i=0; i &boxes) +{ + uint sp = 10; + QPixmap graph = drawGraph(boxes); + QPainter p; + QFontMetrics f(p.font()); + QPixmap pixmap(graph.width() + sp + f.width(xLabel), graph.height() + sp + f.lineSpacing()); + pixmap.fill(Qt::white); + copyBlt(&pixmap, 0, f.lineSpacing() + sp, &graph, 0, 0, graph.width(), graph.height()); + p.begin(&pixmap); + p.setPen(Qt::black); + p.drawText(0, f.lineSpacing(), yLabel); + p.drawText(pixmap.width()-1-f.width(xLabel), pixmap.height()-1, xLabel); + return pixmap; +} + +const Device::Package *Device::barPackage(const char *name, const Device::Data &data) +{ + for (uint i=0; i%2").arg(href).arg(data.alternatives()[i].upper()); + } + } + doc += htmlTableRow(i18n("Alternatives"), s); + } + doc += documentHtml; + doc += ""; + + doc += "
"; + doc += ""; + doc += data.group().informationHtml(data); + QString s; + for (uint i=0; i
"; + for (uint k=0; ktypes.count(); k++) { + if ( k!=0 ) doc += " "; + doc += i18n(Package::TYPE_DATA[package->types[k]].label); + doc += "(" + QString::number(package->pins.count()) + ")"; + } + doc += "
"; + QString label = data.name() + "_pins_graph.png"; + doc += ""; + if (msf) msf->setPixmap(label, pix); + doc += "
"; + } + return doc; +} + +QString Device::htmlVoltageFrequencyGraphs(const Device::Data &data, const QString &imagePrefix, QMimeSourceFactory *msf) +{ + QString doc; + FOR_EACH(Special, special) { + for (uint k=0; k"; + QString label = data.name() + "_" + data.fname(special) + "_" + + fr.operatingCondition.key() + ".png"; + doc += ""; + if (msf) msf->setPixmap(label, Device::vddGraph(i18n("F (MHz)"), i18n("Vdd (V)"), fr.vdds)); + } + } + return doc; +} + +QPixmap Device::memoryGraph(const QValueList &r) +{ + QValueList ranges = r; + QPixmap pixmap; + QPainter p; + QFontMetrics fm(p.font()); + // order + qHeapSort(ranges); + // add empty ranges + QValueList::iterator it; + for (it=ranges.begin(); it!=ranges.end(); ) { + QValueList::iterator prev = it; + ++it; + if ( it==ranges.end() ) break; + if ( (*prev).endAddress+1==(*it).startAddress ) continue; + MemoryGraphData data; + data.startAddress = (*prev).endAddress + 1; + data.endAddress = (*it).startAddress-1; + ranges.insert(it, data); + } + // compute widths and total height + int theight = fm.ascent() + (fm.ascent()%2==0 ? 1 : 0); + int hspacing = 5; + int height = 1; + int w1 = 0, w2 = 0; + for (it=ranges.begin(); it!=ranges.end(); ++it) { + w1 = QMAX(w1, fm.width((*it).start)); + w1 = QMAX(w1, fm.width((*it).end)); + w2 = QMAX(w2, fm.width((*it).label)); + (*it).height = 2*hspacing + theight; + if ( (*it).startAddress!=(*it).endAddress ) (*it).height += 2*theight; + height += (*it).height; + } + int wspacing = 4; + int width = wspacing + w1 + wspacing + wspacing + w2; + pixmap.resize(width, height); + pixmap.fill(Qt::white); + p.begin(&pixmap); + int h = 0; + // draw ranges + for (it=ranges.begin(); it!=ranges.end(); ++it) { + p.setPen(QPen(Qt::black, 1, Qt::DotLine)); + p.drawLine(0,h, width-1,h); + p.setPen(QPen(Qt::black, 1)); + p.setBrush((*it).label.isEmpty() ? Qt::gray : Qt::white); + p.drawRect(0,h, wspacing+w1+wspacing,(*it).height+1); + int hmid = h+(*it).height/2+theight/2; + p.drawText(wspacing+w1+wspacing+wspacing,hmid, (*it).label); + if ( (*it).startAddress==(*it).endAddress ) p.drawText(wspacing,hmid, (*it).start); + else { + p.drawText(wspacing,h+theight, (*it).start); + p.drawText(wspacing,h+(*it).height-3, (*it).end); + } + h += (*it).height; + p.setPen(QPen(Qt::black, 1, Qt::DotLine)); + p.drawLine(0,h, width-1,h); + } + p.end(); + return pixmap; +} + +#endif diff --git a/src/devices/base/device_group.h b/src/devices/base/device_group.h new file mode 100644 index 0000000..087ca99 --- /dev/null +++ b/src/devices/base/device_group.h @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 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. * + ***************************************************************************/ +#ifndef DEVICE_GROUP_H +#define DEVICE_GROUP_H + +#if !defined(NO_KDE) +# include +#endif + +#include "generic_device.h" +#include "common/common/group.h" +#include "common/common/streamer.h" +namespace Debugger { class DeviceSpecific; class Base; } + +namespace Device +{ +class Memory; + +//---------------------------------------------------------------------------- +class MemoryRange { +public: + MemoryRange() {} + virtual ~MemoryRange() {} + virtual bool all() const { return true; } +}; + +//---------------------------------------------------------------------------- +class GroupBase : public ::Group::Base +{ +public: + virtual Memory *createMemory(const Device::Data &data) const = 0; + virtual QString informationHtml(const Device::Data &data) const = 0; +#if !defined(NO_KDE) + virtual QPixmap memoryGraph(const Device::Data &data) const = 0; +#endif + +protected: + virtual void addDevice(const QString &name, const Device::Data *data, ::Group::Support support) { + const_cast(data)->_group = this; + ::Group::Base::addDevice(name, data, support); + } +}; + +template +class Group : public GroupBase, public DataStreamer +{ +protected: + virtual void initSupported() { + QValueList list = fromCppString(dataStream(), dataSize()); + for (uint i=0; iname(), list[i], ::Group::Support::Tested); + } + virtual uint dataSize() const = 0; + virtual const char *dataStream() const = 0; +}; + +//---------------------------------------------------------------------------- +#if !defined(NO_KDE) +extern QColor statusColor(Status status); +extern QPixmap vddGraph(const QString &xLabel, const QString &yLabel, const QValueVector &boxes); +extern const Package *barPackage(const char *name, const Data &data); +extern QPixmap pinsGraph(const Package &package); + +extern QString htmlInfo(const Data &data, const QString &deviceHref, const QString &documentHtml); +extern QString htmlPinDiagrams(const Device::Data &data, const QString &imagePrefix, QMimeSourceFactory *msf); +extern QString htmlVoltageFrequencyGraphs(const Device::Data &data, const QString &imagePrefix, QMimeSourceFactory *msf); + +class MemoryGraphData +{ +public: + Address startAddress, endAddress; + QString start, end, label; + int height; + bool operator <(const MemoryGraphData &data) const { return ( startAddress < data.startAddress ); } +}; +extern QPixmap memoryGraph(const QValueList &ranges); + +#endif + +} // namespace + +#endif diff --git a/src/devices/base/generic_device.cpp b/src/devices/base/generic_device.cpp new file mode 100644 index 0000000..bf69dce --- /dev/null +++ b/src/devices/base/generic_device.cpp @@ -0,0 +1,216 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 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 "generic_device.h" + +#include "common/global/global.h" +#include "device_group.h" +#include "register.h" + +//----------------------------------------------------------------------------- +const Device::Status::Data Device::Status::DATA[Nb_Types] = { + { "IP", I18N_NOOP("In Production") }, + { "Future", I18N_NOOP("Future Product") }, + { "NR", I18N_NOOP("Not Recommended for New Design") }, + { "EOL", I18N_NOOP("End Of Life" ) }, + { "?", I18N_NOOP("Unknown") }, + { "Mature", I18N_NOOP("Mature") } +}; + +const Device::MemoryTechnology::Data Device::MemoryTechnology::DATA[Nb_Types] = { + { "FLASH", I18N_NOOP("Flash") }, + { "EPROM", I18N_NOOP("EPROM (OTP)") }, + { "ROM", I18N_NOOP("ROM") }, + { "ROMLESS", I18N_NOOP("ROM-less") } +}; + +const Device::OperatingCondition::Data Device::OperatingCondition::DATA[Nb_Types] = { + { "commercial", I18N_NOOP("Commercial") }, + { "industrial", I18N_NOOP("Industrial") }, + { "extended", I18N_NOOP("Extended") } +}; + +const Device::Special::Data Device::Special::DATA[Nb_Types] = { + { "", I18N_NOOP("Normal") }, + { "low_power", I18N_NOOP("Low Power") }, + { "low_voltage", I18N_NOOP("Low Voltage") }, + { "high_voltage", I18N_NOOP("High Voltage") } +}; + +const Device::Package::TypeData Device::Package::TYPE_DATA[] = { + { "pdip", I18N_NOOP("PDIP"), Bar, { 8, 14, 18, 20, 28, 40, 0, 0, 0 } }, + { "sdip", I18N_NOOP("SDIP"), Bar, { 0, 0, 0, 0, 28, 0, 0, 0, 0 } }, // skinny + { "spdip", I18N_NOOP("SPDIP"), Bar, { 0, 0, 0, 0, 28, 0, 64, 0, 0 } }, // shrink + { "sot23", I18N_NOOP("SOT-23"), Bar, { 5, 6, 0, 0, 0, 0, 0, 0, 0 } }, + { "msop", I18N_NOOP("MSOP"), Bar, { 8, 0, 0, 0, 0, 0, 0, 0, 0 } }, + { "ssop", I18N_NOOP("SSOP"), Bar, { 0, 0, 0, 20, 28, 0, 0, 0, 0 } }, + { "tssop", I18N_NOOP("TSSOP"), Bar, { 8, 14, 0, 0, 0, 0, 0, 0, 0 } }, + { "soic", I18N_NOOP("SOIC"), Bar, { 8, 14, 18, 20, 28, 0, 0, 0, 0 } }, + { "tqfp", I18N_NOOP("TQFP"), Square, { 0, 0, 0, 0, 0, 44, 64, 80, 100 } }, + { "mqfp", I18N_NOOP("MQFP"), Square, { 0, 0, 0, 0, 0, 44, 0, 0, 0 } }, + { "dfns", I18N_NOOP("DFN-S"), Bar, { 8, 0, 0, 0, 0, 0, 0, 0, 0 } }, + { "qfn", I18N_NOOP("QFN"), Square, { 0, 16, 0, 20, 28, 44, 0, 0, 0 } }, + { "qfns", I18N_NOOP("QFN-S"), Bar, { 0, 0, 0, 0, 28, 0, 0, 0, 0 } }, + { "plcc", I18N_NOOP("PLCC"), Square, { 0, 0, 0, 0, 0, 44, 68, 84, 0 } }, + { "mlf", I18N_NOOP("MLF"), Square, { 0, 0, 0, 0, 28, 0, 0, 0, 0 } }, + { "dfn", I18N_NOOP("DFN"), Bar, { 8, 0, 0, 0, 0, 0, 0, 0, 0 } }, + { 0, 0, Square, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } } +}; + +//----------------------------------------------------------------------------- +double Device::FrequencyRange::vddMin() const +{ + double vdd = 0.0; + for (uint i=0; i=-1 ); + Array array(s==-1 ? size()-index : s); + for (uint i=0; i>(QDataStream &s, RangeBox::Value &rbv) +{ + s >> rbv.x >> rbv.yMin >> rbv.yMax; + return s; +} + +QDataStream &Device::operator <<(QDataStream &s, const RangeBox &rb) +{ + s << rb.start << rb.end << rb.osc << rb.mode << rb.special; + return s; +} +QDataStream &Device::operator >>(QDataStream &s, RangeBox &rb) +{ + s >> rb.start >> rb.end >> rb.osc >> rb.mode >> rb.special; + return s; +} + +QDataStream &Device::operator <<(QDataStream &s, const FrequencyRange &frange) +{ + s << frange.operatingCondition << frange.special << frange.vdds; + return s; +} +QDataStream &Device::operator >>(QDataStream &s, FrequencyRange &frange) +{ + s >> frange.operatingCondition >> frange.special >> frange.vdds; + return s; +} + +QDataStream &Device::operator <<(QDataStream &s, const Package &package) +{ + s << package.types << package.pins; + return s; +} +QDataStream &Device::operator >>(QDataStream &s, Package &package) +{ + s >> package.types >> package.pins; + return s; +} + +QDataStream &Device::operator <<(QDataStream &s, const Documents &documents) +{ + s << documents.webpage << documents.datasheet << documents.progsheet << documents.erratas; + return s; +} +QDataStream &Device::operator >>(QDataStream &s, Documents &documents) +{ + s >> documents.webpage >> documents.datasheet >> documents.progsheet >> documents.erratas; + return s; +} + +QDataStream &Device::operator <<(QDataStream &s, const Data &data) +{ + s << data._name << data._documents << data._alternatives << data._status + << data._frequencyRanges << data._memoryTechnology + << data._packages; + return s; +} +QDataStream &Device::operator >>(QDataStream &s, Data &data) +{ + s >> data._name >> data._documents >> data._alternatives >> data._status + >> data._frequencyRanges >> data._memoryTechnology + >> data._packages; + return s; +} diff --git a/src/devices/base/generic_device.h b/src/devices/base/generic_device.h new file mode 100644 index 0000000..e3cbec9 --- /dev/null +++ b/src/devices/base/generic_device.h @@ -0,0 +1,171 @@ +/*************************************************************************** + * Copyright (C) 2005-2006 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. * + ***************************************************************************/ +#ifndef GENERIC_DEVICE_H +#define GENERIC_DEVICE_H + +#include + +#include "common/common/misc.h" +#include "common/common/bitvalue.h" +#include "common/common/key_enum.h" +#include "common/global/global.h" + +namespace Device +{ +//---------------------------------------------------------------------------- +BEGIN_DECLARE_ENUM(Status) + InProduction = 0, Future, NotRecommended, EOL, Unknown, Mature +END_DECLARE_ENUM_STD(Status) + +BEGIN_DECLARE_ENUM(MemoryTechnology) + Flash = 0, Eprom, Rom, Romless +END_DECLARE_ENUM_STD(MemoryTechnology) + +class RangeBox { +public: + struct Value { double x, yMin, yMax; }; + Value start, end; + QString osc, mode, special; + double yMin() const { return qMin(start.yMin, end.yMin); } + double yMax() const { return qMax(start.yMax, end.yMax); } +}; + +BEGIN_DECLARE_ENUM(OperatingCondition) + Commercial = 0, Industrial, Extended +END_DECLARE_ENUM_STD(OperatingCondition) + +BEGIN_DECLARE_ENUM(Special) + Normal = 0, LowPower, LowVoltage, HighVoltage +END_DECLARE_ENUM_STD(Special) + +class FrequencyRange { +public: + OperatingCondition operatingCondition; + Special special; + QValueVector vdds; + double vddMin() const; + double vddMax() const; +}; + +class IdData { +public: + BitValue revision, minorRevision, process; + Special special; +}; + +class Package +{ +public: + QValueVector types; + QValueVector pins; + +public: + enum Shape { Bar, Square }; + enum { MAX_NB = 9 }; + struct TypeData { + const char *name, *label; + Shape shape; + uint nbPins[MAX_NB]; + }; + static const TypeData TYPE_DATA[]; +}; + +class Documents +{ +public: + QString webpage, datasheet, progsheet; + QStringList erratas; +}; + +//---------------------------------------------------------------------------- +class XmlToDataBase; +class GroupBase; +class RegistersData; + +//---------------------------------------------------------------------------- +// we don't want implicit sharing +class Array +{ +public: + Array(uint size = 0) : _data(size) {} + Array(const Array &array); + Array &operator =(const Array &); + Array &operator +=(const Array &a); + void append(uint v); + Array mid(uint index, int size = -1) const; + void resize(uint s) { _data.resize(s); } + uint size() const { return _data.size(); } + uint count() const { return _data.size(); } + BitValue operator [](uint i) const { return _data[i]; } + BitValue &operator [](uint i) { return _data[i]; } + bool operator ==(const Array &array) const { return _data==array._data; } + bool operator !=(const Array &array) const { return _data!=array._data; } + +private: + QMemArray _data; +}; + +//---------------------------------------------------------------------------- +class Data +{ +public: + Data(RegistersData *rdata) : _group(0), _registersData(rdata) {} + virtual ~Data(); + const GroupBase &group() const { return *_group; } + virtual QString name() const { return _name; } + virtual QString fname(Special) const { return _name; } + virtual QString listViewGroup() const = 0; + Status status() const { return _status; } + const Documents &documents() const { return _documents; } + const QStringList &alternatives() const { return _alternatives; } + MemoryTechnology memoryTechnology() const { return _memoryTechnology; } + virtual bool matchId(BitValue rawId, IdData &idata) const = 0; + const QValueVector &frequencyRanges() const { return _frequencyRanges; } + double vddMin() const; + double vddMax() const; + virtual uint nbBitsAddress() const = 0; + uint nbBytesAddress() const { return nbBitsAddress()/8 + (nbBitsAddress()%8 ? 1 : 0); } + uint nbCharsAddress() const { return nbBitsAddress()/4 + (nbBitsAddress()%4 ? 1 : 0); } + virtual bool canWriteCalibration() const = 0; // #### REMOVE ME + const RegistersData *registersData() const { return _registersData; } + const QValueVector &packages() const { return _packages; } + +protected: + const GroupBase *_group; + QString _name; + Documents _documents; + QStringList _alternatives; + Status _status; + QValueVector _frequencyRanges; + MemoryTechnology _memoryTechnology; + RegistersData *_registersData; + QValueVector _packages; + + friend class XmlToDataBase; + friend class GroupBase; + friend QDataStream &operator <<(QDataStream &s, const Data &data); + friend QDataStream &operator >>(QDataStream &s, Data &data); +}; + +QDataStream &operator <<(QDataStream &s, const RangeBox::Value &rbv); +QDataStream &operator >>(QDataStream &s, RangeBox::Value &rbv); +QDataStream &operator <<(QDataStream &s, const RangeBox &rb); +QDataStream &operator >>(QDataStream &s, RangeBox &rb); +QDataStream &operator <<(QDataStream &s, const FrequencyRange &frange); +QDataStream &operator >>(QDataStream &s, FrequencyRange &frange); +QDataStream &operator <<(QDataStream &s, const Package &package); +QDataStream &operator >>(QDataStream &s, Package &package); +QDataStream &operator <<(QDataStream &s, const Documents &documents); +QDataStream &operator >>(QDataStream &s, Documents &documents); +QDataStream &operator <<(QDataStream &s, const Data &data); +QDataStream &operator >>(QDataStream &s, Data &data); + +} // namespace + +#endif diff --git a/src/devices/base/generic_memory.cpp b/src/devices/base/generic_memory.cpp new file mode 100644 index 0000000..78c4dd6 --- /dev/null +++ b/src/devices/base/generic_memory.cpp @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2006 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 "generic_memory.h" + +bool Device::Memory::load(QTextStream &stream, QStringList &errors, + WarningTypes &warningTypes, QStringList &warnings) +{ + HexBuffer hb; + if ( !hb.load(stream, errors) ) return false; + warningTypes = fromHexBuffer(hb, warnings); + return true; +} + +Device::Memory::WarningTypes Device::Memory::fromHexBuffer(const HexBuffer &hb, QStringList &warnings) +{ + clear(); + WarningTypes result = NoWarning; + warnings.clear(); + QMap inRange; + fromHexBuffer(hb, result, warnings, inRange); + + // check that all values in FragBuffer are within memory ranges + HexBuffer::const_iterator it = hb.begin(); + for (; it!=hb.end(); ++it) { + if ( !it.data().isInitialized() || inRange[it.key()] ) continue; + if ( !(result & ValueOutsideRange) ) { + result |= ValueOutsideRange; + warnings += i18n("At least one value (at address %1) is defined outside memory ranges.").arg(toHexLabel(it.key(), 8)); + } + break; + } + + return result; +} + +bool Device::Memory::save(QTextStream &stream, HexBuffer::Format format) const +{ + savePartial(stream, format); + HexBuffer hb; + hb.saveEnd(stream); + return true; +} diff --git a/src/devices/base/generic_memory.h b/src/devices/base/generic_memory.h new file mode 100644 index 0000000..74bd938 --- /dev/null +++ b/src/devices/base/generic_memory.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2006 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. * + ***************************************************************************/ +#ifndef GENERIC_MEMORY_H +#define GENERIC_MEMORY_H + +#include "devices/base/generic_device.h" +#include "devices/base/hex_buffer.h" + +namespace Device +{ + +class Memory +{ +public: + const Data &device() const { return _device; } + virtual ~Memory() {} + virtual void fill(BitValue value) = 0; + virtual void clear() { fill(BitValue()); } + virtual void copyFrom(const Memory &memory) = 0; + virtual BitValue checksum() const = 0; + + virtual HexBuffer toHexBuffer() const = 0; + bool save(QTextStream &stream, HexBuffer::Format format) const; + enum WarningType { NoWarning = 0, ValueTooLarge = 1, ValueOutsideRange = 2 }; + Q_DECLARE_FLAGS(WarningTypes, WarningType) + WarningTypes fromHexBuffer(const HexBuffer &hb, QStringList &warnings); + bool load(QTextStream &stream, QStringList &errors, WarningTypes &warningTypes, QStringList &warnings); + +protected: + const Data &_device; + + Memory(const Data &device) : _device(device) {} + virtual void fromHexBuffer(const HexBuffer &hb, WarningTypes &warningTypes, + QStringList &warnings, QMap &inRange) = 0; + virtual void savePartial(QTextStream &stream, HexBuffer::Format format) const = 0; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(Memory::WarningTypes) + +} // namespace + +#endif diff --git a/src/devices/base/hex_buffer.cpp b/src/devices/base/hex_buffer.cpp new file mode 100644 index 0000000..a63554d --- /dev/null +++ b/src/devices/base/hex_buffer.cpp @@ -0,0 +1,290 @@ +/*************************************************************************** + * Copyright (C) 2005-2007 Nicolas Hadacek * + * (C) 2003 by Alain Gibaud * + * * + * 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 "hex_buffer.h" + +#include + +#include "devices/base/generic_device.h" + +//----------------------------------------------------------------------------- +const char * const HexBuffer::FORMATS[Nb_Formats] = { + "inhx8m", /*"inhx8s", */"inhx16", "inhx32" +}; + +void HexBuffer::savePartial(QTextStream &stream, Format format) const +{ + BitValue oldseg; + const_iterator block = begin(); + int len; + while ( fetchNextBlock(block, end(), &len) ) { + // block found, write it + BitValue seg = block.key() >> 15 ; // 2 * seg address + if ( format==IHX32 && seg!=oldseg ) { + char buf[50]; + BitValue check = 0x02 + 0x04 + seg.byte(1) + seg.byte(0); + sprintf(buf, ":02000004%04X%02X\n", seg.toUInt(), check.twoComplement().byte(0)); + stream << buf; + oldseg = seg; + } + writeHexBlock(stream, len, block, format); + } +} + +void HexBuffer::saveEnd(QTextStream &stream) const +{ + stream << ":00000001FF\n"; +} + +/* Write one line of Intel-hex file + * Original code source from Timo Rossi, + * modified by Alain Gibaud to support large blocks write + */ +void HexBuffer::writeHexBlock(QTextStream &stream, int reclen, // length (in words) + const_iterator& data, // pointer to 1st data word (incremented by function) + Format format) +{ + while ( reclen>HEXBLKSIZE ) { + writeHexBlock(stream, HEXBLKSIZE, data, format); + reclen -= HEXBLKSIZE; + } + if ( reclen<=0 ) return; /* Oops, block has just a HEXBLKSIZE * n size */ + + char buf[20]; + BitValue check = 0x0; + + // line start + uint loc = data.key(); + switch (format) { + case IHX8M: + case IHX32: + loc *= 2; + sprintf(buf, ":%02X%04X00", 2*reclen, loc & 0xFFFF); + check += ((loc) & 0xff) + (((loc) >> 8) & 0xff) + 2*reclen; + break; + case IHX16: + sprintf(buf, ":%02X%04X00", reclen, loc & 0xFFFF); + check += (loc & 0xff) + ((loc >> 8) & 0xff) + reclen; + break; + case Nb_Formats: Q_ASSERT(false); break; + } + stream << buf; + + // data + for (; reclen > 0; ++data, --reclen) { + BitValue word = data.data(); + switch (format) { + case IHX8M: + case IHX32: + sprintf(buf, "%02X%02X", word.byte(0), word.byte(1)); + break; + case IHX16: + sprintf(buf, "%02X%02X", word.byte(1), word.byte(0)); + break; + case Nb_Formats: Q_ASSERT(false); break; + } + stream << buf; + check += word.byte(0) + word.byte(1); + } + + // checksum, assumes 2-complement + sprintf(buf, "%02X\n", check.twoComplement().byte(0)); + stream << buf; +} + +/* ------------------------------------------------------------------------- + This routine detects the next block to output + A block is a set of consecutive addresse words not + containing 0xFFFFFFFF + @return true if a block has been detected + 'it' is updated to point to the first address of the block + '*len' contains the size of the block +*/ +bool HexBuffer::fetchNextBlock(const_iterator& it, const const_iterator &end, int *len) +{ + uint startadr, curadr; + // for( i = *start ; (i < MAXPICSIZE) && (Mem[i] == INVALID) ; ++i) ; + // skip non-used words + + // Search block start + while ( it!=end && !it.data().isInitialized() ) ++it; + + // if(i >= MAXPICSIZE ) return false ; + if ( it==end ) return false; + + //for( *start = i ; (i < MAXPICSIZE) && (Mem[i] != INVALID) ; ++i) ; + //*len = i - *start ; + // search block end - a block may not cross a segment boundary + const_iterator itt(it) ; + for (curadr = startadr = itt.key(), ++itt; itt!=end; ++itt) { + if ( itt.key()!=curadr+1 ) break; // non contiguous addresses + if ( !itt.data().isInitialized() ) break; // unused word found + if ( ((itt.key()) & 0xFFFF0000U)!=(curadr & 0xFFFF0000U) ) break; // cross segment boundary + curadr = itt.key(); + } + *len = curadr - startadr + 1 ; + + return *len != 0 ; +} + +QString HexBuffer::ErrorData::message() const +{ + switch (type) { + case UnrecognizedFormat: return i18n("Unrecognized format (line %1).").arg(line); + case UnexpectedEOF: return i18n("Unexpected end-of-file."); + case UnexpectedEOL: return i18n("Unexpected end-of-line (line %1).").arg(line); + case WrongCRC: return i18n("CRC mismatch (line %1).").arg(line); + } + Q_ASSERT(false); + return QString::null; +} + +bool HexBuffer::load(QTextStream &stream, QStringList &errors) +{ + Format format; + QValueList list = load(stream, format); + if ( list.isEmpty() ) return true; + errors.clear(); + for (uint i=0; i HexBuffer::load(QTextStream &stream, Format &format) +{ + clear(); + format = Nb_Formats; + QValueList errors; + load(stream, format, errors); + if ( format==Nb_Formats ) format = IHX8M; // default + return errors; +} + +/* ------------------------------------------------------------------------- + Read a Intel HEX file of either INHX16 or INHX8M format type, detecting + the format automagicly by the wordcount and length of the line + Tested in 8 and 16 bits modes + ------------------------------------------------------------------------ */ +void HexBuffer::load(QTextStream &stream, Format &format, QValueList &errors) +{ + uint addrH = 0; // upper 16 bits of 32 bits address (inhx32 format) + uint line = 1; + + for (; !stream.atEnd(); line++) { // read each line + QString s = stream.readLine(); + if ( !s.startsWith(":") ) continue; // skip invalid intel hex line + s = s.stripWhiteSpace(); // clean-up white spaces at end-of-line + if ( s==":" ) continue; // skip empty line + + const char *p = s.latin1(); + p += 1; // skip ':' + uint bytecount = (s.length()-11) / 2; // number of data bytes of this record + + // get the byte count, the address and the type for this line. + uint count, addr, type; + if ( sscanf(p, "%02X%04X%02X", &count , &addr, &type)!=3 ) { + errors += ErrorData(line, UnrecognizedFormat); + return; + } + p += 8; + uint cksum = count + (addr >> 8) + (addr & 0xFF) + type; + + if( type==0x01 ) { // EOF field :00 0000 01 FF + uint data; + if ( sscanf(p, "%02X", &data)!=1 ) errors += ErrorData(line, UnexpectedEOL); + else if ( ((cksum+data) & 0xFF)!=0 ) errors += ErrorData(line, WrongCRC); + return; + } + + if ( type==0x04 ) { // linear extended record (for 0x21xxxx, :02 0000 04 0021 D9) + if( sscanf(p, "%04X", &addrH)!=1 ) { + errors += ErrorData(line, UnrecognizedFormat); // bad address record + return; + } + p += 4; + cksum += (addrH & 0xFF); + cksum += (addrH >> 8); + if ( format==Nb_Formats || format==IHX8M ) format = IHX32; + else if ( format!=IHX32 ) { + errors += ErrorData(line, UnrecognizedFormat); // inconsistent format + return; + } + uint data; + if ( sscanf(p, "%02X", &data)!=1 ) errors += ErrorData(line, UnexpectedEOL); + else if ( ((cksum+data) & 0xFF)!=0 ) errors += ErrorData(line, WrongCRC); + //qDebug("new address high: %s", toHex(addrH<<16, 8).data()); + continue; // goto next record + } + + /* Figure out if its INHX16 or INHX8M + if count is a 16 bits words count => INHX16 + if count is a byte count => INHX8M or INHX32 */ + if ( bytecount==count ) { + if ( format==Nb_Formats ) format = IHX8M; + else if ( format!=IHX8M && format!=IHX32 ) { + errors += ErrorData(line, UnrecognizedFormat); // inconsistent format + return; + } + /* Processing a INHX8M line */ + /* Modified to be able to read fuses from hexfile created by C18 toolchain */ + /* changed by Tobias Schoene 9 April 2005, */ + /* modified by A.G, because low and hi bytes was swapped in Tobias's code , 8 may 2005 + */ + uint addrbase = ((addrH << 16) | addr); + //qDebug("line %i: address %s", line, toHex(addrbase, 8).data()); + for (uint x = 0; x> 1; + BitValue value = (*this)[a]; + if ( addrbase+x & 1 ) insert(a, value.maskWith(0x00FF) | data << 8); // Odd addr => Hi byte + else insert(a, value.maskWith(0xFF00) | data); // Low byte + //if ( x==0 ) qDebug("fb@%s: %s", toHex(addrbase+x >> 1, 8).data(), toHex(fb[addrbase+x >> 1], 8).data()); + cksum += data; + } + } else if ( bytecount==count*2 ) { + if ( format==Nb_Formats ) format = IHX16; + else if ( format!=IHX16 ) { + errors += ErrorData(line, UnrecognizedFormat); // inconsistent format + return; + } + /* Processing a INHX16 line */ + for(uint x=0; x * + * (C) 2003 by Alain Gibaud * + * * + * 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. * + ***************************************************************************/ +#ifndef HEX_BUFFER_H +#define HEX_BUFFER_H + +#include "common/global/global.h" +#include "common/common/bitvalue.h" +class QTextStream; + +class HexBuffer : public QMap +{ +public: + enum Format { /// Differents flavors of Intel HEX file formats + IHX8M = 0, ///< 8 bits "swapped" format + // IHX8S, + IHX16, ///< 16 bits format + IHX32, ///< 8 bit format with 32 bits addresses + Nb_Formats + }; + static const char * const FORMATS[Nb_Formats]; + + void savePartial(QTextStream &s, Format format) const; + void saveEnd(QTextStream &s) const; + enum ErrorType { UnrecognizedFormat, WrongCRC, UnexpectedEOF, UnexpectedEOL }; + class ErrorData { + public: + ErrorData() {} + ErrorData(uint _line, ErrorType _type) : line(_line), type(_type) {} + QString message() const; + uint line; + ErrorType type; + }; + QValueList load(QTextStream &stream, Format &format); + bool load(QTextStream &stream, QStringList &errors); + +private: + enum { HEXBLKSIZE = 8 }; // line size in HEX files + + static bool fetchNextBlock(const_iterator& start, const const_iterator &end, int *len); + static void writeHexBlock(QTextStream &stream, int reclen, const_iterator& data, Format format); + void load(QTextStream &stream, Format &format, QValueList &errors); +}; + +#endif diff --git a/src/devices/base/register.cpp b/src/devices/base/register.cpp new file mode 100644 index 0000000..85fc013 --- /dev/null +++ b/src/devices/base/register.cpp @@ -0,0 +1,156 @@ +/*************************************************************************** + * Copyright (C) 2006 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 "register.h" + +//---------------------------------------------------------------------------- +namespace Register +{ + List *_list = 0; +} +Register::List &Register::list() +{ + if ( _list==0 ) _list = new List; + return *_list; +} + +//---------------------------------------------------------------------------- +Register::TypeData::TypeData(Address address, uint nbChars) + : _nbChars(nbChars), _address(address) +{ + Q_ASSERT( address.isValid() && nbChars!=0 ); +} +Register::TypeData::TypeData(const QString &name, uint nbChars) + : _nbChars(nbChars), _name(name) +{ + Q_ASSERT( !name.isEmpty() && nbChars!=0 ); +} +Register::TypeData::TypeData(const QString &name, Address address, uint nbChars) + : _nbChars(nbChars), _address(address), _name(name) +{ + Q_ASSERT( address.isValid() && nbChars!=0 && !name.isEmpty() ); +} + +Register::Type Register::TypeData::type() const +{ + if ( !_address.isValid() ) { + if ( _name.isEmpty() ) return Invalid; + return Special; + } + if ( _name.isEmpty() ) return Regular; + return Combined; +} + +QString Register::TypeData::toString() const +{ + return QString("%1 %2 %3").arg(toLabel(_address)).arg(_nbChars).arg(_name); +} + +Register::TypeData Register::TypeData::fromString(const QString &s) +{ + QStringList list = QStringList::split(" ", s); + if ( list.count()<2 || list.count()>3 ) return TypeData(); + bool ok; + Address address = list[0].toUInt(&ok); + if ( !ok ) return TypeData(); + uint nbChars = list[1].toUInt(&ok); + if ( !ok || nbChars==0 || (nbChars%2)!=0 ) return TypeData(); + QString name; + if ( list.count()==3 ) name = list[2]; + if ( !address.isValid() ) { + if ( name.isEmpty() ) return TypeData(); + return TypeData(name, nbChars); + } + if ( name.isEmpty() ) return TypeData(address, nbChars); + return TypeData(name, address, nbChars); +} + +//---------------------------------------------------------------------------- +void Register::List::init() +{ + _regulars.clear(); + _specials.clear(); + _watched.clear(); + _portDatas.clear(); + delayedChanged(); +} + +void Register::List::setWatched(const TypeData &data, bool watched) +{ + if (watched) { + if ( _watched.contains(data) ) return; + _watched.append(data); + } else _watched.remove(data); + delayedChanged(); +} + +void Register::List::clearWatched() +{ + _watched.clear(); + delayedChanged(); +} + +void Register::List::setValue(const TypeData &data, BitValue value) +{ + if ( !data.address().isValid() ) { + _specials[data.name()].old = _specials[data.name()].current; + _specials[data.name()].current = value; + } else { + Q_ASSERT( (data.nbChars()%2)==0 ); + uint nb = data.nbChars()/2; + for (uint i=0; i &data) +{ + _portDatas[index].old = _portDatas[index].current; + _portDatas[index].current = data; + delayedChanged(); +} + +BitValue Register::List::value(const TypeData &data) const +{ + if ( !data.address().isValid() ) { + if ( !_specials.contains(data.name()) ) return BitValue(); + return _specials[data.name()].current; + } + Q_ASSERT( (data.nbChars()%2)==0 ); + uint nb = data.nbChars()/2; + BitValue value = 0; + for (int i=nb-1; i>=0; i--) { + value <<= 8; + BitValue v = _regulars[data.address() + i].current; + if ( !v.isInitialized() ) return BitValue(); + value += v; + } + return value; +} + +BitValue Register::List::oldValue(const TypeData &data) const +{ + if ( !data.address().isValid() ) { + if ( !_specials.contains(data.name()) ) return BitValue(); + return _specials[data.name()].old; + } + Q_ASSERT( (data.nbChars()%2)==0 ); + uint nb = data.nbChars()/2; + BitValue value = 0; + for (int i=nb-1; i>=0; i--) { + value <<= 8; + BitValue v = _regulars[data.address() + i].old; + if ( !v.isInitialized() ) return BitValue(); + value += v; + } + return value; +} diff --git a/src/devices/base/register.h b/src/devices/base/register.h new file mode 100644 index 0000000..1c587e2 --- /dev/null +++ b/src/devices/base/register.h @@ -0,0 +1,130 @@ +/*************************************************************************** + * Copyright (C) 2006 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. * + ***************************************************************************/ +#ifndef REGISTER_H +#define REGISTER_H + +#include "common/common/storage.h" +#include "devices/base/generic_device.h" +namespace Register { class TypeData; } + +namespace Device +{ +enum RegisterProperty { NotAccessible = 0x0, Readable = 0x1, Writable = 0x2 }; +Q_DECLARE_FLAGS(RegisterProperties, RegisterProperty) +Q_DECLARE_OPERATORS_FOR_FLAGS(RegisterProperties) + +enum { MAX_NB_PORTS = 8 }; +enum { MAX_NB_PORT_BITS = 16 }; +enum BitState { Low = 0, High, WeakPullUp, WeakPullDown, HighImpedance, Unknown }; +enum IoState { IoLow = 0, IoHigh, IoUnknown }; +class PortBitData { +public: + PortBitData() : state(Unknown), driving(false), drivenState(IoUnknown), drivingState(IoUnknown) {} + BitState state; + bool driving; + IoState drivenState, drivingState; + bool operator !=(const PortBitData &pdb) const { + return ( state!=pdb.state || driving!=pdb.driving || drivenState!=pdb.drivenState || drivingState!=pdb.drivingState ); + } +}; + +} // namespace + +namespace Register +{ +//---------------------------------------------------------------------------- +enum Type { Regular, Special, Combined, Invalid }; +class TypeData { +public: + TypeData() : _nbChars(0) {} + TypeData(Address address, uint nbChars); + TypeData(const QString &name, uint nbChars); + TypeData(const QString &name, Address address, uint nbChars); + bool operator ==(const TypeData &data) const { return _name==data._name && _address==data._address && _nbChars==data._nbChars; } + Type type() const; + QString name() const { return _name; } + Address address() const { return _address; } + uint nbChars() const { return _nbChars; } + QString toString() const; + static TypeData fromString(const QString &s); + +private: + uint _nbChars; + Address _address; + QString _name; +}; + +} // namespace + +namespace Device +{ +//---------------------------------------------------------------------------- +class RegistersData +{ +public: + RegistersData() {} + virtual ~RegistersData() {} + virtual uint nbRegisters() const = 0; + virtual uint nbBits() const = 0; + uint nbBytes() const { return nbBitsToNbBytes(nbBits()); } + uint nbChars() const { return nbBitsToNbChars(nbBits()); } + virtual uint addressFromIndex(uint i) const = 0; + virtual uint indexFromAddress(Address address) const = 0; + virtual RegisterProperties properties(Address address) const = 0; + virtual QValueList relatedRegisters(const Register::TypeData &data) const = 0; + virtual bool hasPort(uint index) const = 0; + virtual int portIndex(Address address) const = 0; + virtual QString portName(uint index) const = 0; + virtual bool hasPortBit(uint index, uint bit) const = 0; + virtual QString portBitName(uint index, uint bit) const = 0; +}; + +} // namespace + +namespace Register +{ +//---------------------------------------------------------------------------- +class List; +extern List &list(); + +class List : public GenericStorage +{ +Q_OBJECT +public: + List() : GenericStorage(0, "register_list") {} + void init(); + void setWatched(const TypeData &data, bool watched); + void clearWatched(); + const QValueList &watched() const { return _watched; } + bool isWatched(const TypeData &data) const { return _watched.contains(data); } + void setValue(const TypeData &data, BitValue value); + BitValue value(const TypeData &data) const; + BitValue oldValue(const TypeData &data) const; + void setPortData(uint index, const QMap &data); + QMap portData(uint index) const { return _portDatas[index].current; } + QMap oldPortData(uint index) const { return _portDatas[index].old; } + +private: + class StateData { + public: + BitValue current, old; + }; + QMap _regulars; // registers with address + QMap _specials; // registers with no address + class PortData { + public: + QMap current, old; + }; + QMap _portDatas; // port index + QValueList _watched; +}; + +} // namespace + +#endif -- cgit v1.2.1