2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 // SVA Properties Simplified Syntax:
29 // if (expr) prop [else prop]
33 // accept_on (expr) prop
34 // reject_on (expr) prop
44 // expr throughout seq
54 #include "kernel/yosys.h"
55 #include "frontends/verific/verific.h"
59 #ifdef VERIFIC_NAMESPACE
60 using namespace Verific
;
65 pool
<int> verific_sva_prims
= {
66 // Copy&paste from Verific 3.16_484_32_170630 Netlist.h
67 PRIM_SVA_IMMEDIATE_ASSERT
, PRIM_SVA_ASSERT
, PRIM_SVA_COVER
, PRIM_SVA_ASSUME
,
68 PRIM_SVA_EXPECT
, PRIM_SVA_POSEDGE
, PRIM_SVA_NOT
, PRIM_SVA_FIRST_MATCH
,
69 PRIM_SVA_ENDED
, PRIM_SVA_MATCHED
, PRIM_SVA_CONSECUTIVE_REPEAT
,
70 PRIM_SVA_NON_CONSECUTIVE_REPEAT
, PRIM_SVA_GOTO_REPEAT
,
71 PRIM_SVA_MATCH_ITEM_TRIGGER
, PRIM_SVA_AND
, PRIM_SVA_OR
, PRIM_SVA_SEQ_AND
,
72 PRIM_SVA_SEQ_OR
, PRIM_SVA_EVENT_OR
, PRIM_SVA_OVERLAPPED_IMPLICATION
,
73 PRIM_SVA_NON_OVERLAPPED_IMPLICATION
, PRIM_SVA_OVERLAPPED_FOLLOWED_BY
,
74 PRIM_SVA_NON_OVERLAPPED_FOLLOWED_BY
, PRIM_SVA_INTERSECT
, PRIM_SVA_THROUGHOUT
,
75 PRIM_SVA_WITHIN
, PRIM_SVA_AT
, PRIM_SVA_DISABLE_IFF
, PRIM_SVA_SAMPLED
,
76 PRIM_SVA_ROSE
, PRIM_SVA_FELL
, PRIM_SVA_STABLE
, PRIM_SVA_PAST
,
77 PRIM_SVA_MATCH_ITEM_ASSIGN
, PRIM_SVA_SEQ_CONCAT
, PRIM_SVA_IF
,
78 PRIM_SVA_RESTRICT
, PRIM_SVA_TRIGGERED
, PRIM_SVA_STRONG
, PRIM_SVA_WEAK
,
79 PRIM_SVA_NEXTTIME
, PRIM_SVA_S_NEXTTIME
, PRIM_SVA_ALWAYS
, PRIM_SVA_S_ALWAYS
,
80 PRIM_SVA_S_EVENTUALLY
, PRIM_SVA_EVENTUALLY
, PRIM_SVA_UNTIL
, PRIM_SVA_S_UNTIL
,
81 PRIM_SVA_UNTIL_WITH
, PRIM_SVA_S_UNTIL_WITH
, PRIM_SVA_IMPLIES
, PRIM_SVA_IFF
,
82 PRIM_SVA_ACCEPT_ON
, PRIM_SVA_REJECT_ON
, PRIM_SVA_SYNC_ACCEPT_ON
,
83 PRIM_SVA_SYNC_REJECT_ON
, PRIM_SVA_GLOBAL_CLOCKING_DEF
,
84 PRIM_SVA_GLOBAL_CLOCKING_REF
, PRIM_SVA_IMMEDIATE_ASSUME
,
85 PRIM_SVA_IMMEDIATE_COVER
, OPER_SVA_SAMPLED
, OPER_SVA_STABLE
88 struct VerificSvaImporter
90 VerificImporter
*importer
= nullptr;
91 Module
*module
= nullptr;
93 Netlist
*netlist
= nullptr;
94 Instance
*root
= nullptr;
96 SigBit clock
= State::Sx
;
97 bool clock_posedge
= false;
99 SigBit disable_iff
= State::S0
;
101 bool mode_assert
= false;
102 bool mode_assume
= false;
103 bool mode_cover
= false;
104 bool eventually
= false;
105 bool did_something
= false;
107 Instance
*net_to_ast_driver(Net
*n
)
112 if (n
->IsMultipleDriven())
115 Instance
*inst
= n
->Driver();
120 if (!verific_sva_prims
.count(inst
->Type()))
123 if (inst
->Type() == PRIM_SVA_ROSE
|| inst
->Type() == PRIM_SVA_FELL
||
124 inst
->Type() == PRIM_SVA_STABLE
|| inst
->Type() == OPER_SVA_STABLE
|| inst
->Type() == PRIM_SVA_PAST
)
130 Instance
*get_ast_input(Instance
*inst
) { return net_to_ast_driver(inst
->GetInput()); }
131 Instance
*get_ast_input1(Instance
*inst
) { return net_to_ast_driver(inst
->GetInput1()); }
132 Instance
*get_ast_input2(Instance
*inst
) { return net_to_ast_driver(inst
->GetInput2()); }
133 Instance
*get_ast_input3(Instance
*inst
) { return net_to_ast_driver(inst
->GetInput3()); }
134 Instance
*get_ast_control(Instance
*inst
) { return net_to_ast_driver(inst
->GetControl()); }
136 // ----------------------------------------------------------
141 bool flag_linear
= true;
144 std::map
<Instance
*, svatype_t
> svatype_cache
;
146 void svatype_visit_child(svatype_t
&entry
, Instance
*inst
)
151 const svatype_t
&child_entry
= svatype(inst
);
152 entry
.flag_linear
&= child_entry
.flag_linear
;
155 const svatype_t
&svatype(Instance
*inst
)
157 if (svatype_cache
.count(inst
) != 0)
158 return svatype_cache
.at(inst
);
160 svatype_t
&entry
= svatype_cache
[inst
];
165 if (inst
->Type() == PRIM_SVA_SEQ_CONCAT
|| inst
->Type() == PRIM_SVA_CONSECUTIVE_REPEAT
)
167 const char *sva_low_s
= inst
->GetAttValue("sva:low");
168 const char *sva_high_s
= inst
->GetAttValue("sva:high");
170 int sva_low
= atoi(sva_low_s
);
171 int sva_high
= atoi(sva_high_s
);
172 bool sva_inf
= !strcmp(sva_high_s
, "$");
174 if (sva_inf
|| sva_low
!= sva_high
)
175 entry
.flag_linear
= false;
178 svatype_visit_child(entry
, get_ast_input(inst
));
179 svatype_visit_child(entry
, get_ast_input1(inst
));
180 svatype_visit_child(entry
, get_ast_input2(inst
));
181 svatype_visit_child(entry
, get_ast_input3(inst
));
182 svatype_visit_child(entry
, get_ast_control(inst
));
187 // ----------------------------------------------------------
190 Net
*rewrite_input(Instance
*inst
) { return rewrite(get_ast_input(inst
), inst
->GetInput()); }
191 Net
*rewrite_input1(Instance
*inst
) { return rewrite(get_ast_input1(inst
), inst
->GetInput1()); }
192 Net
*rewrite_input2(Instance
*inst
) { return rewrite(get_ast_input2(inst
), inst
->GetInput2()); }
193 Net
*rewrite_input3(Instance
*inst
) { return rewrite(get_ast_input3(inst
), inst
->GetInput3()); }
194 Net
*rewrite_control(Instance
*inst
) { return rewrite(get_ast_control(inst
), inst
->GetControl()); }
196 Net
*rewrite(Instance
*inst
, Net
*default_net
= nullptr)
201 if (inst
->Type() == PRIM_SVA_ASSERT
|| inst
->Type() == PRIM_SVA_COVER
|| inst
->Type() == PRIM_SVA_ASSUME
||
202 inst
->Type() == PRIM_SVA_IMMEDIATE_ASSERT
|| inst
->Type() == PRIM_SVA_IMMEDIATE_COVER
|| inst
->Type() == PRIM_SVA_IMMEDIATE_ASSUME
) {
203 Net
*new_net
= rewrite(get_ast_input(inst
));
205 inst
->Disconnect(inst
->View()->GetInput());
206 inst
->Connect(inst
->View()->GetInput(), new_net
);
211 if (inst
->Type() == PRIM_SVA_AT
|| inst
->Type() == PRIM_SVA_DISABLE_IFF
) {
212 Net
*new_net
= rewrite(get_ast_input2(inst
));
214 inst
->Disconnect(inst
->View()->GetInput2());
215 inst
->Connect(inst
->View()->GetInput2(), new_net
);
220 if (inst
->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION
)
223 did_something
= true;
224 Net
*new_in1
= rewrite_input1(inst
);
225 Net
*new_in2
= rewrite_input2(inst
);
226 return netlist
->SvaBinary(PRIM_SVA_SEQ_CONCAT
, new_in1
, new_in2
, inst
->Linefile());
231 if (inst
->Type() == PRIM_SVA_NOT
)
233 if (mode_assert
|| mode_assume
) {
234 did_something
= true;
235 Net
*new_in
= rewrite_input(inst
);
236 Net
*net_zero
= netlist
->Gnd(inst
->Linefile());
237 return netlist
->SvaBinary(PRIM_SVA_OVERLAPPED_IMPLICATION
, new_in
, net_zero
, inst
->Linefile());
247 netlist
= root
->Owner();
249 did_something
= false;
251 } while (did_something
);
254 // ----------------------------------------------------------
257 vector
<SigBit
> sva_until_list_inclusive
;
258 vector
<SigBit
> sva_until_list_exclusive
;
259 vector
<vector
<SigBit
>*> sva_sequence_alive_list
;
263 SigBit sig_a
= State::S1
;
264 SigBit sig_en
= State::S1
;
267 void sequence_cond(sequence_t
&seq
, SigBit cond
)
269 seq
.sig_a
= module
->And(NEW_ID
, seq
.sig_a
, cond
);
272 void sequence_ff(sequence_t
&seq
)
274 if (disable_iff
!= State::S0
)
275 seq
.sig_en
= module
->Mux(NEW_ID
, seq
.sig_en
, State::S0
, disable_iff
);
277 for (auto &expr
: sva_until_list_exclusive
)
278 seq
.sig_a
= module
->LogicAnd(NEW_ID
, seq
.sig_a
, expr
);
280 Wire
*sig_a_q
= module
->addWire(NEW_ID
);
281 sig_a_q
->attributes
["\\init"] = Const(0, 1);
283 Wire
*sig_en_q
= module
->addWire(NEW_ID
);
284 sig_en_q
->attributes
["\\init"] = Const(0, 1);
286 for (auto list
: sva_sequence_alive_list
)
287 list
->push_back(module
->LogicAnd(NEW_ID
, seq
.sig_a
, seq
.sig_en
));
289 module
->addDff(NEW_ID
, clock
, seq
.sig_a
, sig_a_q
, clock_posedge
);
290 module
->addDff(NEW_ID
, clock
, seq
.sig_en
, sig_en_q
, clock_posedge
);
296 seq
.sig_en
= sig_en_q
;
298 for (auto &expr
: sva_until_list_inclusive
)
299 seq
.sig_a
= module
->LogicAnd(NEW_ID
, seq
.sig_a
, expr
);
302 void combine_seq(sequence_t
&seq
, const sequence_t
&other_seq
)
304 if (seq
.length
!= other_seq
.length
)
307 SigBit filtered_a
= module
->LogicAnd(NEW_ID
, seq
.sig_a
, seq
.sig_en
);
308 SigBit other_filtered_a
= module
->LogicAnd(NEW_ID
, other_seq
.sig_a
, other_seq
.sig_en
);
310 seq
.sig_a
= module
->LogicOr(NEW_ID
, filtered_a
, other_filtered_a
);
311 seq
.sig_en
= module
->LogicOr(NEW_ID
, seq
.sig_en
, other_seq
.sig_en
);
314 void combine_seq(sequence_t
&seq
, SigBit other_a
, SigBit other_en
)
316 SigBit filtered_a
= module
->LogicAnd(NEW_ID
, seq
.sig_a
, seq
.sig_en
);
317 SigBit other_filtered_a
= module
->LogicAnd(NEW_ID
, other_a
, other_en
);
320 seq
.sig_a
= module
->LogicOr(NEW_ID
, filtered_a
, other_filtered_a
);
321 seq
.sig_en
= module
->LogicOr(NEW_ID
, seq
.sig_en
, other_en
);
324 SigBit
make_temporal_one_hot(SigBit enable
= State::S1
, SigBit
*latched
= nullptr)
326 Wire
*state
= module
->addWire(NEW_ID
);
327 state
->attributes
["\\init"] = State::S0
;
329 SigBit any
= module
->Anyseq(NEW_ID
);
330 if (enable
!= State::S1
)
331 any
= module
->LogicAnd(NEW_ID
, any
, enable
);
333 SigBit next_state
= module
->LogicOr(NEW_ID
, state
, any
);
334 module
->addDff(NEW_ID
, clock
, next_state
, state
, clock_posedge
);
336 if (latched
!= nullptr)
339 SigBit not_state
= module
->LogicNot(NEW_ID
, state
);
340 return module
->LogicAnd(NEW_ID
, next_state
, not_state
);
343 SigBit
make_permanent_latch(SigBit enable
, bool async
= false)
345 Wire
*state
= module
->addWire(NEW_ID
);
346 state
->attributes
["\\init"] = State::S0
;
348 SigBit next_state
= module
->LogicOr(NEW_ID
, state
, enable
);
349 module
->addDff(NEW_ID
, clock
, next_state
, state
, clock_posedge
);
351 return async
? next_state
: state
;
354 void parse_sequence(sequence_t
&seq
, Net
*n
)
356 Instance
*inst
= net_to_ast_driver(n
);
358 // Regular expression
360 if (inst
== nullptr) {
361 sequence_cond(seq
, importer
->net_map_at(n
));
367 if (inst
->Type() == PRIM_SVA_OVERLAPPED_IMPLICATION
||
368 inst
->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION
)
370 Instance
*consequent
= get_ast_input2(inst
);
371 bool linear_consequent
= svatype(consequent
).flag_linear
;
373 parse_sequence(seq
, inst
->GetInput1());
374 seq
.sig_en
= module
->And(NEW_ID
, seq
.sig_en
, seq
.sig_a
);
376 if (inst
->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION
)
379 if (!linear_consequent
&& mode_assume
)
380 log_error("Non-linear consequent is currently not supported in SVA assumptions.\n");
382 if (linear_consequent
)
384 parse_sequence(seq
, inst
->GetInput2());
389 seq
.sig_en
= make_temporal_one_hot(seq
.sig_en
, &activated
);
391 SigBit pass_latch_en
= module
->addWire(NEW_ID
);
392 SigBit pass_latch
= make_permanent_latch(pass_latch_en
, true);
394 vector
<SigBit
> alive_list
;
395 sva_sequence_alive_list
.push_back(&alive_list
);
396 parse_sequence(seq
, inst
->GetInput2());
397 sva_sequence_alive_list
.pop_back();
399 module
->addLogicAnd(NEW_ID
, seq
.sig_a
, seq
.sig_en
, pass_latch_en
);
400 alive_list
.push_back(pass_latch
);
403 seq
.sig_a
= module
->ReduceOr(NEW_ID
, SigSpec(alive_list
));
404 seq
.sig_en
= module
->ReduceOr(NEW_ID
, activated
);
410 if (inst
->Type() == PRIM_SVA_SEQ_CONCAT
)
412 const char *sva_low_s
= inst
->GetAttValue("sva:low");
413 const char *sva_high_s
= inst
->GetAttValue("sva:high");
415 int sva_low
= atoi(sva_low_s
);
416 int sva_high
= atoi(sva_high_s
);
417 bool sva_inf
= !strcmp(sva_high_s
, "$");
419 parse_sequence(seq
, inst
->GetInput1());
421 for (int i
= 0; i
< sva_low
; i
++)
426 SigBit latched_a
= module
->addWire(NEW_ID
);
427 SigBit latched_en
= module
->addWire(NEW_ID
);
428 combine_seq(seq
, latched_a
, latched_en
);
430 sequence_t seq_latched
= seq
;
431 sequence_ff(seq_latched
);
432 module
->connect(latched_a
, seq_latched
.sig_a
);
433 module
->connect(latched_en
, seq_latched
.sig_en
);
437 for (int i
= sva_low
; i
< sva_high
; i
++)
439 sequence_t last_seq
= seq
;
441 combine_seq(seq
, last_seq
);
445 parse_sequence(seq
, inst
->GetInput2());
449 if (inst
->Type() == PRIM_SVA_CONSECUTIVE_REPEAT
)
451 const char *sva_low_s
= inst
->GetAttValue("sva:low");
452 const char *sva_high_s
= inst
->GetAttValue("sva:high");
454 int sva_low
= atoi(sva_low_s
);
455 int sva_high
= atoi(sva_high_s
);
456 bool sva_inf
= !strcmp(sva_high_s
, "$");
458 parse_sequence(seq
, inst
->GetInput());
460 for (int i
= 1; i
< sva_low
; i
++) {
462 parse_sequence(seq
, inst
->GetInput());
467 SigBit latched_a
= module
->addWire(NEW_ID
);
468 SigBit latched_en
= module
->addWire(NEW_ID
);
469 combine_seq(seq
, latched_a
, latched_en
);
471 sequence_t seq_latched
= seq
;
472 sequence_ff(seq_latched
);
473 parse_sequence(seq_latched
, inst
->GetInput());
474 module
->connect(latched_a
, seq_latched
.sig_a
);
475 module
->connect(latched_en
, seq_latched
.sig_en
);
479 for (int i
= sva_low
; i
< sva_high
; i
++)
481 sequence_t last_seq
= seq
;
483 parse_sequence(seq
, inst
->GetInput());
484 combine_seq(seq
, last_seq
);
491 if (inst
->Type() == PRIM_SVA_THROUGHOUT
|| inst
->Type() == PRIM_SVA_UNTIL
|| inst
->Type() == PRIM_SVA_S_UNTIL
||
492 inst
->Type() == PRIM_SVA_UNTIL_WITH
|| inst
->Type() == PRIM_SVA_S_UNTIL_WITH
)
494 bool flag_with
= inst
->Type() == PRIM_SVA_THROUGHOUT
|| inst
->Type() == PRIM_SVA_UNTIL_WITH
|| inst
->Type() == PRIM_SVA_S_UNTIL_WITH
;
496 if (get_ast_input1(inst
) != nullptr)
497 log_error("Currently only simple expression properties are supported as first operand to SVA_UNTIL.\n");
499 SigBit expr
= importer
->net_map_at(inst
->GetInput1());
503 seq
.sig_a
= module
->LogicAnd(NEW_ID
, seq
.sig_a
, expr
);
504 sva_until_list_inclusive
.push_back(expr
);
505 parse_sequence(seq
, inst
->GetInput2());
506 sva_until_list_inclusive
.pop_back();
510 sva_until_list_exclusive
.push_back(expr
);
511 parse_sequence(seq
, inst
->GetInput2());
512 sva_until_list_exclusive
.pop_back();
518 // Handle unsupported primitives
520 if (!importer
->mode_keep
)
521 log_error("Verific SVA primitive %s (%s) is currently unsupported in this context.\n", inst
->View()->Owner()->Name(), inst
->Name());
522 log_warning("Verific SVA primitive %s (%s) is currently unsupported in this context.\n", inst
->View()->Owner()->Name(), inst
->Name());
527 module
= importer
->module
;
528 netlist
= root
->Owner();
530 RTLIL::IdString root_name
= module
->uniquify(importer
->mode_names
|| root
->IsUserDeclared() ? RTLIL::escape_id(root
->Name()) : NEW_ID
);
532 // parse SVA property clock event
534 Instance
*at_node
= get_ast_input(root
);
536 // asynchronous immediate assertion/assumption/cover
537 if (at_node
== nullptr && (root
->Type() == PRIM_SVA_IMMEDIATE_ASSERT
||
538 root
->Type() == PRIM_SVA_IMMEDIATE_COVER
|| root
->Type() == PRIM_SVA_IMMEDIATE_ASSUME
))
540 SigSpec sig_a
= importer
->net_map_at(root
->GetInput());
541 RTLIL::Cell
*c
= nullptr;
544 if (mode_assert
) c
= module
->addLive(root_name
, sig_a
, State::S1
);
545 if (mode_assume
) c
= module
->addFair(root_name
, sig_a
, State::S1
);
547 if (mode_assert
) c
= module
->addAssert(root_name
, sig_a
, State::S1
);
548 if (mode_assume
) c
= module
->addAssume(root_name
, sig_a
, State::S1
);
549 if (mode_cover
) c
= module
->addCover(root_name
, sig_a
, State::S1
);
552 importer
->import_attributes(c
->attributes
, root
);
556 log_assert(at_node
&& at_node
->Type() == PRIM_SVA_AT
);
558 VerificClockEdge
clock_edge(importer
, get_ast_input1(at_node
));
559 clock
= clock_edge
.clock_sig
;
560 clock_posedge
= clock_edge
.posedge
;
562 // parse disable_iff expression
564 Net
*sequence_net
= at_node
->GetInput2();
568 Instance
*sequence_node
= net_to_ast_driver(sequence_net
);
570 if (sequence_node
&& sequence_node
->Type() == PRIM_SVA_S_EVENTUALLY
) {
572 sequence_net
= sequence_node
->GetInput();
576 if (sequence_node
&& sequence_node
->Type() == PRIM_SVA_DISABLE_IFF
) {
577 disable_iff
= importer
->net_map_at(sequence_node
->GetInput1());
578 sequence_net
= sequence_node
->GetInput2();
585 // parse SVA sequence into trigger signal
588 parse_sequence(seq
, sequence_net
);
591 // generate assert/assume/cover cell
593 RTLIL::Cell
*c
= nullptr;
596 if (mode_assert
) c
= module
->addLive(root_name
, seq
.sig_a
, seq
.sig_en
);
597 if (mode_assume
) c
= module
->addFair(root_name
, seq
.sig_a
, seq
.sig_en
);
599 if (mode_assert
) c
= module
->addAssert(root_name
, seq
.sig_a
, seq
.sig_en
);
600 if (mode_assume
) c
= module
->addAssume(root_name
, seq
.sig_a
, seq
.sig_en
);
601 if (mode_cover
) c
= module
->addCover(root_name
, seq
.sig_a
, seq
.sig_en
);
604 importer
->import_attributes(c
->attributes
, root
);
608 void svapp_assert(Instance
*inst
)
610 VerificSvaImporter worker
;
612 worker
.mode_assert
= true;
616 void svapp_assume(Instance
*inst
)
618 VerificSvaImporter worker
;
620 worker
.mode_assume
= true;
624 void svapp_cover(Instance
*inst
)
626 VerificSvaImporter worker
;
628 worker
.mode_cover
= true;
632 void import_sva_assert(VerificImporter
*importer
, Instance
*inst
)
634 VerificSvaImporter worker
;
635 worker
.importer
= importer
;
637 worker
.mode_assert
= true;
641 void import_sva_assume(VerificImporter
*importer
, Instance
*inst
)
643 VerificSvaImporter worker
;
644 worker
.importer
= importer
;
646 worker
.mode_assume
= true;
650 void import_sva_cover(VerificImporter
*importer
, Instance
*inst
)
652 VerificSvaImporter worker
;
653 worker
.importer
= importer
;
655 worker
.mode_cover
= true;