Implement synchronization between deleting peripherals/changing processors
MODIFY
src/io/iomanager.cpp
src/io/iomanager.cpp
@@ -9,45 +9,74 @@ namespace Ripes {
IOManager::IOManager() : QObject(nullptr) {
// Always re-register the currently active peripherals when the processor changes
- connect(ProcessorHandler::get(), &ProcessorHandler::processorChanged, this, &IOManager::setProcessorPeripherals);
+ connect(ProcessorHandler::get(), &ProcessorHandler::processorChanged, this,
+ &IOManager::refreshAllPeriphsToProcessor);
connect(ProcessorHandler::get(), &ProcessorHandler::reqProcessorReset, this, &IOManager::refreshMemoryMap);
refreshMemoryMap();
}
-IOBase* IOManager::createPeripheral(IOType type) {
- auto* peripheral = IOFactories.at(type)(nullptr);
-
- // Assign base address to peripheral
- uint32_t base;
+uint32_t IOManager::nextPeripheralAddress() const {
+ uint32_t base = 0;
if (m_peripherals.empty()) {
base = RipesSettings::value(RIPES_SETTING_PERIPHERALS_START).toUInt();
} else {
- auto lastPeriph = m_peripherals.rbegin();
- base = lastPeriph->first + lastPeriph->second.size;
+ for (const auto& periph : m_peripherals) {
+ if (periph.second.end() > base) {
+ base = periph.second.end();
+ }
+ }
+ }
+ return base;
}
+void IOManager::registerPeripheralToProcessor(IOBase* peripheral) {
ProcessorHandler::get()->getMemory().addRegion(
- base, peripheral->size(),
+ m_peripherals.at(peripheral).startAddr, peripheral->size(),
vsrtl::core::IOFunctors{
[peripheral](uint32_t offset, uint32_t value, uint32_t size) { peripheral->ioWrite(offset, value, size); },
[peripheral](uint32_t offset, uint32_t size) { return peripheral->ioRead(offset, size); }});
+}
- m_peripherals[base] = {peripheral->size(), peripheral->name()};
+IOBase* IOManager::createPeripheral(IOType type) {
+ auto* peripheral = IOFactories.at(type)(nullptr);
+
+ // Assign base address to peripheral
+ const uint32_t base = nextPeripheralAddress();
+ m_peripherals[peripheral] = {base, peripheral->size(), peripheral->name()};
+ registerPeripheralToProcessor(peripheral);
refreshMemoryMap();
return peripheral;
}
-void IOManager::setProcessorPeripherals() {}
+void IOManager::removePeripheral(IOBase* peripheral) {
+ auto periphit = m_peripherals.find(peripheral);
+ Q_ASSERT(periphit != m_peripherals.end());
+ const auto& mmEntry = m_peripherals.at(peripheral);
+ ProcessorHandler::get()->getMemory().removeRegion(mmEntry.startAddr, mmEntry.size);
+ m_peripherals.erase(periphit);
+ refreshMemoryMap();
+}
+
+void IOManager::refreshAllPeriphsToProcessor() {
+ for (const auto& periph : m_peripherals) {
+ registerPeripheralToProcessor(periph.first);
+ }
+}
void IOManager::refreshMemoryMap() {
- m_memoryMap = m_peripherals;
+ m_memoryMap.clear();
+
+ for (const auto& periph : m_peripherals) {
+ m_memoryMap[periph.second.startAddr] = periph.second;
+ }
const auto& program = ProcessorHandler::get()->getProgram();
if (program) {
for (const auto& section : program.get()->sections) {
m_memoryMap[section.second.address] =
- MemoryMapEntry{static_cast<unsigned>(section.second.data.size()), section.second.name};
+ MemoryMapEntry{static_cast<uint32_t>(section.second.address),
+ static_cast<unsigned>(section.second.data.size()), section.second.name};
}
}

MODIFY
src/io/iomanager.h
src/io/iomanager.h
namespace Ripes {
struct MemoryMapEntry {
+ uint32_t startAddr;
unsigned size;
QString name;
+ uint32_t end() const { return startAddr + size; }
};
using MemoryMap = std::map<uint32_t, MemoryMapEntry>;
@@ -18,6 +20,7 @@ class IOManager : public QObject {
public:
IOManager();
IOBase* createPeripheral(IOType type);
+ void removePeripheral(IOBase* peripheral);
const MemoryMap& memoryMap() const { return m_memoryMap; }
signals:
@@ -25,9 +28,29 @@ signals:
private:
void refreshMemoryMap();
- void setProcessorPeripherals();
+
+ /**
+ * @brief registerPeripheralToProcessor
+ * Registers @param peripheral with the processor. Specifically, the peripheral hooks into the memory of the
+ * processor, and creates the link between the peripheral memory read/write functionality, and the processor memory.
+ */
+ void registerPeripheralToProcessor(IOBase* peripheral);
+
+ /**
+ * @brief refreshAllPeriphsToProcessor
+ * Shall be called after changing the processor. Registers all the currently initialized peripherals to the (new)
+ * processor.
+ */
+ void refreshAllPeriphsToProcessor();
+
+ /**
+ * @brief nextPeripheralAddress
+ * @returns a valid base address for a new peripheral
+ */
+ uint32_t nextPeripheralAddress() const;
+
MemoryMap m_memoryMap;
- MemoryMap m_peripherals;
+ std::map<IOBase*, MemoryMapEntry> m_peripherals;
};
} // namespace Ripes

MODIFY
src/iotab.cpp
src/iotab.cpp
@@ -69,13 +69,6 @@ IOTab::IOTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, parent), m_
m_ui->memoryMapView->horizontalHeader()->setSectionResizeMode(MemoryMapModel::Size, QHeaderView::ResizeToContents);
}
-/**
- * Dummy function, should be moved to a separate memory map manager
- */
-uint32_t nextAddress() {
- return 0x10000;
-}
-
void IOTab::createPeripheral(IOType type) {
auto* peripheral = m_iomanager.createPeripheral(type);
// Create tab for peripheral
@@ -87,12 +80,13 @@ void IOTab::createPeripheral(IOType type) {
// behaviour + dockable widgets that are able to pop out to a separate window
auto* mw = new QMainWindow(this);
m_ui->dockArea->addWidget(mw); // Shouldn't be needed, but MDI windows aren't created without this?
- auto* dw = new QDockWidget(IOTypeTitles.at(type));
+ auto* dw = new QDockWidget();
dw->setFeatures(dw->features() & ~QDockWidget::DockWidgetClosable);
dw->setWidget(peripheral);
dw->setAllowedAreas(Qt::AllDockWidgetAreas);
mw->addDockWidget(Qt::TopDockWidgetArea, dw);
auto* mdiw = m_ui->mdiArea->addSubWindow(mw);
+ mdiw->setWindowTitle(IOTypeTitles.at(type));
m_subWindows[peripheralTab] = mdiw;
@@ -125,6 +119,11 @@ void IOTab::setPeripheralMDIWindowActive(int tabIndex) {
}
void IOTab::removePeripheral(QObject* peripheral) {
+ // This might be a little ugly. We have to static cast to an IOBase, given that, when QObject::destroyed is emitted,
+ // the entire inheriting class hierarchy has already been destroyed (thus we cannot dynamic_cast to an IOBase).
+ // However, the base pointer stays the same...
+ m_iomanager.removePeripheral(static_cast<IOBase*>(peripheral));
+
auto* tab = m_ioTabs.at(peripheral);
Q_ASSERT(m_subWindows.count(tab) != 0);
m_subWindows.erase(tab);

MODIFY
src/iotab.h
src/iotab.h
@@ -49,6 +49,7 @@ private:
* IOBase* subclass has already been destroyed.
*/
std::unordered_map<QObject*, QWidget*> m_ioTabs;
+
/**
* @brief m_ioTabs
* Pointer from the tab associated with a peripheral to its corresponding MDI subwindow.

Implement synchronization between deleting peripherals/changing processors