Skip to content

Commit

Permalink
btor2aiger: Add test
Browse files Browse the repository at this point in the history
Based on fifo.sby, running both with and without `btor_aig on`, as well as combined with `vcd_sim on` (after an earlier version had issues when using `vcd_sim off`).

Has both pass and fail checks, so should be able to catch any major issues, although it doesn't fully check equivalence.
  • Loading branch information
KrystalDelusion committed Apr 6, 2024
1 parent c081a8a commit f17a6e1
Showing 1 changed file with 204 additions and 0 deletions.
204 changes: 204 additions & 0 deletions tests/unsorted/btor2aig.sby
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
[tasks]
bmc
prove
prove_f: prove
prove_v: prove_f prove
bmc_b2a: bmc btor_aig
prove_b2a: prove btor_aig
prove_f_b2a: prove_f prove btor_aig
prove_v_b2a: prove_v prove_f prove btor_aig

[options]
prove:
mode prove
--

bmc:
mode bmc
--

prove_f: expect fail
prove_v: vcd_sim on
btor_aig: btor_aig on

[engines]
bmc: abc bmc3
prove: abc --keep-going pdr

[script]
prove_f: read -define NO_FULL_SKIP=1
read -formal fifo.sv
prep -top fifo

[file fifo.sv]
// address generator/counter
module addr_gen
#( parameter MAX_DATA=16
) ( input en, clk, rst,
output reg [3:0] addr
);
initial addr <= 0;

// async reset
// increment address when enabled
always @(posedge clk or posedge rst)
if (rst)
addr <= 0;
else if (en) begin
if (addr == MAX_DATA-1)
addr <= 0;
else
addr <= addr + 1;
end
endmodule

// Define our top level fifo entity
module fifo
#( parameter MAX_DATA=16
) ( input wen, ren, clk, rst,
input [7:0] wdata,
output [7:0] rdata,
output [4:0] count,
output full, empty
);
wire wskip, rskip;
reg [4:0] data_count;

// fifo storage
// async read, sync write
wire [3:0] waddr, raddr;
reg [7:0] data [MAX_DATA-1:0];
always @(posedge clk)
if (wen)
data[waddr] <= wdata;
assign rdata = data[raddr];
// end storage

// addr_gen for both write and read addresses
addr_gen #(.MAX_DATA(MAX_DATA))
fifo_writer (
.en (wen || wskip),
.clk (clk ),
.rst (rst),
.addr (waddr)
);

addr_gen #(.MAX_DATA(MAX_DATA))
fifo_reader (
.en (ren || rskip),
.clk (clk ),
.rst (rst),
.addr (raddr)
);

// status signals
initial data_count <= 0;

always @(posedge clk or posedge rst) begin
if (rst)
data_count <= 0;
else if (wen && !ren && data_count < MAX_DATA)
data_count <= data_count + 1;
else if (ren && !wen && data_count > 0)
data_count <= data_count - 1;
end

assign full = data_count == MAX_DATA;
assign empty = (data_count == 0) && ~rst;
assign count = data_count;

// overflow protection
`ifndef NO_FULL_SKIP
// write while full => overwrite oldest data, move read pointer
assign rskip = wen && !ren && data_count >= MAX_DATA;
// read while empty => read invalid data, keep write pointer in sync
assign wskip = ren && !wen && data_count == 0;
`else
assign rskip = 0;
assign wskip = 0;
`endif // NO_FULL_SKIP

`ifdef FORMAL
// observers
wire [4:0] addr_diff;
assign addr_diff = waddr >= raddr
? waddr - raddr
: waddr + MAX_DATA - raddr;

// tests
always @(posedge clk) begin
if (~rst) begin
// waddr and raddr can only be non zero if reset is low
w_nreset: cover (waddr || raddr);

// count never more than max
a_oflow: assert (count <= MAX_DATA);
a_oflow2: assert (waddr < MAX_DATA);

// count should be equal to the difference between writer and reader address
a_count_diff: assert (count == addr_diff
|| count == MAX_DATA && addr_diff == 0);

// count should only be able to increase or decrease by 1
a_counts: assert (count == 0
|| count == $past(count)
|| count == $past(count) + 1
|| count == $past(count) - 1);

// read/write addresses can only increase (or stay the same)
a_raddr: assert (raddr == 0
|| raddr == $past(raddr)
|| raddr == $past(raddr + 1));
a_waddr: assert (waddr == 0
|| waddr == $past(waddr)
|| waddr == $past(waddr + 1));

// full and empty work as expected
a_full: assert (!full || count == MAX_DATA);
w_full: cover (wen && !ren && count == MAX_DATA-1);
a_empty: assert (!empty || count == 0);
w_empty: cover (ren && !wen && count == 1);

// reading/writing non zero values
w_nzero_write: cover (wen && wdata);
w_nzero_read: cover (ren && rdata);
end else begin
// waddr and raddr are zero while reset is high
a_reset: assert (!waddr && !raddr);
w_reset: cover (rst);

// outputs are zero while reset is high
a_zero_out: assert (!empty && !full && !count);
end
end

// if we have verific we can also do the following additional tests
// read/write enables enable
ap_raddr2: assert property (@(posedge clk) disable iff (rst) ren |=> $changed(raddr));
ap_waddr2: assert property (@(posedge clk) disable iff (rst) wen |=> $changed(waddr));

// read/write needs enable UNLESS full/empty
ap_raddr3: assert property (@(posedge clk) disable iff (rst) !ren && !full |=> $stable(raddr));
ap_waddr3: assert property (@(posedge clk) disable iff (rst) !wen && !empty |=> $stable(waddr));

// use block formatting for w_underfill so it's easier to describe in docs
// and is more readily comparable with the non SVA implementation
property write_skip;
@(posedge clk) disable iff (rst)
!wen |=> $changed(waddr);
endproperty
w_underfill: cover property (write_skip);

// look for an overfill where the value in memory changes
// the change in data makes certain that the value is overriden
let d_change = (wdata != rdata);
property read_skip;
@(posedge clk) disable iff (rst)
!ren && d_change |=> $changed(raddr);
endproperty
w_overfill: cover property (read_skip);

`endif // FORMAL

endmodule

0 comments on commit f17a6e1

Please sign in to comment.