Как моделировать цифровые логические схемы с помощью контуров обратной связи?

Я учусь моделировать цифровые логические схемы.
Я представляю исходный код моей первой попытки здесь.
Это небольшая программа для моделирования цепей, состоящая из
И, ИЛИ И НЕ ворота.

Этот код хорошо работает для схем без петель.
Когда вводятся контуры схемы, это вызывает переполнение стека из-за бесконечной рекурсии.
Пожалуйста, помогите мне удалить эту ошибку.

Обратите внимание, что это хобби-проект, и любая помощь будет оценена.

Исходный код :

#include <cstdlib>
#include <iostream>
using namespace std;

class LogicGate
{
int type;//gate type: 0 for NOT, 1 for OR, 2 for AND
//pins
bool ina;//input a
bool inb;//input b::this pin is not used for NOT gate
bool outc;//output

//fan-in
LogicGate* ga;//gate connected to input a
LogicGate* gb;//gate connected to input b

//fan-out
LogicGate* gc;//gate connected to output
int gctarget;//target input to which the gate "gc" is connected, 0 for input a, 1 for input cpublic:
char* name;
LogicGate()
{
ina = inb = outc = false;
ga = gb = gc = (LogicGate*)0;
type = 0;
}
LogicGate(bool a, bool b)
{
ina = a; inb = b; outc = false;
ga = gb = gc = (LogicGate*)0;
type = 0;
}

//set logic
void settype(int t){if(t>=0&&t<3)type=t;else type=0;}

//set input
void seta(bool a){ ina = a; }
void setb(bool b){ inb = b; }
void setab(bool a, bool b){ina = a; inb = b; }

//connect gate
void cona(LogicGate* cga){ ga = cga; }
void conb(LogicGate* cgb){ gb = cgb; }
void conab(LogicGate* cga, LogicGate* cgb){ ga = cga; gb = cgb; }

//connect the output of this gate to another gate's input
void chainc(LogicGate* cgc, int target)
{
gc = cgc;
gctarget = target;
if(target==0) cgc->cona(this); else cgc->conb(this);
}

//calculate output
bool calcout()
{
//if the input is not available make it available by forcing the connected gates to calculate
if(ga){ ina = ga->calcout(); } //BUG:this may cause Stack overflow for circuits with loops
if(gb){ inb = gb->calcout(); }//BUG:this may cause Stack overflow for circuits with loops

//do the logic when inputs are available
switch(type)
{
case 0:
outc = !ina; break;
case 1:
outc = ina || inb; break;
case 2:
outc = ina && inb; break;
}

//if a gate is connected to output pin transfer the output value to the target input pin of the gate
if(gc){
if(gctarget==0){
gc->seta(outc);
}else{
gc->setb(outc);
}
}

//for debugging only
cout<<name<<" outputs "<<outc<<endl;
return outc;
}};
int main(int argc, char *argv[])
{
LogicGate x,z;

//AND gate
z.settype(2);
z.seta(false);
z.setb(true);
z.name = "ZZZ";//OR gate
x.settype(1);
x.cona(&z); // take one input from AND gate's output
x.setb(true);
x.name = "XXX";

//z.cona(&x);// take one input from OR gate's output to make a loop:: results in stack overflow
x.chainc(&z,0);//connect the output to AND gate's input "a" to form loop:: results in stack overflow

cout<<"final output"<<x.calcout()<<endl;

return 0;
}

0

Решение

Проблема в том, что вы бесконечно зацикливаетесь. Программа ведет себя как-то иначе, чем реальный логические ворота. Я вижу две возможности здесь:

1) Реализация циклов

Вы можете реализовать это так, как работает процессор. вызов для расчета рассчитывает только на выход одного шлюза и переходит к следующему. Вы можете создать класс Container для ваших ворот:

class GateContainer
{
//Contains all gates of your "circuit"std::vector<LogicalGate> allGates;

//Contains all current gates to be processed
std::queue<LogicalGate*> currentGates;

void nextStep();
}

Функция nextStep может выглядеть так:

void GateContainer::nextStep()
{
//Get first gate from queue
LogicalGate *current = currentGates.front();
currentGates.pop();

//Do all the calculations with th current gate

//Push the gate connected to the Output to the list
currentGates.push(current->gc);
}

Пожалуйста, обратите внимание, что этот код не проверен и может также нуждаться в проверке ошибок.

2) Попробуйте поймать петли

Вы также можете попробовать поймать петли в calcout, Этого можно добиться, создав флаг в LogicalGate и сбрасывая его каждый раз перед вызовом calcout:

class LogicalGate
{
...
bool calculated;
...
}

Сейчас перед звонком calcout() Вам нужно установить рассчитанный на false за каждые ворота. Тогда вычисление может выглядеть примерно так:

bool calcout()
{
calculated = true;

if(ga && !ga->calculated){ ina = ga->calcout(); }
if(gb && !ga->calculated){ inb = gb->calcout(); }

...
}
0

Другие решения


По вопросам рекламы [email protected]