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
// Link: Activate the target node if ctrl signal is true, doesn't consume clock cycle
vector<pair<int, SigBit>> edges, links;
bool is_cond_node;
};
// 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
// Accept: This node functions as an accept node if all bits in ctrl signal are true
vector<pair<int, SigSpec>> edges;
vector<SigSpec> accept;
vector<SigSpec> accept, cond;
bool reachable;
};
@ -128,14 +129,19 @@ struct SvaFsm
SigBit trigger_sig = State::S1, disable_sig;
SigBit throughout_sig = State::S1;
bool materialized = false;
bool in_cond_mode = false;
vector<SigBit> disable_stack;
vector<SigBit> throughout_stack;
int startNode, acceptNode;
int startNode, acceptNode, condNode;
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_reject_sig = State::Sx;
@ -147,6 +153,10 @@ struct SvaFsm
startNode = createNode();
acceptNode = createNode();
in_cond_mode = true;
condNode = createNode();
in_cond_mode = false;
}
void pushDisable(SigBit sig)
@ -197,6 +207,7 @@ struct SvaFsm
int idx = GetSize(nodes);
nodes.push_back(SvaNFsmNode());
nodes.back().is_cond_node = in_cond_mode;
return idx;
}
@ -207,6 +218,12 @@ struct SvaFsm
log_assert(0 <= to_node && to_node < GetSize(nodes));
log_assert(from_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 (ctrl != State::S1)
@ -224,6 +241,11 @@ struct SvaFsm
log_assert(0 <= from_node && from_node < GetSize(nodes));
log_assert(0 <= to_node && to_node < GetSize(nodes));
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 (ctrl != State::S1)
@ -365,14 +387,14 @@ struct SvaFsm
// ----------------------------------------------------
// 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)
{
if (node == acceptNode)
unodes[unode].accept.push_back(ctrl);
if (node == condNode)
unodes[unode].cond.push_back(ctrl);
for (auto &it : nodes[node].edges) {
if (it.second != State::S1) {
SigSpec s = {ctrl, it.second};
@ -422,7 +444,7 @@ struct SvaFsm
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)
return;
@ -436,12 +458,20 @@ struct SvaFsm
dnode.ctrl.append(it.second);
for (auto &it : unodes[unode].accept)
dnode.ctrl.append(it);
for (auto &it : unodes[unode].cond)
dnode.ctrl.append(it);
}
dnode.ctrl.sort_and_unify();
if (GetSize(dnode.ctrl) > 10)
log_error("SVA property DFSM state ctrl signal has over 10 bits. Stopping to prevent exponential design size explosion.\n");
if (GetSize(dnode.ctrl) > 16) {
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++)
{
@ -453,36 +483,156 @@ struct SvaFsm
ctrl_bits.insert(dnode.ctrl[i]);
vector<int> new_state;
bool accept = false;
bool accept = false, cond = false;
for (int unode : state)
for (auto &it : unodes[unode].accept)
if (cmp_ctrl(ctrl_bits, it))
accept = true;
for (int unode : state) {
for (auto &it : unodes[unode].accept)
if (cmp_ctrl(ctrl_bits, it))
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) {
for (int unode : state)
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);
}
}
if (accept)
dnode.accept.push_back(ctrl_val);
if (condaccept && (!new_state_cond || !new_state_noncond))
new_state.clear();
if (new_state.empty()) {
if (!accept)
dnode.reject.push_back(ctrl_val);
} else {
usortint(new_state);
dnode.edges.push_back(make_pair(new_state, ctrl_val));
create_dnode(new_state, firstmatch);
create_dnode(new_state, firstmatch, condaccept);
}
}
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)
{
log_assert(!materialized);
@ -499,7 +649,7 @@ struct SvaFsm
// Create DFSM
create_dnode(vector<int>{startNode}, true);
create_dnode(vector<int>{startNode}, true, false);
dnodes.sort();
// Create DFSM Circuit
@ -519,20 +669,29 @@ struct SvaFsm
for (auto &it : dnodes)
{
SvaDFsmNode &dnode = it.second;
dict<vector<int>, vector<Const>> edge_cond;
for (auto &edge : dnode.edges) {
SigBit trig = module->Eq(NEW_ID, {dnode.ctrl, dnode.statesig}, {edge.second, State::S1});
dnodes.at(edge.first).nextstate.append(trig);
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)
dnodes.at(it.first).nextstate.append(make_cond_eq(dnode.ctrl, value, dnode.statesig));
}
if (accept_p) {
for (auto &value : dnode.accept)
accept_sig.append(module->Eq(NEW_ID, {dnode.ctrl, dnode.statesig}, {value, State::S1}));
vector<Const> accept_cond = dnode.accept;
optimize_cond(accept_cond);
for (auto &value : accept_cond)
accept_sig.append(make_cond_eq(dnode.ctrl, value, dnode.statesig));
}
if (reject_p) {
for (auto &value : dnode.reject)
reject_sig.append(module->Eq(NEW_ID, {dnode.ctrl, dnode.statesig}, {value, State::S1}));
vector<Const> reject_cond = dnode.reject;
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 accept;
getFirstAcceptReject(nullptr, &accept);
getFirstAcceptReject(&accept, nullptr);
return accept;
}
@ -587,7 +746,7 @@ struct SvaFsm
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);
materialized = true;
@ -603,33 +762,47 @@ struct SvaFsm
// Create DFSM
create_dnode(vector<int>{startNode}, true);
create_dnode(vector<int>{startNode}, firstmatch, condaccept);
dnodes.sort();
// Create DFSM Graph
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})
output_fsm.createLink(output_start_node, it.second.outnode);
output_fsm.createLink(output_start_node, dnode.outnode);
if (output_accept_node >= 0) {
for (auto &value : it.second.accept)
output_fsm.createLink(it.second.outnode, output_accept_node, module->Eq(NEW_ID, it.second.ctrl, value));
vector<Const> accept_cond = dnode.accept;
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) {
for (auto &value : it.second.reject)
output_fsm.createLink(it.second.outnode, output_reject_node, module->Eq(NEW_ID, it.second.ctrl, value));
vector<Const> reject_cond = dnode.reject;
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 &edge : it.second.edges)
output_fsm.createEdge(it.second.outnode, dnodes.at(edge.first).outnode, module->Eq(NEW_ID, it.second.ctrl, edge.second));
SvaDFsmNode &dnode = it.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");
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) {
if (it.second != State::S1)
@ -688,6 +864,13 @@ struct SvaFsm
else
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();
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;
}