rockbox/utils/regtools/qeditor/backend.cpp
Amaury Pouly 5ac0166388 qeditor: port to the new hwstub library and add features
This commit adds support for the version of the hwstub library, which requires
a lot of changes. It also adds some editing features, such as register access
and much better editing of fields using the mouse (double click on a field
to be able to resize and move it).

Change-Id: I3c4e4cc855cb44911c72bc8127bad841b68efe52
2016-04-08 18:46:46 +01:00

1039 lines
25 KiB
C++

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2014 by Amaury Pouly
*
* 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.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QFileInfo>
#include <QFont>
#include "backend.h"
/**
* SocFile
*/
SocFile::SocFile()
:m_valid(true)
{
}
SocFile::SocFile(const QString& filename)
:m_filename(filename)
{
soc_desc::error_context_t ctx;
m_valid = soc_desc::parse_xml(filename.toStdString(), m_soc, ctx);
}
bool SocFile::IsValid()
{
return m_valid;
}
soc_desc::soc_ref_t SocFile::GetSocRef()
{
if(m_valid)
return soc_desc::soc_ref_t(&m_soc);
else
return soc_desc::soc_ref_t();
}
QString SocFile::GetFilename()
{
return m_filename;
}
/**
* Backend
*/
Backend::Backend()
{
}
QList< SocFileRef > Backend::GetSocFileList()
{
QList< SocFileRef > list;
for(std::list< SocFile >::iterator it = m_socs.begin(); it != m_socs.end(); ++it)
{
if(it->IsValid())
list.append(SocFileRef(&(*it)));
}
return list;
}
QList< soc_desc::soc_ref_t > Backend::GetSocList()
{
QList< soc_desc::soc_ref_t > list;
for(std::list< SocFile >::iterator it = m_socs.begin(); it != m_socs.end(); ++it)
{
soc_desc::soc_ref_t r = it->GetSocRef();
if(r.valid())
list.append(r);
}
return list;
}
bool Backend::LoadSocDesc(const QString& filename)
{
SocFile f(filename);
if(!f.IsValid())
return false;
m_socs.push_back(f);
emit OnSocAdded(SocFileRef(&m_socs.back()));
return true;
}
IoBackend *Backend::CreateFileIoBackend(const QString& filename)
{
return new FileIoBackend(filename);
}
IoBackend *Backend::CreateDummyIoBackend()
{
return new DummyIoBackend();
}
#ifdef HAVE_HWSTUB
IoBackend *Backend::CreateHWStubIoBackend(HWStubDevice *dev)
{
return new HWStubIoBackend(dev);
}
#endif
/**
* DummyIoBackend
*/
DummyIoBackend::DummyIoBackend()
{
}
bool DummyIoBackend::IsValid()
{
return false;
}
QString DummyIoBackend::GetSocName()
{
return "";
}
bool DummyIoBackend::ReadRegister(soc_addr_t addr, soc_word_t& value,
unsigned width)
{
Q_UNUSED(addr);
Q_UNUSED(value);
Q_UNUSED(width);
return false;
}
bool DummyIoBackend::Reload()
{
return false;
}
bool DummyIoBackend::IsReadOnly()
{
return true;
}
bool DummyIoBackend::WriteRegister(soc_addr_t addr, soc_word_t value,
unsigned width, WriteMode mode)
{
Q_UNUSED(addr);
Q_UNUSED(value);
Q_UNUSED(mode);
Q_UNUSED(width);
return false;
}
bool DummyIoBackend::IsDirty()
{
return false;
}
bool DummyIoBackend::Commit()
{
return false;
}
/**
* RamIoBackend
*/
RamIoBackend::RamIoBackend(const QString& soc_name)
{
m_soc = soc_name;
}
bool RamIoBackend::IsValid()
{
return m_soc != "";
}
QString RamIoBackend::GetSocName()
{
return m_soc;
}
void RamIoBackend::SetSocName(const QString& soc_name)
{
m_soc = soc_name;
}
bool RamIoBackend::RamIoBackend::Reload()
{
return false;
}
bool RamIoBackend::IsReadOnly()
{
return false;
}
bool RamIoBackend::ReadRegister(soc_addr_t addr, soc_word_t& value,
unsigned width)
{
Q_UNUSED(width);
QMap<soc_addr_t, soc_word_t>::const_iterator it = m_map.find(addr);
if(it == m_map.end())
return false;
value = it.value();
return true;
}
void RamIoBackend::DeleteAll()
{
m_map.clear();
}
bool RamIoBackend::WriteRegister(soc_addr_t addr, soc_word_t value,
unsigned width, WriteMode mode)
{
Q_UNUSED(width);
switch(mode)
{
case Write: m_map[addr] = value; return true;
case Set: m_map[addr] |= value; return true;
case Clear: m_map[addr] &= ~value; return true;
case Toggle: m_map[addr] ^= value; return true;
default: return false;
}
}
bool RamIoBackend::IsDirty()
{
return false;
}
bool RamIoBackend::Commit()
{
return false;
}
/**
* FileIoBackend
*/
FileIoBackend::FileIoBackend(const QString& filename, const QString& soc_name)
:RamIoBackend(soc_name)
{
m_filename = filename;
m_valid = false;
Reload();
}
bool FileIoBackend::IsValid()
{
return m_valid;
}
bool FileIoBackend::Reload()
{
m_valid = false;
QFile file(m_filename);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
return false;
DeleteAll();
QTextStream in(&file);
while(!in.atEnd())
{
QString line = in.readLine();
int idx = line.indexOf('=');
if(idx == -1)
continue;
QString key_str = line.left(idx).trimmed();
QString val_str = line.mid(idx + 1).trimmed();
bool key_ok,val_ok;
soc_word_t val = val_str.toULong(&val_ok, 0);
soc_word_t key = key_str.toULong(&key_ok, 0);
if(key_str == "soc")
m_soc = val_str;
else if(key_ok && val_ok)
RamIoBackend::WriteRegister(key, val, 32, Write);
}
m_readonly = !QFileInfo(file).isWritable();
m_dirty = false;
m_valid = true;
return true;
}
bool FileIoBackend::WriteRegister(soc_addr_t addr, soc_word_t value,
unsigned width, WriteMode mode)
{
m_dirty = true;
return RamIoBackend::WriteRegister(addr, value, width, mode);
}
bool FileIoBackend::Commit()
{
if(!m_dirty)
return true;
QFile file(m_filename);
if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
return false;
QTextStream out(&file);
out << "soc = " << m_soc << "\n";
QMapIterator< soc_addr_t, soc_word_t > it(m_map);
while(it.hasNext())
{
it.next();
out << hex << showbase << it.key() << " = " << hex << showbase << it.value() << "\n";
}
out.flush();
return file.flush();
}
bool FileIoBackend::IsReadOnly()
{
return m_readonly;
}
bool FileIoBackend::IsDirty()
{
return m_dirty;
}
QString FileIoBackend::GetFileName()
{
return m_filename;
}
#ifdef HAVE_HWSTUB
/**
* HWStubManager
*/
HWStubManager *HWStubManager::g_inst = nullptr;
HWStubManager::HWStubManager()
{
Add("Default", QString::fromStdString(hwstub::uri::default_uri().full_uri()));
}
HWStubManager::~HWStubManager()
{
}
HWStubManager *HWStubManager::Get()
{
if(g_inst == nullptr)
g_inst = new HWStubManager();
return g_inst;
}
bool HWStubManager::Add(const QString& name, const QString& uri)
{
struct Context ctx;
ctx.name = name;
ctx.uri = uri;
ctx.context = hwstub::uri::create_context(uri.toStdString());
if(!ctx.context)
return false;
ctx.context->start_polling();
beginInsertRows(QModelIndex(), m_list.size(), m_list.size());
m_list.push_back(ctx);
endInsertRows();
return true;
}
void HWStubManager::Clear()
{
m_list.clear();
}
int HWStubManager::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return m_list.size();
}
int HWStubManager::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return 2;
}
std::shared_ptr< hwstub::context > HWStubManager::GetContext(int row)
{
if(row < 0 || (size_t)row >= m_list.size())
return std::shared_ptr< hwstub::context >();
else
return m_list[row].context;
}
QVariant HWStubManager::data(const QModelIndex& index, int role) const
{
if(index.row() < 0 || (size_t)index.row() >= m_list.size())
return QVariant();
int section = index.column();
const Context& ctx = m_list[index.row()];
if(section == GetNameColumn())
{
if(role == Qt::DisplayRole || role == Qt::EditRole)
return QVariant(ctx.name);
}
else if(section == GetUriColumn())
{
if(role == Qt::DisplayRole)
return QVariant(ctx.uri);
}
return QVariant();
}
QVariant HWStubManager::headerData(int section, Qt::Orientation orientation, int role) const
{
if(orientation == Qt::Vertical)
return QVariant();
if(role != Qt::DisplayRole)
return QVariant();
if(section == GetNameColumn())
return QVariant("Name");
else if(section == GetUriColumn())
return QVariant("URI");
return QVariant();
}
Qt::ItemFlags HWStubManager::flags(const QModelIndex& index) const
{
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
int section = index.column();
if(section == GetNameColumn())
flags |= Qt::ItemIsEditable;
return flags;
}
bool HWStubManager::setData(const QModelIndex& index, const QVariant& value, int role)
{
if(role != Qt::EditRole)
return false;
if(index.row() < 0 || (size_t)index.row() >= m_list.size())
return false;
if(index.column() != GetNameColumn())
return false;
m_list[index.row()].name = value.toString();
emit dataChanged(index, index);
return true;
}
int HWStubManager::GetNameColumn() const
{
return 0;
}
int HWStubManager::GetUriColumn() const
{
return 1;
}
QString HWStubManager::GetFriendlyName(std::shared_ptr< hwstub::device > device)
{
/* try to open the device */
std::shared_ptr< hwstub::handle > handle;
hwstub::error err = device->open(handle);
if(err != hwstub::error::SUCCESS)
goto Lfallback;
/* get target descriptor */
struct hwstub_target_desc_t target_desc;
err = handle->get_target_desc(target_desc);
if(err != hwstub::error::SUCCESS)
goto Lfallback;
return QString::fromStdString(target_desc.bName);
/* fallback: don't open the device */
Lfallback:
hwstub::usb::device *udev = dynamic_cast< hwstub::usb::device* >(device.get());
if(udev)
{
return QString("USB Bus %1 Device %2: ID %3:%4")
.arg(udev->get_bus_number()).arg(udev->get_address(), 3, 10, QChar('0'))
.arg(udev->get_vid(), 4, 16, QChar('0')).arg(udev->get_pid(), 4, 16, QChar('0'));
}
else
return QString("<Unknown device>");
}
/**
* HWStubContextModel
*/
HWStubContextModel::HWStubContextModel(QObject *parent)
:QAbstractTableModel(parent), m_has_dummy(false)
{
}
HWStubContextModel::~HWStubContextModel()
{
SetContext(std::shared_ptr< hwstub::context >());
}
void HWStubContextModel::SetContext(std::shared_ptr< hwstub::context > context)
{
int first_row = m_has_dummy ? 1: 0;
/* clear previous model if any */
if(m_list.size() > 0)
{
beginRemoveRows(QModelIndex(), first_row, first_row + m_list.size() - 1);
m_list.clear();
endRemoveRows();
}
/* don't forget to unregister callback if context still exists */
std::shared_ptr< hwstub::context > ctx = m_context.lock();
if(ctx)
ctx->unregister_callback(m_callback_ref);
/* get new context */
m_context = context;
if(context)
{
/* register new callback */
m_callback_ref = context->register_callback(
std::bind(&HWStubContextModel::OnDevChangeLow, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3));
/* get dev list */
std::vector< std::shared_ptr< hwstub::device > > list;
hwstub::error err = context->get_device_list(list);
if(err == hwstub::error::SUCCESS)
{
beginInsertRows(QModelIndex(), first_row, first_row + list.size() - 1);
for(auto& d : list)
{
Device dev;
dev.name = GetFriendlyName(d);
dev.device = d;
m_list.push_back(dev);
}
endInsertRows();
}
}
}
void HWStubContextModel::EnableDummy(bool en, const QString& text)
{
/* if needed, create/remove raw */
if(m_has_dummy && !en)
{
/* remove row */
beginRemoveRows(QModelIndex(), 0, 0);
m_has_dummy = false;
endRemoveRows();
}
else if(!m_has_dummy && en)
{
/* add row */
beginInsertRows(QModelIndex(), 0, 0);
m_has_dummy = true;
m_dummy_text = text;
endInsertRows();
}
else if(en)
{
/* text change only */
emit dataChanged(index(0, GetNameColumn()), index(0, GetNameColumn()));
}
}
int HWStubContextModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return m_list.size() + (m_has_dummy ? 1 : 0);
}
int HWStubContextModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent);
return 1;
}
QVariant HWStubContextModel::data(const QModelIndex& index, int role) const
{
int first_row = m_has_dummy ? 1: 0;
/* special case for dummy */
if(m_has_dummy && index.row() == 0)
{
int section = index.column();
if(section == GetNameColumn())
{
if(role == Qt::DisplayRole)
return QVariant(m_dummy_text);
else if(role == Qt::FontRole)
{
QFont font;
font.setItalic(true);
return QVariant(font);
}
}
return QVariant();
}
if(index.row() < first_row || (size_t)index.row() >= first_row + m_list.size())
return QVariant();
int section = index.column();
if(section == GetNameColumn())
{
if(role == Qt::DisplayRole)
return QVariant(m_list[index.row() - first_row].name);
}
return QVariant();
}
QVariant HWStubContextModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(orientation == Qt::Vertical)
return QVariant();
if(role != Qt::DisplayRole)
return QVariant();
if(section == GetNameColumn())
return QVariant("Friendly name");
return QVariant();
}
Qt::ItemFlags HWStubContextModel::flags(const QModelIndex& index) const
{
Q_UNUSED(index);
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
int HWStubContextModel::GetNameColumn() const
{
return 0;
}
std::shared_ptr< hwstub::device > HWStubContextModel::GetDevice(int row)
{
int first_row = m_has_dummy ? 1: 0;
/* special case for dummy */
if(row < first_row || (size_t)row >= first_row + m_list.size())
return std::shared_ptr< hwstub::device >();
else
return m_list[row - first_row].device;
}
QString HWStubContextModel::GetFriendlyName(std::shared_ptr< hwstub::device > device)
{
return HWStubManager::GetFriendlyName(device);
}
namespace
{
struct dev_change_t
{
std::shared_ptr< hwstub::context > ctx;
bool arrived;
std::shared_ptr< hwstub::device > device;
};
}
void HWStubContextModel::OnDevChangeLow(std::shared_ptr< hwstub::context > ctx,
bool arrived, std::shared_ptr< hwstub::device > device)
{
/* calling Qt function from non-Qt thread is unsafe. Since the polling thread
* is a pthread, the safest way to use Qt invoke mecanism to make it run
* on the event loop */
dev_change_t *evt = new dev_change_t;
evt->ctx = ctx;
evt->arrived = arrived;
evt->device = device;
QMetaObject::invokeMethod(this, "OnDevChangeUnsafe", Q_ARG(void *, (void *)evt));
}
void HWStubContextModel::OnDevChangeUnsafe(void *data)
{
dev_change_t *evt = (dev_change_t *)data;
OnDevChange(evt->ctx, evt->arrived, evt->device);
delete evt;
}
void HWStubContextModel::OnDevChange(std::shared_ptr< hwstub::context > ctx, bool arrived,
std::shared_ptr< hwstub::device > device)
{
int first_row = m_has_dummy ? 1: 0;
Q_UNUSED(ctx);
if(arrived)
{
Device dev;
dev.name = GetFriendlyName(device);
dev.device = device;
beginInsertRows(QModelIndex(), first_row + m_list.size(),
first_row + m_list.size());
m_list.push_back(dev);
endInsertRows();
}
else
{
/* find device in the list */
auto it = m_list.begin();
int idx = 0;
for(; it != m_list.end(); ++it, ++idx)
if(it->device == device)
break;
if(it == m_list.end())
return;
/* remove it */
beginRemoveRows(QModelIndex(), first_row + idx, first_row + idx);
m_list.erase(it);
endRemoveRows();
}
}
/**
* HWStubDevice
*/
HWStubDevice::HWStubDevice(std::shared_ptr< hwstub::device > device)
{
m_valid = Probe(device);
}
HWStubDevice::~HWStubDevice()
{
}
bool HWStubDevice::Probe(std::shared_ptr<hwstub::device> device)
{
if(!device)
return false;
hwstub::error err = device->open(m_handle);
if(err != hwstub::error::SUCCESS)
return false;
// get target information
err = m_handle->get_target_desc(m_hwdev_target);
if(err != hwstub::error::SUCCESS)
return false;
// get STMP/PP information
if(m_hwdev_target.dID == HWSTUB_TARGET_STMP)
{
err = m_handle->get_stmp_desc(m_hwdev_stmp);
if(err != hwstub::error::SUCCESS)
return false;
}
else if(m_hwdev_target.dID == HWSTUB_TARGET_PP)
{
err = m_handle->get_pp_desc(m_hwdev_pp);
if(err != hwstub::error::SUCCESS)
return false;
}
else if(m_hwdev_target.dID == HWSTUB_TARGET_JZ)
{
err = m_handle->get_jz_desc(m_hwdev_jz);
if(err != hwstub::error::SUCCESS)
return false;
}
m_name = HWStubManager::GetFriendlyName(device);
return true;
}
bool HWStubDevice::ReadMem(soc_addr_t addr, size_t length, void *buffer)
{
size_t len = length;
hwstub::error err = m_handle->read(addr, buffer, len, true);
return err == hwstub::error::SUCCESS && len == length;
}
bool HWStubDevice::WriteMem(soc_addr_t addr, size_t length, void *buffer)
{
size_t len = length;
hwstub::error err = m_handle->write(addr, buffer, len, true);
return err == hwstub::error::SUCCESS && len == length;
}
bool HWStubDevice::IsValid()
{
return m_valid;
}
QString HWStubDevice::GetFriendlyName()
{
return m_name;
}
/**
* HWStubIoBackend
*/
HWStubIoBackend::HWStubIoBackend(HWStubDevice *dev)
{
m_dev = dev;
struct hwstub_target_desc_t target = m_dev->GetTargetInfo();
if(target.dID == HWSTUB_TARGET_STMP)
{
struct hwstub_stmp_desc_t stmp = m_dev->GetSTMPInfo();
if(stmp.wChipID == 0x3780)
m_soc = "imx233";
else if(stmp.wChipID >= 0x3700 && stmp.wChipID < 0x3780)
m_soc = "stmp3700";
else if(stmp.wChipID >= 0x3600 && stmp.wChipID < 0x3700)
m_soc = "stmp3600";
else
m_soc = QString("stmp%1").arg(stmp.wChipID, 4, 16, QChar('0'));
}
else if(target.dID == HWSTUB_TARGET_JZ)
{
struct hwstub_jz_desc_t jz = m_dev->GetJZInfo();
m_soc = QString("jz%1").arg(jz.wChipID, 4, 16, QChar('0'));
if(jz.bRevision != 0)
m_soc.append(QChar(jz.bRevision).toLower());
}
else if(target.dID == HWSTUB_TARGET_RK27)
m_soc = "rk27x";
else if(target.dID == HWSTUB_TARGET_PP)
{
struct hwstub_pp_desc_t pp = m_dev->GetPPInfo();
if(pp.wChipID == 0x6110 )
m_soc = "pp6110";
else
m_soc = QString("pp%1").arg(pp.wChipID, 4, 16, QChar('0'));
}
else if(target.dID == HWSTUB_TARGET_ATJ)
m_soc = "atj213x";
else
m_soc = target.bName;
}
QString HWStubIoBackend::GetSocName()
{
return m_soc;
}
HWStubIoBackend::~HWStubIoBackend()
{
delete m_dev;
}
bool HWStubIoBackend::IsValid()
{
return m_dev->IsValid();
}
bool HWStubIoBackend::IsReadOnly()
{
return false;
}
bool HWStubIoBackend::IsDirty()
{
return false;
}
bool HWStubIoBackend::Commit()
{
return true;
}
HWStubDevice *HWStubIoBackend::GetDevice()
{
return m_dev;
}
bool HWStubIoBackend::ReadRegister(soc_addr_t addr, soc_word_t& value,
unsigned width)
{
if(width != 8 && width != 16 && width != 32)
return false;
return m_dev->ReadMem(addr, width / 8, &value);
}
bool HWStubIoBackend::WriteRegister(soc_addr_t addr, soc_word_t value,
unsigned width, WriteMode mode)
{
if(width != 8 && width != 16 && width != 32)
return false;
switch(mode)
{
case Set: addr += 4; break;
case Clear: addr += 8; break;
case Toggle: addr += 12; break;
default: break;
}
return m_dev->WriteMem(addr, width / 8, &value);
}
bool HWStubIoBackend::Reload()
{
return true;
}
#endif /* HAVE_HWSTUB */
/**
* BackendHelper
*/
BackendHelper::BackendHelper(IoBackend *io_backend, const soc_desc::soc_ref_t& soc)
:m_io_backend(io_backend), m_soc(soc)
{
}
QString BackendHelper::GetPath(const soc_desc::node_inst_t& inst)
{
if(!inst.valid() || inst.is_root())
return QString();
QString s = GetPath(inst.parent());
if(!s.isEmpty())
s += ".";
s += inst.name().c_str();
if(inst.is_indexed())
s = QString("%1[%2]").arg(s).arg(inst.index());
return s;
}
soc_desc::node_inst_t BackendHelper::ParsePath(const QString& path)
{
soc_desc::node_inst_t inst = m_soc.root_inst();
/* empty path is root */
if(path.isEmpty())
return inst;
int pos = 0;
while(pos < path.size())
{
/* try to find the next separator */
int next = path.indexOf('.', pos);
if(next == -1)
next = path.size();
/* try to find the index, if any */
int lidx = path.indexOf('[', pos);
if(lidx == -1 || lidx > next)
lidx = next;
/* extract name */
std::string name = path.mid(pos, lidx - pos).toStdString();
/* and index */
if(lidx < next)
{
int ridx = path.indexOf(']', lidx + 1);
/* syntax error ? */
if(ridx == -1 || ridx > next)
return soc_desc::node_inst_t();
/* invalid number ? */
bool ok = false;
size_t idx = path.mid(lidx + 1, ridx - lidx - 1).toUInt(&ok);
if(ok)
inst = inst.child(name, idx);
else
inst = soc_desc::node_inst_t();
}
else
inst = inst.child(name);
/* advance right after the separator */
pos = next + 1;
}
return inst;
}
bool BackendHelper::ReadRegister(const soc_desc::node_inst_t& inst,
soc_word_t& v)
{
soc_addr_t addr;
if(!GetRegisterAddress(inst, addr))
return false;
return m_io_backend->ReadRegister(addr, v, inst.node().reg().get()->width);
}
bool BackendHelper::WriteRegister(const soc_desc::node_inst_t& inst,
soc_word_t v, IoBackend::WriteMode mode)
{
soc_addr_t addr;
if(!GetRegisterAddress(inst, addr))
return false;
return m_io_backend->WriteRegister(addr, v, inst.node().reg().get()->width, mode);
}
bool BackendHelper::GetRegisterAddress(const soc_desc::node_inst_t& inst,
soc_addr_t& addr)
{
if(!inst.valid())
return false;
addr = inst.addr();
return true;
}
bool BackendHelper::ReadRegisterField(const soc_desc::node_inst_t& inst,
const QString& field, soc_word_t& v)
{
soc_desc::field_ref_t ref = inst.node().reg().field(field.toStdString());
if(!ref.valid())
return false;
if(!ReadRegister(inst, v))
return false;
v = (v & ref.get()->bitmask()) >> ref.get()->pos;
return true;
}
bool BackendHelper::DumpAllRegisters(const QString& filename, bool ignore_errors)
{
FileIoBackend b(filename, QString::fromStdString(m_soc.get()->name));
bool ret = DumpAllRegisters(&b, ignore_errors);
return ret && b.Commit();
}
bool BackendHelper::DumpAllRegisters(IoBackend *backend, bool ignore_errors)
{
BackendHelper helper(backend, m_soc);
return DumpAllRegisters(&helper, m_soc.root_inst(), ignore_errors);
}
bool BackendHelper::DumpAllRegisters(BackendHelper *bh,
const soc_desc::node_inst_t& inst, bool ignore_errors)
{
bool ret = true;
if(inst.node().reg().valid())
{
soc_word_t val;
if(!ReadRegister(inst, val))
{
ret = false;
if(!ignore_errors)
return false;
}
else if(!bh->WriteRegister(inst, val))
{
ret = false;
if(!ignore_errors)
return false;
}
}
std::vector< soc_desc::node_inst_t > list = inst.children();
for(size_t i = 0; i < list.size(); i++)
{
if(!DumpAllRegisters(bh, list[i], ignore_errors))
{
ret = false;
if(!ignore_errors)
return false;
}
}
return ret;
}