132 lines
2.9 KiB
C++
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;
|
|
}
|