Skip to content

Commit dfca8ce

Browse files
authored
Merge pull request #619 from diffblue/countones1
SystemVerilog: $countones
2 parents 4b8a2d3 + 27a1f5d commit dfca8ce

File tree

9 files changed

+106
-3
lines changed

9 files changed

+106
-3
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
countones1.sv
3+
--module main --bound 0
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module main;
2+
3+
always assert ($countones('b10101)==3);
4+
5+
// $countones yields an elaboration-time constant
6+
parameter P = 123;
7+
parameter Q = $countones(P);
8+
9+
endmodule
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
countones2.sv
3+
--bound 50
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module gray_counter#(N = 4) (input clk, output [N-1:0] out);
2+
3+
reg [N-1:0] state = 0;
4+
assign out = {state[N-1], state[N-1:1] ^ state[N-2:0]};
5+
6+
always_ff @(posedge clk) state++;
7+
8+
// two successive values differ in one bit exactly
9+
p0: assert property (@(posedge clk)
10+
##1 $countones($past(out) ^ out) == 1);
11+
12+
endmodule

src/verilog/verilog_synthesis.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ exprt verilog_synthesist::synth_expr(exprt expr, symbol_statet symbol_state)
235235
}
236236
else if(expr.id()==ID_function_call)
237237
{
238-
return expand_function_call(to_function_call_expr(expr));
238+
return expand_function_call(to_function_call_expr(expr), symbol_state);
239239
}
240240
else if(expr.id()==ID_hierarchical_identifier)
241241
{
@@ -461,7 +461,9 @@ Function: verilog_synthesist::expand_function_call
461461
462462
\*******************************************************************/
463463

464-
exprt verilog_synthesist::expand_function_call(const function_call_exprt &call)
464+
exprt verilog_synthesist::expand_function_call(
465+
const function_call_exprt &call,
466+
symbol_statet symbol_state)
465467
{
466468
// Is it a 'system function call'?
467469
if(call.is_system_function_call())
@@ -511,6 +513,14 @@ exprt verilog_synthesist::expand_function_call(const function_call_exprt &call)
511513
else
512514
DATA_INVARIANT(false, "all cases covered");
513515
}
516+
else if(identifier == "$countones")
517+
{
518+
// lower to popcount
519+
DATA_INVARIANT(
520+
call.arguments().size() == 1, "$countones must have one argument");
521+
auto what = synth_expr(call.arguments()[0], symbol_state); // rec. call
522+
return popcount_exprt{what, call.type()};
523+
}
514524
else
515525
{
516526
// Attempt to constant fold.

src/verilog/verilog_synthesis_class.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,8 @@ class verilog_synthesist:
304304
class hierarchical_identifier_exprt &expr,
305305
symbol_statet symbol_state);
306306

307-
exprt expand_function_call(const class function_call_exprt &call);
307+
exprt
308+
expand_function_call(const class function_call_exprt &call, symbol_statet);
308309

309310
typedef std::map<irep_idt, exprt> replace_mapt;
310311

src/verilog/verilog_typecheck_expr.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,33 @@ constant_exprt verilog_typecheck_exprt::right(const exprt &expr)
561561

562562
/*******************************************************************\
563563
564+
Function: verilog_typecheck_exprt::countones
565+
566+
Inputs:
567+
568+
Outputs:
569+
570+
Purpose:
571+
572+
\*******************************************************************/
573+
574+
constant_exprt verilog_typecheck_exprt::countones(const constant_exprt &expr)
575+
{
576+
// lower to popcount and try simplifier
577+
auto simplified =
578+
simplify_expr(popcount_exprt{expr, verilog_int_typet{}.lower()}, ns);
579+
580+
if(!simplified.is_constant())
581+
{
582+
throw errort{}.with_location(expr.source_location())
583+
<< "failed to simplify constant $countones";
584+
}
585+
else
586+
return to_constant_expr(simplified);
587+
}
588+
589+
/*******************************************************************\
590+
564591
Function: verilog_typecheck_exprt::increment
565592
566593
Inputs:
@@ -755,6 +782,19 @@ exprt verilog_typecheck_exprt::convert_system_function(
755782

756783
return std::move(expr);
757784
}
785+
else if(identifier == "$countones") // SystemVerilog
786+
{
787+
if(arguments.size() != 1)
788+
{
789+
throw errort().with_location(expr.source_location())
790+
<< "$countones takes one argument";
791+
}
792+
793+
// The return type is 'int'
794+
expr.type() = verilog_int_typet{}.lower();
795+
796+
return std::move(expr);
797+
}
758798
else if(identifier=="$onehot") // SystemVerilog
759799
{
760800
if(arguments.size()!=1)
@@ -1586,6 +1626,17 @@ exprt verilog_typecheck_exprt::elaborate_constant_system_function_call(
15861626
DATA_INVARIANT(arguments.size() == 1, "$increment has one argument");
15871627
return increment(arguments[0]);
15881628
}
1629+
else if(identifier == "$countones")
1630+
{
1631+
DATA_INVARIANT(arguments.size() == 1, "$countones has one argument");
1632+
1633+
auto op = elaborate_constant_expression(arguments[0]);
1634+
1635+
if(!op.is_constant())
1636+
return std::move(expr); // give up
1637+
1638+
return countones(to_constant_expr(op));
1639+
}
15891640
else if(identifier == "$clog2")
15901641
{
15911642
// the ceiling of the log with base 2 of the argument

src/verilog/verilog_typecheck_expr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class verilog_typecheck_exprt:public verilog_typecheck_baset
137137
// system functions
138138
exprt bits(const exprt &);
139139
std::optional<mp_integer> bits_rec(const typet &) const;
140+
constant_exprt countones(const constant_exprt &);
140141
constant_exprt left(const exprt &);
141142
constant_exprt right(const exprt &);
142143
constant_exprt low(const exprt &);

src/verilog/verilog_types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ class verilog_int_typet : public typet
218218
{
219219
return 32;
220220
}
221+
222+
typet lower() const
223+
{
224+
return signedbv_typet{width()};
225+
}
221226
};
222227

223228
/// 2-state data type, 64-bit signed integer

0 commit comments

Comments
 (0)