system verilog assertion trigger==1 4 cycles before signal asserted - system-verilog

How would I write SVA that checks that if sig goes high trigger was high 4 cycles before trigger [*4] |-> signal
is not good enough because it does not check that signal didn't go high for 3 cycles. Should I use $past how ??

This would check that on a rising edge of sig, trigger was high 4 clk cycles ago:
assert_name: assert property (
#(posedge clk) (
($rose(sig) -> $past(trigger,4))
)
);

There's nothing stopping you writing a small piece of synthesisable RTL which counts how many cycles trigger has been high.
always #(posedge clk) begin
if (trigger) begin
triggerCount := triggerCount + 1;
end else begin
triggerCount := 0;
end
end
assert_name: assert property (
#(posedge clk) (
($rose(sig) -> triggerCount == 4)
)
);

Related

How to make 4 bit ring counter with 4 flip flops?

I have this 4 bit ring counter that I'm trying to make, and I feel like I'm so close, but I can't figure out how to make one input depend on the previous state's output. Here's what I have:
`default_nettype none
// Empty top module
module top (
// I/O ports
input logic hz100, reset,
input logic [20:0] pb,
output logic [7:0] left, right
);
// Your code goes here...
q[3:0];
assign q[3:0] = right[3:0];
hc74_set setFF(.c(pb[0]), .d(pb[1]), .q(right[0]), .sn(pb[16]));
hc74_reset resetFF1(.c(pb[0]), .d(pb[1]), .q0(right[1]), .rn(pb[16]));
hc74_reset resetFF2(.c(pb[0]), .d(pb[1]), .q1(right[2]), .rn(pb[16]));
hc74_reset resetFF3(.c(pb[0]), .d(pb[1]), .q2(right[3]), .rn(pb[16]));
endmodule
// Add more modules down here...
// This is a single D flip-flop with an active-low asynchronous set (preset).
// It has no asynchronous reset because the simulator does not allow it.
// Other than the lack of a reset, it is half of a 74HC74 chip.
module hc74_set(input logic d, c, sn,
output logic q, qn);
assign qn = ~q;
always_ff #(posedge c, negedge sn)
if (sn == 1'b0)
q <= 1'b1;
else
q <= d;
endmodule
// This is a single D flip-flop with an active-low asynchronous reset (clear).
// It has no asynchronous set because the simulator does not allow it.
// Other than the lack of a set, it is half of a 74HC74 chip.
module hc74_reset(input logic d, c, rn,
output logic q, qn);
assign qn = ~q;
always_ff #(posedge c, negedge rn)
if (rn == 1'b0)
q <= 1'b0;
else
q <= d;
endmodule
This is on an FPGA simulator, which is why there are a few things like pb (these are push buttons) and left, right outputs which are sets of 8 LEDs each.
Let's first make sure we are on the same page
Based on wikipedia description of a ring counter
This could be implemented as follows:
module top (
// I/O ports
input logic reset_n,
input logic clk,
output logic [3:0] ring
);
// Your code goes here...
always #(posedge clk or negedge reset_n) begin
if(~reset_n) begin
ring = 4'b0001;
end
else begin
ring[0] <= ring[3];
ring[1] <= ring[0];
ring[2] <= ring[1];
ring[3] <= ring[2];
end
end
endmodule
The output ring is a 4-bit one hot vector, reset_n = 0 makes ring = 0001 every clock with reset_n = 1 rolls the ring to the right, [0001, 0010, 0100, 1000, 0001, ...].
But you want to use instances of the flops you defined. Notice that in an assignment a <= b, a is the output of the flop (q port), and b is the input of the flop (d port).
module top (
// I/O ports
input logic reset_n,
input logic clk,
output logic [3:0] ring
);
// Your code goes here...
hc74_set setFF(.c(clk), .d(ring[3]), .q(ring[0]), .sn(reset_n));
hc74_reset resetFF1(.c(clk), .d(ring[0]), .q0(ring[1]), .rn(reset_n));
hc74_reset resetFF2(.c(clk), .d(ring[1]), .q1(ring[2]), .rn(reset_n));
hc74_reset resetFF3(.c(clk), .d(ring[2]), .q2(ring[3]), .rn(reset_n));
endmodule
You have to connect the ports accordingly, I just used clk for the clock and reset_n for the negated reset signal.

System Verilog Assertions, SVA

Im writing assertions for a handshake protocol where there can be back to back requests and acks. Acks can come between 1 to 5 cycles after req. How can I use assertions to make sure there is 1 ack for every req while also taking glitching on req or ack into account ?
property p1:
#(posedge clk) req ##[1:5] ack ;
endproperty
property p2:
#(posedge clk) $rose(ack) |-> $past(req,5);
Im not sure if this keeps 1-to-1 mapping of req vs ack.
Can there be two requests before an ack? If not I would write :
property p_test;
#(posedge clk)
$rose(req) |=> !req[*0:$] ##0 ack;
endproperty
It works if req is pulse only
Property2 below is not in sync with property 1.
property p2: #(posedge clk) $rose(ack) |-> $past(req,5);
You are saying that ack must have had a request 5 clocks earlier. But property 1 says that req followed by ack is valid.
I think you need a id with a request that you can match when the ack happens.
sequence s_ack_check;
byte id;
(req && id == ack_id) ##[1:5](ack && ack_id == id);
endsequence
I take it you meant that there could be multiple reqs before any acks? If so, the solution needs either property variables or helper logic. Formal properties don't have memory or counters (without using variables).
Here's some code if you want to use helper logic:
Assume you allow at most 15 outstanding and it takes at most 25 clocks to get all acks:
logic [3:0] req_cnt, ack_cnt;
always # (posedge clk) if (rst) req_cnt <= 0; else req_cnt <= req_cnt + req;
always # (posedge clk) if (rst) ack_cnt <= 0; else ack_cnt <= ack_cnt + ack;
assert property (# (posedge clk) disable iff (rst) sync_accept_on(req) ##25 req_cnt == ack_cnt);
Count the requests and acks. Then assert that after 25 cycles of no req, the req_cnt == ack_cnt.
If there's never more than 1 req outstanding, the logic is much simpler. Please clarify if that is the case.

fork..join in SystemVerilog

I am trying to achieve req ##[3:5]ack using fork..join. I am able to run logic for req##[5]ack. But I am unable to run for req ##[3:5]ack.
I am trying-
wait(req)
fork:check_ack
begin
wait(ack)
$display("Ack passed");
end
begin
repeat(5)
#(posedge clk);
$display("Ack failed");
end
begin
repeat(3)
#(posedge clk);
$display("Ack failed");
end
join_any
disable check_ack;
I need to somehow continue to check after 3 cycles also.
You need to create a state bit that indicates when you are inside the range.
bit in_range;
#(posedge clk iff req);
fork
begin
in_range = 0;
#(posedge clk iff ack) if (in_range) $display("passes");
else $display("fails");
end
begin
repeat(3) #(posedge clk) ;
in_range <='1;
wait(0);
end
begin
repeat(5) #(posedge clk);
$display("fails");
end
join_any
disable fork;

using $past in cover property statement

I have the following simple code:
module past;
logic clk=0;
logic[3:0] adr=0;
// Clock Gen
initial forever #10 clk = ~clk;
initial #100 $finish;
always #(posedge clk) adr <= adr+1;
sequence DUMMY_SEQ;
#(posedge clk) 1'b1;
endsequence
cover property (#(posedge clk) DUMMY_SEQ) begin
$display("ADR %h past(ADR) %h at %0t", adr, $past(adr), $time);
end
endmodule
I would expect the $past(adr) return the value of adr in previous one clock cycle. But I got below simulation result which seemingly the $past(adr) return the value of adr in previous two clock cycle. Please notice it from line number 3.
ADR 1 past(ADR) 0 at 10
ADR 2 past(ADR) 0 at 10
ADR 3 past(ADR) 1 at 10
ADR 4 past(ADR) 2 at 10
ADR 5 past(ADR) 3 at 10
Can anybody explain why it is behaving like that?
Just to be clear, I am using $display just for illustration purpose. The actual problem is I couldn't get correct $past(adr) in cover statement.
Lets forget about the $display and do something else in cover statement. For example, by right, adr - $past(adr) should never exceed 1 as per above code. If I do something like this:
cover property (#(posedge clk) DUMMY_SEQ) begin
if ( (adr > $past(adr))
&& (adr - $past(adr)) > 1) $fatal;
end
then it should never get fatal, because adr increment by 1 at each clock cycle. However, it actually does get fatal error. This is confusing. Any explanation?
$past returns the value of an expression in a previous clock cycle.
Actually, there is difference between $display and $monitor that you have to understand.
$display displays once every time code is executed.
$monitor displays every time one of its parameters changes.
If you replace $display with $monitor then you will get your expected output.
The issue you are seeing is addr is updated before the $display statement and $past. This gives the impression that $past looks two clocks behind. To resolve this, use $sampled. See IEEE Std 1800-2012 16.9.3 Sampled value functions
cover property (#(posedge clk) DUMMY_SEQ) begin
$display("ADR %h past(ADR) %h at %0t", $sampled(adr), $past(adr), $time);
end
Output
ADR 0 past(ADR) 0 at 10
ADR 1 past(ADR) 0 at 30
ADR 2 past(ADR) 1 at 50
ADR 3 past(ADR) 2 at 70
ADR 4 past(ADR) 3 at 90
Another option is to put the display as a sequence_match_item which is best explained in IEEE Std 1800-2012 16.10 Local variables
cover property (#(posedge clk) (DUMMY_SEQ, $display("ADR %h past(ADR) %h at %0t", adr, $past(adr), $time));
For fatal and error reporting, it is better to use assert:
assert property (#(posedge clk) (adr >= $past(adr)) else $fatal;

Parallel To Serial HDL

I am making a parallel to serial converter using ring counter in verilog. The ring counter is working fine but the Parallel to serial converter is not working properly and I am getting x undefined result. I am providing the code kindly help me finding the problem.
TOP
module PtoSTOP;
reg clk,rst;
wire [3:0] myout;
wire out;
Ring a(clk,rst,myout);
parToser x(myout,clk,rst,out);
initial begin
clk=1;
rst=1;
#1 rst=0;
end
always
#2 clk=~clk;
endmodule
Parallel TO Serial Converter
module parToser(myout,clk,rst,out);
input clk,rst;
input [3:0] myout;
output reg out;
reg [2:0]i;
always #(posedge clk or posedge rst) begin
if(rst) begin
out <= 0;
i <= 0;
end
else begin
out <= myout[i];
i <= i+1;
end
end
endmodule
RingCounter
module Ring(clk,rst,myout);
input clk,rst;
output reg [3:0]myout;
always #(posedge clk or posedge rst) begin
if(rst)
myout<=1;
else
myout<=myout<<1;
end
endmodule
I think the main issue you are seeing is part of parToser.
You have reg [2:0]i; which you increment and use to address input [3:0] myout; but i can hold values 0 to 7, half of which is outside the address range of [3:0] myout. You should be seeing a simulation error about out of range addressing.
Also you have included a few flip-flops with a reset condition but not added the reset to the sensitivity list in 'parToser' & 'Ring':
always #(posedge clk)
Should be:
always #(posedge clk or posedge rst)
With out this trigger your out, i and myout variables will be x, as they have not been set to a known condition.
NB: parToser i = i+1; should be i <= i+1;