summaryrefslogtreecommitdiffstats
path: root/src/devices/base
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 18:42:24 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 18:42:24 +0000
commitf508189682b6fba62e08feeb1596f682bad5fff9 (patch)
tree28aeb0e6c19386c385c1ce5edf8a92c1bca15281 /src/devices/base
downloadpiklab-f508189682b6fba62e08feeb1596f682bad5fff9.tar.gz
piklab-f508189682b6fba62e08feeb1596f682bad5fff9.zip
Added KDE3 version of PikLab
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/piklab@1095639 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/devices/base')
-rw-r--r--src/devices/base/Makefile.am9
-rw-r--r--src/devices/base/base.pro6
-rw-r--r--src/devices/base/device_group.cpp362
-rw-r--r--src/devices/base/device_group.h87
-rw-r--r--src/devices/base/generic_device.cpp216
-rw-r--r--src/devices/base/generic_device.h171
-rw-r--r--src/devices/base/generic_memory.cpp48
-rw-r--r--src/devices/base/generic_memory.h47
-rw-r--r--src/devices/base/hex_buffer.cpp290
-rw-r--r--src/devices/base/hex_buffer.h51
-rw-r--r--src/devices/base/register.cpp156
-rw-r--r--src/devices/base/register.h130
12 files changed, 1573 insertions, 0 deletions
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 <hadacek@kde.org> *
+ * *
+ * 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 <qpainter.h>
+# include <kglobal.h>
+
+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("<font color=\"") + color.name() + "\">" + text + "</font>";
+}
+
+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<double, Tick>
+{
+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<Device::RangeBox> &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.count(); i++) {
+// qDebug("box #%i: %f=[%f %f] %f=[%f %f]", i, boxes[i].start.x, boxes[i].start.yMin,
+// boxes[i].start.yMax, boxes[i].end.x, boxes[i].end.yMin, boxes[i].end.yMax);
+ xTicks.add(boxes[i].start.x, boxes[i].start.yMin);
+ xTicks.add(boxes[i].start.x, boxes[i].start.yMax);
+ xTicks.add(boxes[i].end.x, boxes[i].end.yMin);
+ xTicks.add(boxes[i].end.x, boxes[i].end.yMax);
+ yTicks.add(boxes[i].start.yMin, boxes[i].start.x);
+ yTicks.add(boxes[i].start.yMax, boxes[i].start.x);
+ yTicks.add(boxes[i].end.yMin, boxes[i].end.x);
+ yTicks.add(boxes[i].end.yMax, boxes[i].end.x);
+ }
+ double xMax = 0.0, yMax = 0.0;
+ int xStart = 0;
+ int yStart = h-1 - f.lineSpacing();
+ TickMap::const_iterator it = xTicks.begin();
+ for (; it!=xTicks.end(); ++it) {
+ xStart = QMAX(xStart, f.width(it.data().s));
+ xMax = QMAX(xMax, it.key());
+ }
+ for (it = yTicks.begin(); it!=yTicks.end(); ++it)
+ yMax = QMAX(yMax, it.key());
+ int xEnd = w-1 - f.width(xTicks[xMax].s)/2;
+ QRect rect = f.boundingRect(yTicks[yMax].s);
+ int yEnd = rect.height()/2;
+
+ // draw boxes
+ p.setPen(Qt::lightGray);
+ p.setBrush(Qt::lightGray);
+ for (uint i=0; i<boxes.count(); i++) {
+ double ax = double(xEnd - xStart)/xMax;
+ double ay = double(yEnd - yStart)/yMax;
+ QPointArray pa(4);
+ pa.setPoint(0, qRound(ax*boxes[i].start.x), qRound(ay*boxes[i].start.yMin));
+ pa.setPoint(1, qRound(ax*boxes[i].end.x), qRound(ay*boxes[i].end.yMin));
+ pa.setPoint(2, qRound(ax*boxes[i].end.x), qRound(ay*boxes[i].end.yMax));
+ pa.setPoint(3, qRound(ax*boxes[i].start.x), qRound(ay*boxes[i].start.yMax));
+ pa.translate(xStart, yStart);
+ p.drawPolygon(pa);
+ }
+
+ // draw axis
+ p.setPen(Qt::black);
+ p.drawLine(xStart, yStart, w-1, yStart);
+ p.drawLine(xStart, yStart, xStart, 0);
+
+ // draw ticks and lines
+ p.setPen(Qt::DotLine);
+ for (it = yTicks.begin(); it!=yTicks.end(); ++it) {
+ int y1 = yStart + qRound(it.key()*(yEnd-yStart)/yMax);
+ QRect rect = f.boundingRect(it.data().s);
+ p.drawText(xStart/2-rect.width()/2 , y1+rect.height()/2, it.data().s);
+ int xmin = xStart + qRound(it.data().min*(xEnd-xStart)/xMax);
+ p.drawLine(xStart, y1, xmin, y1);
+ }
+ for (it = xTicks.begin(); it!=xTicks.end(); ++it) {
+ int x1 = xStart + qRound(it.key()*(xEnd-xStart)/xMax);
+ QRect rect = f.boundingRect(it.data().s);
+ p.drawText(x1-rect.width()/2, h-1, it.data().s);
+ int ymin = yStart + qRound(it.data().min*(yEnd-yStart)/yMax);
+ p.drawLine(x1, yStart, x1, ymin);
+ }
+
+ return pixmap;
+}
+
+QPixmap Device::vddGraph(const QString &xLabel, const QString &yLabel,
+ const QValueVector<Device::RangeBox> &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<data.packages().count(); i++)
+ for (uint k=0; k<data.packages()[i].types.count(); k++)
+ if ( Package::TYPE_DATA[data.packages()[i].types[k]].name==name ) return &data.packages()[i];
+ return 0;
+}
+
+QPixmap Device::pinsGraph(const Device::Package &package)
+{
+ QPixmap pixmap;
+ QPainter p;
+ QFontMetrics fm(p.font());
+ uint nb = package.pins.count();
+ const int hspacing = 3, wspacing = 3, wmark = 10, wpin = 4;
+ int theight = fm.ascent() + (fm.ascent()%2==0 ? 1 : 0);
+ int height = hspacing + (nb/2)*(hspacing + theight);
+ int wnumber = fm.width("1");
+ wnumber = QMAX(wnumber, fm.width(QString::number(nb/2)));
+ wnumber = QMAX(wnumber, fm.width(QString::number(nb/2+1)));
+ wnumber = QMAX(wnumber, fm.width(QString::number(nb)));
+ int bwidth = 4*wspacing + 2*wnumber + wmark;
+ int lwidth = 0, rwidth = 0;
+ for (uint k=0; k<nb/2; k++) {
+ lwidth = QMAX(lwidth, fm.width(package.pins[k]));
+ rwidth = QMAX(rwidth, fm.width(package.pins[nb-k-1]));
+ }
+ int bx = lwidth + wspacing + wpin;
+ int width = bx + bwidth + wpin + wspacing + rwidth;
+ pixmap.resize(width, height);
+ pixmap.fill(Qt::white);
+ p.begin(&pixmap);
+ p.setPen(QPen(Qt::black, 2));
+ p.drawRect(bx, 1, bwidth, height-1);
+ p.drawArc(bx+wspacing+wnumber+wspacing, -wmark/2+2, wmark, wmark, 0, -180*16);
+ for (uint k=0; k<nb/2; k++) {
+ int h = hspacing + theight/2 + k*(hspacing + theight);
+ p.drawLine(bx-wpin-1, h, bx, h);
+ p.drawLine(bx+bwidth, h, bx+bwidth+wpin, h);
+ h += theight/2;
+ QString label = package.pins[k];
+ p.drawText(bx-wpin-wspacing-fm.width(label), h, label);
+ p.drawText(bx+bwidth+wpin+wspacing, h, package.pins[nb-k-1]);
+ uint pin = (k+1);
+ if ( pin==1 || pin==(nb/2) ) {
+ p.drawText(bx+wspacing, h, QString::number(pin));
+ label = QString::number(nb-k);
+ p.drawText(bx+bwidth-wspacing-fm.width(label), h, label);
+ }
+ }
+ p.end();
+ return pixmap;
+}
+
+QString Device::htmlInfo(const Device::Data &data, const QString &deviceHref, const QString &documentHtml)
+{
+ QString doc;
+
+ // title
+ doc += "<h1>";
+ bool first = true;
+ FOR_EACH(Special, special) {
+ for (uint k=0; k<data.frequencyRanges().count(); k++) {
+ if ( data.frequencyRanges()[k].special!=special ) continue;
+ if (first) first = false;
+ else doc += " / ";
+ doc += data.fname(special);
+ break;
+ }
+ }
+ doc += "</h1>";
+
+ doc += "<table>";
+ QString status = coloredString(data.status().label(), statusColor(data.status()));
+ doc += htmlTableRow(i18n("Status"), status);
+ if ( data.alternatives().count() ) {
+ QString s;
+ for (uint i=0; i<data.alternatives().count(); i++) {
+ if ( i!=0 ) s += ", ";
+ if ( deviceHref.isEmpty() ) s += data.alternatives()[i].upper();
+ else {
+ QString href = deviceHref.arg(data.alternatives()[i].upper());
+ s += QString("<a href=\"%1\">%2</a>").arg(href).arg(data.alternatives()[i].upper());
+ }
+ }
+ doc += htmlTableRow(i18n("Alternatives"), s);
+ }
+ doc += documentHtml;
+ doc += "</table>";
+
+ doc += "<hr />";
+ doc += "<table>";
+ doc += data.group().informationHtml(data);
+ QString s;
+ for (uint i=0; i<data.packages().count(); i++)
+ for (uint k=0; k<data.packages()[i].types.count(); k++)
+ s += i18n(Package::TYPE_DATA[data.packages()[i].types[k]].label) + QString("[%1] ").arg(data.packages()[i].pins.count());
+ doc += htmlTableRow(i18n("Packaging"), s);
+ doc += "</table>";
+
+ return doc;
+}
+
+QString Device::htmlPinDiagrams(const Device::Data &data, const QString &imagePrefix, QMimeSourceFactory *msf)
+{
+ QString doc;
+ // pins
+ const Package *package = 0;
+ for (uint i=0; Package::TYPE_DATA[i].name; i++) {
+ if ( Package::TYPE_DATA[i].shape!=Package::Bar ) continue;
+ package = barPackage(Package::TYPE_DATA[i].name, data);
+ if (package) break;
+ }
+ if (package) {
+ QPixmap pix = pinsGraph(*package);
+ doc += "<table cellpadding=\"3\"><tr bgcolor=\"gray\"><th align=\"center\">";
+ for (uint k=0; k<package->types.count(); k++) {
+ if ( k!=0 ) doc += " ";
+ doc += i18n(Package::TYPE_DATA[package->types[k]].label);
+ doc += "(" + QString::number(package->pins.count()) + ")";
+ }
+ doc += "</th></tr><tr><td align=\"center\">";
+ QString label = data.name() + "_pins_graph.png";
+ doc += "<img src=\"" + imagePrefix + label + "\" />";
+ if (msf) msf->setPixmap(label, pix);
+ doc += "</td></tr></table>";
+ }
+ 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<data.frequencyRanges().count(); k++) {
+ const Device::FrequencyRange &fr = data.frequencyRanges()[k];
+ if ( fr.special!=special ) continue;
+ doc += "<h3>" + data.fname(special) + " - " + i18n("Temperature range: ") + fr.operatingCondition.label() + "</h3>";
+ QString label = data.name() + "_" + data.fname(special) + "_"
+ + fr.operatingCondition.key() + ".png";
+ doc += "<img src=\"" + imagePrefix + label + "\" />";
+ if (msf) msf->setPixmap(label, Device::vddGraph(i18n("F (MHz)"), i18n("Vdd (V)"), fr.vdds));
+ }
+ }
+ return doc;
+}
+
+QPixmap Device::memoryGraph(const QValueList<MemoryGraphData> &r)
+{
+ QValueList<MemoryGraphData> ranges = r;
+ QPixmap pixmap;
+ QPainter p;
+ QFontMetrics fm(p.font());
+ // order
+ qHeapSort(ranges);
+ // add empty ranges
+ QValueList<MemoryGraphData>::iterator it;
+ for (it=ranges.begin(); it!=ranges.end(); ) {
+ QValueList<MemoryGraphData>::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 <hadacek@kde.org> *
+ * *
+ * 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 <qcolor.h>
+#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<Device::Data *>(data)->_group = this;
+ ::Group::Base::addDevice(name, data, support);
+ }
+};
+
+template <class DataType>
+class Group : public GroupBase, public DataStreamer<DataType>
+{
+protected:
+ virtual void initSupported() {
+ QValueList<DataType *> list = fromCppString(dataStream(), dataSize());
+ for (uint i=0; i<uint(list.count()); i++) addDevice(list[i]->name(), 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<RangeBox> &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<MemoryGraphData> &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 <hadacek@kde.org> *
+ * *
+ * 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<uint(vdds.count()); i++) {
+ if ( i==0 ) vdd = vdds[i].yMin();
+ vdd = qMin(vdd, vdds[i].yMin());
+ }
+ return vdd;
+}
+
+double Device::FrequencyRange::vddMax() const
+{
+ double vdd = 0.0;
+ for (uint i=0; i<uint(vdds.count()); i++) {
+ if ( i==0 ) vdd = vdds[i].yMax();
+ vdd = qMax(vdd, vdds[i].yMax());
+ }
+ return vdd;
+}
+
+//-----------------------------------------------------------------------------
+Device::Array::Array(const Array &array)
+{
+ _data = array._data.copy();
+}
+
+Device::Array &Device::Array::operator +=(const Array &a)
+{
+ uint s = _data.size();
+ _data.resize(s + a.size());
+ for (uint i=0; i<a.size(); i++) _data[s+i] = a[i];
+ return *this;
+}
+
+void Device::Array::append(uint v)
+{
+ uint s = _data.size();
+ _data.resize(s+1);
+ _data[s] = v;
+}
+
+Device::Array Device::Array::mid(uint index, int s) const
+{
+ CRASH_ASSERT( index<=size() && s<=int(size()-index) && s>=-1 );
+ Array array(s==-1 ? size()-index : s);
+ for (uint i=0; i<array.size(); i++) array[i] = _data[index+i];
+ return array;
+}
+
+Device::Array &Device::Array::operator =(const Array &array)
+{
+ _data = array._data.copy();
+ return *this;
+}
+
+//-----------------------------------------------------------------------------
+Device::Data::~Data()
+{
+ delete _registersData;
+}
+
+double Device::Data::vddMin() const
+{
+ double vdd = 0.0;
+ for (uint i=0; i<uint(_frequencyRanges.count()); i++) {
+ if ( i==0 ) vdd = _frequencyRanges[i].vddMin();
+ vdd = qMin(vdd, _frequencyRanges[i].vddMin());
+ }
+ return vdd;
+}
+
+double Device::Data::vddMax() const
+{
+ double vdd = 0.0;
+ for (uint i=0; i<uint(_frequencyRanges.count()); i++) {
+ if ( i==0 ) vdd = _frequencyRanges[i].vddMax();
+ vdd = qMax(vdd, _frequencyRanges[i].vddMax());
+ }
+ return vdd;
+}
+
+//-----------------------------------------------------------------------------
+QDataStream &Device::operator <<(QDataStream &s, const RangeBox::Value &rbv)
+{
+ s << rbv.x << rbv.yMin << rbv.yMax;
+ return s;
+}
+QDataStream &Device::operator >>(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 <hadacek@kde.org> *
+ * *
+ * 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 <qstringlist.h>
+
+#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<RangeBox> vdds;
+ double vddMin() const;
+ double vddMax() const;
+};
+
+class IdData {
+public:
+ BitValue revision, minorRevision, process;
+ Special special;
+};
+
+class Package
+{
+public:
+ QValueVector<uint> types;
+ QValueVector<QString> 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<BitValue> _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<FrequencyRange> &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<Package> &packages() const { return _packages; }
+
+protected:
+ const GroupBase *_group;
+ QString _name;
+ Documents _documents;
+ QStringList _alternatives;
+ Status _status;
+ QValueVector<FrequencyRange> _frequencyRanges;
+ MemoryTechnology _memoryTechnology;
+ RegistersData *_registersData;
+ QValueVector<Package> _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 <hadacek@kde.org> *
+ * *
+ * 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<uint, bool> 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 <hadacek@kde.org> *
+ * *
+ * 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<uint, bool> &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 <hadacek@kde.org> *
+ * (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 <qtextstream.h>
+
+#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<ErrorData> list = load(stream, format);
+ if ( list.isEmpty() ) return true;
+ errors.clear();
+ for (uint i=0; i<uint(list.count()); i++) errors += list[i].message();
+ return false;
+}
+
+QValueList<HexBuffer::ErrorData> HexBuffer::load(QTextStream &stream, Format &format)
+{
+ clear();
+ format = Nb_Formats;
+ QValueList<HexBuffer::ErrorData> 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<ErrorData> &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<count; x++) {
+ uint data;
+ if ( sscanf(p, "%02X", &data)!=1 ) {
+ errors += ErrorData(line, UnexpectedEOL);
+ break;
+ }
+ p += 2;
+ // A.G: I suspect possible initialization problem
+ // if block begins at odd address
+ // because |= works on an uninitalized word
+ // however, I don't know if such a situation can occurs
+ uint a = addrbase+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<count; x++) {
+ uint datal, datah;
+ if( sscanf(p, "%02X%02X", &datah, &datal)!=2 ) {
+ errors += ErrorData(line, UnexpectedEOL);
+ break;
+ }
+ p += 4;
+ //qDebug("%s: %s", toHexLabel(addr+x, 4).latin1(), toHexLabel(datal | (datah << 8), 4).latin1());
+ insert(addr+x, datal | (datah << 8));
+ cksum += datah;
+ cksum += datal;
+ }
+ } else {
+ errors += ErrorData(line, UnrecognizedFormat); // Brrrr !! Strange format.
+ return;
+ }
+
+ /* Process the checksum */
+ uint data;
+ if( sscanf(p, "%02X", &data)!=1 ) errors += ErrorData(line, UnexpectedEOL);
+ else if( ((data + cksum) & 0xFF)!=0 ) errors += ErrorData(line, WrongCRC);
+ }
+
+ errors += ErrorData(line, UnexpectedEOF);
+ return;
+}
diff --git a/src/devices/base/hex_buffer.h b/src/devices/base/hex_buffer.h
new file mode 100644
index 0000000..93b0640
--- /dev/null
+++ b/src/devices/base/hex_buffer.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * Copyright (C) 2005-2007 Nicolas Hadacek <hadacek@kde.org> *
+ * (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<uint, BitValue>
+{
+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<ErrorData> 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<ErrorData> &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 <hadacek@kde.org> *
+ * *
+ * 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<nb; i++) {
+ Address address = data.address() + i;
+ _regulars[address].old = _regulars[address].current;
+ _regulars[address].current = value.byte(i);
+ }
+ }
+ delayedChanged();
+}
+
+void Register::List::setPortData(uint index, const QMap<uint, Device::PortBitData> &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 <hadacek@kde.org> *
+ * *
+ * 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<Register::TypeData> 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<TypeData> &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<uint, Device::PortBitData> &data);
+ QMap<uint, Device::PortBitData> portData(uint index) const { return _portDatas[index].current; }
+ QMap<uint, Device::PortBitData> oldPortData(uint index) const { return _portDatas[index].old; }
+
+private:
+ class StateData {
+ public:
+ BitValue current, old;
+ };
+ QMap<Address, StateData> _regulars; // registers with address
+ QMap<QString, StateData> _specials; // registers with no address
+ class PortData {
+ public:
+ QMap<uint, Device::PortBitData> current, old;
+ };
+ QMap<uint, PortData> _portDatas; // port index
+ QValueList<TypeData> _watched;
+};
+
+} // namespace
+
+#endif