Add support for SVA sequence intersect

Signed-off-by: Clifford Wolf <clifford@clifford.at>
This commit is contained in:
Clifford Wolf 2018-03-06 14:26:57 +01:00
parent d86e875f0f
commit 5555292ce2
1 changed files with 251 additions and 36 deletions

View File

@ -91,6 +91,7 @@ struct SvaNFsmNode
// Edge: Activate the target node if ctrl signal is true, consumes clock cycle // Edge: Activate the target node if ctrl signal is true, consumes clock cycle
// Link: Activate the target node if ctrl signal is true, doesn't consume clock cycle // Link: Activate the target node if ctrl signal is true, doesn't consume clock cycle
vector<pair<int, SigBit>> edges, links; vector<pair<int, SigBit>> edges, links;
bool is_cond_node;
}; };
// Non-deterministic FSM after resolving links // Non-deterministic FSM after resolving links
@ -99,7 +100,7 @@ struct SvaUFsmNode
// Edge: Activate the target node if all bits in ctrl signal are true, consumes clock cycle // Edge: Activate the target node if all bits in ctrl signal are true, consumes clock cycle
// Accept: This node functions as an accept node if all bits in ctrl signal are true // Accept: This node functions as an accept node if all bits in ctrl signal are true
vector<pair<int, SigSpec>> edges; vector<pair<int, SigSpec>> edges;
vector<SigSpec> accept; vector<SigSpec> accept, cond;
bool reachable; bool reachable;
}; };
@ -128,14 +129,19 @@ struct SvaFsm
SigBit trigger_sig = State::S1, disable_sig; SigBit trigger_sig = State::S1, disable_sig;
SigBit throughout_sig = State::S1; SigBit throughout_sig = State::S1;
bool materialized = false; bool in_cond_mode = false;
vector<SigBit> disable_stack; vector<SigBit> disable_stack;
vector<SigBit> throughout_stack; vector<SigBit> throughout_stack;
int startNode, acceptNode; int startNode, acceptNode, condNode;
vector<SvaNFsmNode> nodes; vector<SvaNFsmNode> nodes;
vector<SvaUFsmNode> unodes;
dict<vector<int>, SvaDFsmNode> dnodes;
dict<pair<SigSpec, SigSpec>, SigBit> cond_eq_cache;
bool materialized = false;
SigBit final_accept_sig = State::Sx; SigBit final_accept_sig = State::Sx;
SigBit final_reject_sig = State::Sx; SigBit final_reject_sig = State::Sx;
@ -147,6 +153,10 @@ struct SvaFsm
startNode = createNode(); startNode = createNode();
acceptNode = createNode(); acceptNode = createNode();
in_cond_mode = true;
condNode = createNode();
in_cond_mode = false;
} }
void pushDisable(SigBit sig) void pushDisable(SigBit sig)
@ -197,6 +207,7 @@ struct SvaFsm
int idx = GetSize(nodes); int idx = GetSize(nodes);
nodes.push_back(SvaNFsmNode()); nodes.push_back(SvaNFsmNode());
nodes.back().is_cond_node = in_cond_mode;
return idx; return idx;
} }
@ -207,6 +218,12 @@ struct SvaFsm
log_assert(0 <= to_node && to_node < GetSize(nodes)); log_assert(0 <= to_node && to_node < GetSize(nodes));
log_assert(from_node != acceptNode); log_assert(from_node != acceptNode);
log_assert(to_node != acceptNode); log_assert(to_node != acceptNode);
log_assert(from_node != condNode);
log_assert(to_node != condNode);
log_assert(to_node != startNode);
if (from_node != startNode)
log_assert(nodes.at(from_node).is_cond_node == nodes.at(to_node).is_cond_node);
if (throughout_sig != State::S1) { if (throughout_sig != State::S1) {
if (ctrl != State::S1) if (ctrl != State::S1)
@ -224,6 +241,11 @@ struct SvaFsm
log_assert(0 <= from_node && from_node < GetSize(nodes)); log_assert(0 <= from_node && from_node < GetSize(nodes));
log_assert(0 <= to_node && to_node < GetSize(nodes)); log_assert(0 <= to_node && to_node < GetSize(nodes));
log_assert(from_node != acceptNode); log_assert(from_node != acceptNode);
log_assert(from_node != condNode);
log_assert(to_node != startNode);
if (from_node != startNode)
log_assert(nodes.at(from_node).is_cond_node == nodes.at(to_node).is_cond_node);
if (throughout_sig != State::S1) { if (throughout_sig != State::S1) {
if (ctrl != State::S1) if (ctrl != State::S1)
@ -365,14 +387,14 @@ struct SvaFsm
// ---------------------------------------------------- // ----------------------------------------------------
// Generating DFSM circuit to acquire reject signal // Generating DFSM circuit to acquire reject signal
vector<SvaUFsmNode> unodes;
dict<vector<int>, SvaDFsmNode> dnodes;
void node_to_unode(int node, int unode, SigSpec ctrl) void node_to_unode(int node, int unode, SigSpec ctrl)
{ {
if (node == acceptNode) if (node == acceptNode)
unodes[unode].accept.push_back(ctrl); unodes[unode].accept.push_back(ctrl);
if (node == condNode)
unodes[unode].cond.push_back(ctrl);
for (auto &it : nodes[node].edges) { for (auto &it : nodes[node].edges) {
if (it.second != State::S1) { if (it.second != State::S1) {
SigSpec s = {ctrl, it.second}; SigSpec s = {ctrl, it.second};
@ -422,7 +444,7 @@ struct SvaFsm
return true; return true;
} }
void create_dnode(const vector<int> &state, bool firstmatch) void create_dnode(const vector<int> &state, bool firstmatch, bool condaccept)
{ {
if (dnodes.count(state) != 0) if (dnodes.count(state) != 0)
return; return;
@ -436,12 +458,20 @@ struct SvaFsm
dnode.ctrl.append(it.second); dnode.ctrl.append(it.second);
for (auto &it : unodes[unode].accept) for (auto &it : unodes[unode].accept)
dnode.ctrl.append(it); dnode.ctrl.append(it);
for (auto &it : unodes[unode].cond)
dnode.ctrl.append(it);
} }
dnode.ctrl.sort_and_unify(); dnode.ctrl.sort_and_unify();
if (GetSize(dnode.ctrl) > 10) if (GetSize(dnode.ctrl) > 16) {
log_error("SVA property DFSM state ctrl signal has over 10 bits. Stopping to prevent exponential design size explosion.\n"); if (verific_verbose >= 2) {
log(" detected state explosion in DFSM generation:\n");
dump();
log(" ctrl signal: %s\n", log_signal(dnode.ctrl));
}
log_error("SVA DFSM state ctrl signal has %d (>16) bits. Stopping to prevent exponential design size explosion.\n", GetSize(dnode.ctrl));
}
for (int i = 0; i < (1 << GetSize(dnode.ctrl)); i++) for (int i = 0; i < (1 << GetSize(dnode.ctrl)); i++)
{ {
@ -453,36 +483,156 @@ struct SvaFsm
ctrl_bits.insert(dnode.ctrl[i]); ctrl_bits.insert(dnode.ctrl[i]);
vector<int> new_state; vector<int> new_state;
bool accept = false; bool accept = false, cond = false;
for (int unode : state) for (int unode : state) {
for (auto &it : unodes[unode].accept) for (auto &it : unodes[unode].accept)
if (cmp_ctrl(ctrl_bits, it)) if (cmp_ctrl(ctrl_bits, it))
accept = true; accept = true;
for (auto &it : unodes[unode].cond)
if (cmp_ctrl(ctrl_bits, it))
cond = true;
}
bool new_state_cond = false;
bool new_state_noncond = false;
if (accept && condaccept)
accept = cond;
if (!accept || !firstmatch) { if (!accept || !firstmatch) {
for (int unode : state) for (int unode : state)
for (auto &it : unodes[unode].edges) for (auto &it : unodes[unode].edges)
if (cmp_ctrl(ctrl_bits, it.second)) if (cmp_ctrl(ctrl_bits, it.second)) {
if (nodes.at(it.first).is_cond_node)
new_state_cond = true;
else
new_state_noncond = true;
new_state.push_back(it.first); new_state.push_back(it.first);
}
} }
if (accept) if (accept)
dnode.accept.push_back(ctrl_val); dnode.accept.push_back(ctrl_val);
if (condaccept && (!new_state_cond || !new_state_noncond))
new_state.clear();
if (new_state.empty()) { if (new_state.empty()) {
if (!accept) if (!accept)
dnode.reject.push_back(ctrl_val); dnode.reject.push_back(ctrl_val);
} else { } else {
usortint(new_state); usortint(new_state);
dnode.edges.push_back(make_pair(new_state, ctrl_val)); dnode.edges.push_back(make_pair(new_state, ctrl_val));
create_dnode(new_state, firstmatch); create_dnode(new_state, firstmatch, condaccept);
} }
} }
dnodes[state] = dnode; dnodes[state] = dnode;
} }
void optimize_cond(vector<Const> &values)
{
bool did_something = true;
while (did_something)
{
did_something = false;
for (int i = 0; i < GetSize(values); i++)
for (int j = 0; j < GetSize(values); j++)
{
if (i == j)
continue;
log_assert(GetSize(values[i]) == GetSize(values[j]));
int delta_pos = -1;
bool i_within_j = true;
bool j_within_i = true;
for (int k = 0; k < GetSize(values[i]); k++) {
if (values[i][k] == State::Sa && values[j][k] != State::Sa) {
i_within_j = false;
continue;
}
if (values[i][k] != State::Sa && values[j][k] == State::Sa) {
j_within_i = false;
continue;
}
if (values[i][k] == values[j][k])
continue;
if (delta_pos >= 0)
goto next_pair;
delta_pos = k;
}
if (delta_pos >= 0 && i_within_j && j_within_i) {
did_something = true;
values[i][delta_pos] = State::Sa;
values[j] = values.back();
values.pop_back();
goto next_pair;
}
if (delta_pos < 0 && i_within_j) {
did_something = true;
values[i] = values.back();
values.pop_back();
goto next_pair;
}
if (delta_pos < 0 && j_within_i) {
did_something = true;
values[j] = values.back();
values.pop_back();
goto next_pair;
}
next_pair:;
}
}
}
SigBit make_cond_eq(const SigSpec &ctrl, const Const &value, SigBit enable = State::S1)
{
SigSpec sig_a, sig_b;
log_assert(GetSize(ctrl) == GetSize(value));
for (int i = 0; i < GetSize(ctrl); i++)
if (value[i] != State::Sa) {
sig_a.append(ctrl[i]);
sig_b.append(value[i]);
}
if (GetSize(sig_a) == 0)
return enable;
if (enable != State::S1) {
sig_a.append(enable);
sig_b.append(State::S1);
}
auto key = make_pair(sig_a, sig_b);
if (cond_eq_cache.count(key) == 0)
{
if (sig_b == State::S1)
cond_eq_cache[key] = sig_a;
else if (sig_b == State::S0)
cond_eq_cache[key] = module->Not(NEW_ID, sig_a);
else
cond_eq_cache[key] = module->Eq(NEW_ID, sig_a, sig_b);
if (verific_verbose >= 2) {
log(" Cond: %s := %s == %s\n", log_signal(cond_eq_cache[key]),
log_signal(sig_a), log_signal(sig_b));
}
}
return cond_eq_cache.at(key);
}
void getFirstAcceptReject(SigBit *accept_p, SigBit *reject_p) void getFirstAcceptReject(SigBit *accept_p, SigBit *reject_p)
{ {
log_assert(!materialized); log_assert(!materialized);
@ -499,7 +649,7 @@ struct SvaFsm
// Create DFSM // Create DFSM
create_dnode(vector<int>{startNode}, true); create_dnode(vector<int>{startNode}, true, false);
dnodes.sort(); dnodes.sort();
// Create DFSM Circuit // Create DFSM Circuit
@ -519,20 +669,29 @@ struct SvaFsm
for (auto &it : dnodes) for (auto &it : dnodes)
{ {
SvaDFsmNode &dnode = it.second; SvaDFsmNode &dnode = it.second;
dict<vector<int>, vector<Const>> edge_cond;
for (auto &edge : dnode.edges) { for (auto &edge : dnode.edges)
SigBit trig = module->Eq(NEW_ID, {dnode.ctrl, dnode.statesig}, {edge.second, State::S1}); edge_cond[edge.first].push_back(edge.second);
dnodes.at(edge.first).nextstate.append(trig);
for (auto &it : edge_cond) {
optimize_cond(it.second);
for (auto &value : it.second)
dnodes.at(it.first).nextstate.append(make_cond_eq(dnode.ctrl, value, dnode.statesig));
} }
if (accept_p) { if (accept_p) {
for (auto &value : dnode.accept) vector<Const> accept_cond = dnode.accept;
accept_sig.append(module->Eq(NEW_ID, {dnode.ctrl, dnode.statesig}, {value, State::S1})); optimize_cond(accept_cond);
for (auto &value : accept_cond)
accept_sig.append(make_cond_eq(dnode.ctrl, value, dnode.statesig));
} }
if (reject_p) { if (reject_p) {
for (auto &value : dnode.reject) vector<Const> reject_cond = dnode.reject;
reject_sig.append(module->Eq(NEW_ID, {dnode.ctrl, dnode.statesig}, {value, State::S1})); optimize_cond(reject_cond);
for (auto &value : reject_cond)
reject_sig.append(make_cond_eq(dnode.ctrl, value, dnode.statesig));
} }
} }
@ -576,7 +735,7 @@ struct SvaFsm
SigBit getFirstAccept() SigBit getFirstAccept()
{ {
SigBit accept; SigBit accept;
getFirstAcceptReject(nullptr, &accept); getFirstAcceptReject(&accept, nullptr);
return accept; return accept;
} }
@ -587,7 +746,7 @@ struct SvaFsm
return reject; return reject;
} }
void getDFsm(SvaFsm &output_fsm, int output_start_node, int output_accept_node, int output_reject_node) void getDFsm(SvaFsm &output_fsm, int output_start_node, int output_accept_node, int output_reject_node = -1, bool firstmatch = true, bool condaccept = false)
{ {
log_assert(!materialized); log_assert(!materialized);
materialized = true; materialized = true;
@ -603,33 +762,47 @@ struct SvaFsm
// Create DFSM // Create DFSM
create_dnode(vector<int>{startNode}, true); create_dnode(vector<int>{startNode}, firstmatch, condaccept);
dnodes.sort(); dnodes.sort();
// Create DFSM Graph // Create DFSM Graph
for (auto &it : dnodes) for (auto &it : dnodes)
{ {
it.second.outnode = output_fsm.createNode(); SvaDFsmNode &dnode = it.second;
dnode.outnode = output_fsm.createNode();
if (it.first == vector<int>{startNode}) if (it.first == vector<int>{startNode})
output_fsm.createLink(output_start_node, it.second.outnode); output_fsm.createLink(output_start_node, dnode.outnode);
if (output_accept_node >= 0) { if (output_accept_node >= 0) {
for (auto &value : it.second.accept) vector<Const> accept_cond = dnode.accept;
output_fsm.createLink(it.second.outnode, output_accept_node, module->Eq(NEW_ID, it.second.ctrl, value)); optimize_cond(accept_cond);
for (auto &value : accept_cond)
output_fsm.createLink(it.second.outnode, output_accept_node, make_cond_eq(dnode.ctrl, value));
} }
if (output_reject_node >= 0) { if (output_reject_node >= 0) {
for (auto &value : it.second.reject) vector<Const> reject_cond = dnode.reject;
output_fsm.createLink(it.second.outnode, output_reject_node, module->Eq(NEW_ID, it.second.ctrl, value)); optimize_cond(reject_cond);
for (auto &value : reject_cond)
output_fsm.createLink(it.second.outnode, output_reject_node, make_cond_eq(dnode.ctrl, value));
} }
} }
for (auto &it : dnodes) for (auto &it : dnodes)
{ {
for (auto &edge : it.second.edges) SvaDFsmNode &dnode = it.second;
output_fsm.createEdge(it.second.outnode, dnodes.at(edge.first).outnode, module->Eq(NEW_ID, it.second.ctrl, edge.second)); dict<vector<int>, vector<Const>> edge_cond;
for (auto &edge : dnode.edges)
edge_cond[edge.first].push_back(edge.second);
for (auto &it : edge_cond) {
optimize_cond(it.second);
for (auto &value : it.second)
output_fsm.createEdge(dnode.outnode, dnodes.at(it.first).outnode, make_cond_eq(dnode.ctrl, value));
}
} }
} }
@ -644,7 +817,10 @@ struct SvaFsm
log(" non-deterministic encoding:\n"); log(" non-deterministic encoding:\n");
for (int i = 0; i < GetSize(nodes); i++) for (int i = 0; i < GetSize(nodes); i++)
{ {
log(" node %d:%s\n", i, i == startNode ? " [start]" : i == acceptNode ? " [accept]" : ""); log(" node %d:%s\n", i,
i == startNode ? " [start]" :
i == acceptNode ? " [accept]" :
i == condNode ? " [cond]" : "");
for (auto &it : nodes[i].edges) { for (auto &it : nodes[i].edges) {
if (it.second != State::S1) if (it.second != State::S1)
@ -688,6 +864,13 @@ struct SvaFsm
else else
log(" accept\n"); log(" accept\n");
} }
for (auto &ctrl : unodes[i].cond) {
if (!ctrl.empty())
log(" cond %s\n", log_signal(ctrl));
else
log(" cond\n");
}
} }
} }
@ -980,6 +1163,38 @@ struct VerificSvaImporter
int node = fsm.createNode(); int node = fsm.createNode();
combined_fsm.getDFsm(fsm, start_node, -1, node); combined_fsm.getDFsm(fsm, start_node, -1, node);
if (verific_verbose)
{
log(" Left And FSM:\n");
fsm1.dump();
log(" Right And FSM:\n");
fsm1.dump();
log(" Combined And FSM:\n");
combined_fsm.dump();
}
return node;
}
if (inst->Type() == PRIM_SVA_INTERSECT)
{
SvaFsm intersect_fsm(clocking);
intersect_fsm.createLink(parse_sequence(intersect_fsm, intersect_fsm.startNode, inst->GetInput1()), intersect_fsm.acceptNode);
intersect_fsm.in_cond_mode = true;
intersect_fsm.createLink(parse_sequence(intersect_fsm, intersect_fsm.startNode, inst->GetInput2()), intersect_fsm.condNode);
intersect_fsm.in_cond_mode = false;
int node = fsm.createNode();
intersect_fsm.getDFsm(fsm, start_node, node, -1, false, true);
if (verific_verbose) {
log(" Intersect FSM:\n");
intersect_fsm.dump();
}
return node; return node;
} }