wiRedPanda
Logic Circuit Simulator
Loading...
Searching...
No Matches
WaveformSimulator.cpp
Go to the documentation of this file.
1// Copyright 2015 - 2026, GIBIS-UNIFESP and the wiRedPanda contributors
2// SPDX-License-Identifier: GPL-3.0-or-later
3
5
6#include <utility>
7
8#include "App/Core/Common.h"
11#include "App/Scene/Scene.h"
15
17 : m_externalScene(externalScene)
18 , m_simulation(simulation)
19{
20}
21
22QVector<Status> WaveformSimulator::captureInputs(const QVector<GraphicElementInput *> &inputs, const int inputPorts)
23{
24 QVector<Status> oldValues(inputPorts);
25 int oldIndex = 0;
26
27 for (auto *input : std::as_const(inputs)) {
28 for (int port = 0; port < input->outputSize(); ++port) {
29 // Snapshot the live port state before the simulation sweep overwrites it
30 oldValues[oldIndex] = input->outputPort(port)->status();
31 ++oldIndex;
32 }
33 }
34
35 return oldValues;
36}
37
38void WaveformSimulator::restoreInputs(const QVector<GraphicElementInput *> &inputs, const QVector<Status> &saved)
39{
40 qCDebug(zero) << "Restoring old values to inputs, prior to simulation.";
41
42 // `saved` is indexed by PORT (one entry per output port of each input element),
43 // not by element. A separate port-level index is required to avoid reading the wrong
44 // saved value for multi-port inputs (e.g. InputRotary).
45 int portIndex = 0;
46 for (auto *input : std::as_const(inputs)) {
47 for (int port = 0; port < input->outputSize(); ++port) {
48 const bool oldValue = static_cast<bool>(saved.at(portIndex++));
49 if (input->outputSize() > 1) {
50 input->setOn(oldValue, port);
51 } else {
52 input->setOn(oldValue);
53 }
54 }
55 }
56}
57
58void WaveformSimulator::sweep(const QVector<GraphicElementInput *> &inputs,
59 const QVector<GraphicElement *> &outputs,
60 const int inputPorts, const int columns,
61 const std::function<bool(int row, int col)> &readInput,
62 const std::function<void(int row, int col, int value)> &writeOutput) const
63{
64 // Block the live simulation timer while we drive the circuit manually column by column
65 qCDebug(zero) << "Creating class to pause main window simulator while creating waveform.";
66 SimulationBlocker simulationBlocker(m_simulation);
67 // Disable the visual refresh throttle so phases 3–4 (port-status updates) run on every
68 // update() call. Without this, output port statuses are stale for most columns and the
69 // waveform shows incorrect values.
70 SimulationThrottleDisabler throttleDisabler(m_simulation);
71
72 // Reset every element's sequential state (Q/~Q outputs, edge-detection variables) to
73 // power-on defaults before the sweep so results are reproducible regardless of any
74 // prior simulation run that may have left flip-flops in a different state.
75 qCDebug(zero) << "Resetting simulation state of all elements.";
76 for (auto *elm : m_externalScene->elements()) {
77 if (elm && elm->type() == GraphicElement::Type) {
78 elm->resetSimState();
79 }
80 }
81
82 // --- Step through each time column and compute circuit outputs ---
83 for (int column = 0; column < columns; ++column) {
84 qCDebug(four) << "Itr: " << column << ", inputs: " << inputs.size();
85 int row = 0;
86
87 for (auto *input : std::as_const(inputs)) {
88 for (int port = 0; port < input->outputSize(); ++port) {
89 // Each input applies the cell value its own way (e.g. a rotary ignores lows).
90 input->setWaveformValue(readInput(row++, column), port);
91 }
92 }
93
94 qCDebug(four) << "Updating the values of the circuit logic based on current input values.";
95 m_simulation->update();
96
97 // Write computed output port states back into the model's output rows
98 qCDebug(four) << "Setting the computed output values to the waveform results.";
99 row = inputPorts;
100
101 for (auto *output : std::as_const(outputs)) {
102 for (int port = 0; port < output->inputSize(); ++port) {
103 const int value = static_cast<int>(output->inputPort(port)->status());
104 writeOutput(row, column, value);
105 ++row;
106 }
107 }
108 }
109}
Common logging utilities, the Pandaception error type, and helper macros.
#define qCDebug(category)
Definition Common.h:29
Abstract base class for user-controllable input elements.
Abstract base class for all graphical circuit elements.
Main circuit editing scene with undo/redo and user interaction.
RAII guard that temporarily stops the simulation while in scope.
RAII guard that disables the visual refresh throttle while in scope.
Synchronous cycle-based simulation engine with event-driven clock support.
Drives the wiRedPanda circuit simulation column-by-column for the waveform table.
Main circuit editing scene.
Definition Scene.h:56
RAII guard that stops the simulation on construction and restarts it on destruction.
RAII guard that disables the visual refresh throttle for the duration of its scope.
Manages the digital circuit simulation loop.
Definition Simulation.h:38
WaveformSimulator(Scene *externalScene, Simulation *simulation)
Constructs the driver for externalScene and its simulation.
static QVector< Status > captureInputs(const QVector< GraphicElementInput * > &inputs, int inputPorts)
Snapshots the live output-port state of every input element.
void sweep(const QVector< GraphicElementInput * > &inputs, const QVector< GraphicElement * > &outputs, int inputPorts, int columns, const std::function< bool(int row, int col)> &readInput, const std::function< void(int row, int col, int value)> &writeOutput) const
Runs the simulation across columns time steps.
static void restoreInputs(const QVector< GraphicElementInput * > &inputs, const QVector< Status > &saved)
Restores input-port states previously captured by captureInputs().