spo/ass2/simulator/executor.cpp
2025-12-11 07:38:13 +01:00

132 lines
2.9 KiB
C++

#include "executor.h"
#include "machine.h"
#include <QTimer>
#include <QThread>
Executor::Executor(Machine* m)
: QObject(nullptr), machine(m), timer(nullptr)
{
}
Executor::~Executor()
{
if (timer) {
timer->stop();
delete timer;
timer = nullptr;
}
}
bool Executor::hasEnded() const {
return ended;
}
void Executor::resetProgram() {
// resetiraj stanje, poruši izvajanje in spravi lučko v stopped
ended = false;
running = false;
stepping = false;
if (timer) timer->stop();
emit signalStopped();
emit updateRequested();
}
// START: pripravimo timer (v threadu, kjer je ta objekt) in ga zaženemo
void Executor::start() {
// če je končano, pošljemo ended in ne začnemo
if (ended) {
emit signalEnded();
return;
}
// če že tečemo, nič
if (running) return;
running = true;
emit signalStarted();
// timer naj bo kreiran v končni niti (start() bo klican v executorThread preko queued connection)
if (!timer) {
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &Executor::runStep, Qt::DirectConnection);
}
// zaženi timer z intervalom
timer->start(intervalMs);
}
// STOP: takoj ustavimo timer in sporočimo stopped
void Executor::stop() {
if (!running && !timer) {
emit signalStopped();
return;
}
running = false;
stepping = false;
if (timer && timer->isActive()) timer->stop();
emit signalStopped();
emit updateRequested();
}
// runStep: izvede en ukaz — klican iz timer timeout
void Executor::runStep() {
if (!running || ended) {
if (timer && timer->isActive()) timer->stop();
return;
}
// izvedemo en ukaz
int pc_before = machine->getPC();
machine->execute();
int pc_after = machine->getPC();
// obvestimo UI
emit updateRequested();
// preverimo halt / ended
if (pc_before == pc_after) {
ended = true;
// ustavimo timer in pošljemo samo ended (ne stopped)
if (timer && timer->isActive()) timer->stop();
emit signalEnded();
return;
}
// Če je uporabnik pritisnil stop med izvajanjem, ustavimo timer
if (!running) {
if (timer && timer->isActive()) timer->stop();
emit signalStopped();
}
}
// step: en sam korak, le če ne tečemo že v avtomatskem načinu
void Executor::step() {
if (ended) {
emit signalEnded();
return;
}
// če je avtomatsko izvajanje v teku, ignoriramo manualni step
if (running) return;
// preprečimo reentrance
if (stepping) return;
stepping = true;
int pc_before = machine->getPC();
machine->execute();
int pc_after = machine->getPC();
emit updateRequested();
if (pc_after == pc_before) {
ended = true;
emit signalEnded();
} else {
emit signalStopped();
}
stepping = false;
}