Skip to content

Commit

Permalink
Merge pull request #593 from emsec/fix/net_group_algorithm
Browse files Browse the repository at this point in the history
Fix/net group algorithm
  • Loading branch information
joern274 authored Oct 25, 2024
2 parents c7a3c68 + efbcce2 commit 65f57ff
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 52 deletions.
97 changes: 71 additions & 26 deletions plugins/logic_evaluator/src/logic_evaluator_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ namespace hal {
std::unordered_set<const Net*> inputNets = mSimulationInput->get_input_nets();
for (SimulationInput::NetGroup grp : mSimulationInput->get_net_groups())
{
if (!grp.is_input) continue;
if (!grp.is_input())
continue;
for (const Net* n : grp.get_nets())
{
auto it = inputNets.find(n);
Expand All @@ -80,7 +81,8 @@ namespace hal {
std::unordered_set<const Net*> outputNets(mSimulationInput->get_output_nets().begin(),mSimulationInput->get_output_nets().end());
for (SimulationInput::NetGroup grp : mSimulationInput->get_net_groups())
{
if (grp.is_input) continue;
if (!grp.is_output())
continue;
bool isOutputGroup = true;

std::vector<const Net*> temp;
Expand Down Expand Up @@ -287,39 +289,82 @@ namespace hal {
// propagate by gates
for (const Gate* g : mEvaluationOrder)
{
QMap<QString,QString> referableOutputPins;

for (const GatePin* gp : g->get_type()->get_output_pins())
struct FunctionReference
{
QString pinNameOut = QString::fromStdString(gp->get_name());
const Net* nOut = g->get_fan_out_net(gp);
if (!mExternalArrayIndex.contains(nOut))
QString theFunction;
QSet<QString> dependencies;
bool placed;
FunctionReference() : placed(false) {;}
FunctionReference(const BooleanFunction& func)
: placed(false)
{
int sz = mExternalArrayIndex.size();
mExternalArrayIndex[nOut] = sz;
theFunction = QString::fromStdString(func.to_string());
for (std::string dep : func.get_variable_names())
dependencies.insert(QString::fromStdString(dep));
}

QString theFunction = QString::fromStdString(g->get_boolean_function(gp).to_string());
for (const GatePin* gp : g->get_type()->get_input_pins())
void replace(const QString& var, const QString& ccExpression)
{
QString pinNameIn = QString::fromStdString(gp->get_name());
const Net* nIn = g->get_fan_in_net(gp);
int inxIn = mExternalArrayIndex.value(nIn,-1);
if (inxIn < 0) return false;
QString ccVar = QString("logic_evaluator_signals[%1]").arg(inxIn);
theFunction.replace(pinNameIn, ccVar);
auto it = dependencies.find(var);
if (it == dependencies.end()) return;
theFunction.replace(var, ccExpression);
dependencies.erase(it);
}
for (auto it = referableOutputPins.constBegin(); it != referableOutputPins.constEnd(); ++it)
};

QMap<const GatePin*,FunctionReference> referableOutputPins;
int unresolved = 0;

// collect all functions
for (const GatePin* gp : g->get_type()->get_output_pins())
{
QString pinNameOut = QString::fromStdString(gp->get_name());
referableOutputPins[gp] = FunctionReference(g->get_boolean_function(gp));
++unresolved;
}

// replace input pins by C-Variable
for (const GatePin* gp : g->get_type()->get_input_pins())
{
QString pinNameIn = QString::fromStdString(gp->get_name());
const Net* nIn = g->get_fan_in_net(gp);
int inxIn = mExternalArrayIndex.value(nIn,-1);
if (inxIn < 0) return false;
QString ccVar = QString("logic_evaluator_signals[%1]").arg(inxIn);
for (auto it = referableOutputPins.begin(); it != referableOutputPins.end(); ++it)
it->replace(pinNameIn, ccVar);
}

QString gateFunctions;

// place and resolve outputs
int lastUnresolved = 0;
while (unresolved || lastUnresolved == unresolved)
{
lastUnresolved = unresolved;
for (auto it = referableOutputPins.begin(); it != referableOutputPins.end(); ++it)
{
theFunction.replace(it.key(),it.value());
if (!it->dependencies.isEmpty() || it->placed) continue;
const GatePin* gp = it.key();
const Net* nOut = g->get_fan_out_net(gp);
int inxOut = mExternalArrayIndex.value(nOut,-1);
if (inxOut < 0)
{
inxOut = mExternalArrayIndex.size();
mExternalArrayIndex[nOut] = inxOut;
}
QString pinNameOut = QString::fromStdString(gp->get_name());
QString ccVar = QString("logic_evaluator_signals[%1]").arg(inxOut);
for (auto jt = referableOutputPins.begin(); jt != referableOutputPins.end(); ++jt)
if (it != jt) jt->replace(pinNameOut, ccVar);
gateFunctions += QString(" %1 = %2;\n").arg(ccVar).arg(it->theFunction);
it->placed=true;
--unresolved;
}
}

int inxOut = mExternalArrayIndex.value(nOut,-1);
if (inxOut < 0) return false;
codeEvalFunction += QString(" logic_evaluator_signals[%1] = %2;\n").arg(inxOut).arg(theFunction);
if (unresolved) return false;

referableOutputPins[pinNameOut] = QString("logic_evaluator_signals[%1]").arg(inxOut);
}
codeEvalFunction += gateFunctions;
}

for (LogicEvaluatorPingroup* lepg : mOutputs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ namespace hal {
class SimulationInput {

public:
enum DirectionType { Undefined, InputOnly, OutputOnly, Mixed};

struct Clock
{
const Net* clock_net;
Expand All @@ -59,13 +61,15 @@ namespace hal {

struct NetGroup
{
bool is_input;
DirectionType direction;
const Gate* gate;
PinGroup<ModulePin>* module_pin_group;
PinGroup<GatePin>* gate_pin_group;
NetGroup() : is_input(true), gate(nullptr), module_pin_group(nullptr), gate_pin_group(nullptr) {;}
NetGroup() : direction(Undefined), gate(nullptr), module_pin_group(nullptr), gate_pin_group(nullptr) {;}
std::vector<const Net*> get_nets() const;
std::string get_name() const;
bool is_input() const { return direction == InputOnly; }
bool is_output() const { return direction == OutputOnly; }
};

private:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -951,11 +951,11 @@ namespace hal
{
if (inputs)
{
if (!ng.is_input) continue;
if (!ng.is_input()) continue;
}
else
{
if (ng.is_input) continue;
if (ng.is_input()) continue;
}
if (ng.gate)
add_waveform_group(ng.gate, ng.gate_pin_group);
Expand Down Expand Up @@ -1023,7 +1023,7 @@ namespace hal

for (SimulationInput::NetGroup ng : mSimulationInput->get_net_groups())
{
if (!ng.is_input) continue;
if (!ng.is_input()) continue;
InputColumnHeader ipc;
ipc.name = ng.get_name();
ipc.is_clock = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,11 @@ namespace hal {
std::unordered_set<const Module*> simulated_modules;

// all nets that are part of the simulation
std::unordered_set<const Net*> single_nets(m_partial_nets.begin(), m_partial_nets.end());
std::unordered_map<const Net*, DirectionType> ungrouped_nets;

for (const Net* n : m_partial_nets) ungrouped_nets[n] = Undefined;
for (const Net* n : m_input_nets) ungrouped_nets[n] = InputOnly;
for (const Net* n : m_output_nets) ungrouped_nets[n] = OutputOnly;

// all modules that contain at least one simulated gate
for (const Gate* g : mSimulationSet)
Expand Down Expand Up @@ -281,32 +285,40 @@ namespace hal {
{
if (pg->size() < 2) continue;
bool pin_group_simulated = true;
DirectionType groupType = Undefined;

for (ModulePin* mp : pg->get_pins())
{
Net* n = mp->get_net();
if (n)
{
if (single_nets.find(n) == single_nets.end())
auto itNet = ungrouped_nets.find(n);
if (itNet == ungrouped_nets.end())
{
// pin : net exists and is not part of the simulation, ignore pin group
pin_group_simulated = false;
break;
}
else
{
if (groupType == Undefined)
groupType = itNet->second;
else if (groupType != Mixed && groupType != itNet->second)
groupType = Mixed;
}
}
}
if (pin_group_simulated)
{
NetGroup group;
group.module_pin_group = pg;
group.direction = groupType;
for (ModulePin* mp : pg->get_pins())
{
Net* n = mp->get_net();
if (n)
{
single_nets.erase(n);
if (!is_input_net(n))
group.is_input = false;
ungrouped_nets.erase(n);
}
}
m_netgroups.push_back(group);
Expand All @@ -325,6 +337,8 @@ namespace hal {
{
if (pg->size() < 2) continue;
bool pin_group_simulated = true;
DirectionType groupType = Undefined;
std::unordered_set<const Net*> connectedNets;

for (GatePin* gp : pg->get_pins())
{
Expand All @@ -342,34 +356,34 @@ namespace hal {
}
if (n)
{
if (single_nets.find(n) == single_nets.end())
auto itNet = ungrouped_nets.find(n);
if (itNet == ungrouped_nets.end())
{
// pin : net alreade assigned to module pin group, ignore gate pin group
// pin : net already assigned to module pin group, ignore gate pin group
pin_group_simulated = false;
break;
}
else
{
connectedNets.insert(n);
if (groupType == Undefined)
groupType = itNet->second;
else if (groupType != Mixed && groupType != itNet->second)
groupType = Mixed;
}
}
else
pin_group_simulated = false;
}

if (pin_group_simulated)
{
NetGroup group;
group.gate = g;
group.gate_pin_group = pg;
if (pg->get_direction() == PinDirection::input)
{
for (GatePin* gp : pg->get_pins())
{
Net* n = g->get_fan_in_net(gp);
if (n && !is_input_net(n))
{
group.is_input = false;
break;
}
}
}
else
group.is_input = false;
group.direction = groupType;
for (const Net* n : connectedNets)
ungrouped_nets.erase(n);
m_netgroups.push_back(group);
}
}
Expand Down

0 comments on commit 65f57ff

Please sign in to comment.