mirror of
https://github.com/YosysHQ/sby.git
synced 2025-09-02 09:40:43 +00:00
New exercise section
Worked exercise using the MAX_DATA parameter, highlighting its incompleteness. Includes completed examples in /golden subdirectory. Also some formatting changes for spacing and extra links.
This commit is contained in:
parent
7ba67ef260
commit
aab2c3c2e0
3 changed files with 279 additions and 11 deletions
32
docs/examples/fifo/golden/fifo.sby
Normal file
32
docs/examples/fifo/golden/fifo.sby
Normal file
|
@ -0,0 +1,32 @@
|
|||
[tasks]
|
||||
basic bmc
|
||||
nofullskip prove
|
||||
cover
|
||||
bigtest cover
|
||||
basic cover : default
|
||||
|
||||
[options]
|
||||
cover:
|
||||
mode cover
|
||||
--
|
||||
prove:
|
||||
mode prove
|
||||
--
|
||||
bmc:
|
||||
mode bmc
|
||||
--
|
||||
bigtest: depth 120
|
||||
~bigtest: depth 10
|
||||
|
||||
[engines]
|
||||
smtbmc boolector
|
||||
|
||||
[script]
|
||||
nofullskip: read -define NO_FULL_SKIP=1
|
||||
read -formal fifo.sv
|
||||
bigtest: hierarchy -check -top fifo -chparam MAX_DATA 100 -chparam ADDR_BITS 7
|
||||
~bigtest: hierarchy -check -top fifo -chparam MAX_DATA 5 -chparam ADDR_BITS 3
|
||||
prep -top fifo
|
||||
|
||||
[files]
|
||||
fifo.sv
|
192
docs/examples/fifo/golden/fifo.sv
Normal file
192
docs/examples/fifo/golden/fifo.sv
Normal file
|
@ -0,0 +1,192 @@
|
|||
// address generator/counter
|
||||
module addr_gen (
|
||||
input en, clk, rst_n,
|
||||
output reg [ADDR_BITS-1:0] addr
|
||||
);
|
||||
parameter MAX_DATA = 16;
|
||||
parameter ADDR_BITS = 5;
|
||||
|
||||
initial begin
|
||||
addr <= 0;
|
||||
end
|
||||
|
||||
// async reset
|
||||
// increment address when enabled
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (~rst_n)
|
||||
addr <= 0;
|
||||
else if (en)
|
||||
if (addr == MAX_DATA-1)
|
||||
addr <= 0;
|
||||
else
|
||||
addr <= addr + 1;
|
||||
end
|
||||
endmodule
|
||||
|
||||
// Define our top level fifo entity
|
||||
module fifo (
|
||||
input wen, ren, clk, rst_n,
|
||||
input [7:0] wdata,
|
||||
output [7:0] rdata,
|
||||
output [ADDR_BITS:0] count,
|
||||
output full, empty
|
||||
);
|
||||
parameter MAX_DATA = 16;
|
||||
parameter ADDR_BITS = 5;
|
||||
|
||||
// wire up our sub modules
|
||||
// ADDR_BITS=5 gives 5 bits of address, [4:0]
|
||||
// supporting MAX_DATA up to 2**5=32
|
||||
wire [ADDR_BITS-1:0] waddr, raddr;
|
||||
wire wskip, rskip;
|
||||
|
||||
// fifo storage
|
||||
// reset not defined
|
||||
reg [7:0] data [MAX_DATA-1:0];
|
||||
always @(posedge clk) begin
|
||||
if (wen)
|
||||
data[waddr] <= wdata;
|
||||
end
|
||||
assign rdata = data[raddr];
|
||||
|
||||
addr_gen #(.MAX_DATA(MAX_DATA), .ADDR_BITS(ADDR_BITS))
|
||||
fifo_writer (
|
||||
.en (wen || wskip),
|
||||
.clk (clk ),
|
||||
.rst_n (rst_n),
|
||||
.addr (waddr)
|
||||
);
|
||||
|
||||
addr_gen #(.MAX_DATA(MAX_DATA), .ADDR_BITS(ADDR_BITS))
|
||||
fifo_reader (
|
||||
.en (ren || rskip),
|
||||
.clk (clk ),
|
||||
.rst_n (rst_n),
|
||||
.addr (raddr)
|
||||
);
|
||||
|
||||
// internals
|
||||
reg [ADDR_BITS:0] data_count;
|
||||
initial begin
|
||||
data_count <= 0;
|
||||
end
|
||||
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (~rst_n)
|
||||
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_n;
|
||||
assign count = data_count;
|
||||
|
||||
`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 [ADDR_BITS:0] addr_diff;
|
||||
assign addr_diff = waddr >= raddr
|
||||
? waddr - raddr
|
||||
: waddr + MAX_DATA - raddr;
|
||||
|
||||
reg init = 0;
|
||||
always @(posedge clk) begin
|
||||
if (rst_n)
|
||||
init <= 1;
|
||||
// if init is low we don't care about the value of rst_n
|
||||
// if init is high (rst_n has ben high), then rst_n must remain high
|
||||
assume (!init || init && rst_n);
|
||||
end
|
||||
|
||||
// tests
|
||||
always @(posedge clk) begin
|
||||
if (rst_n) begin
|
||||
// waddr and raddr can only be non zero if reset is high
|
||||
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 || full && count == MAX_DATA);
|
||||
w_full: cover (wen && !ren && count == MAX_DATA-1);
|
||||
a_empty: assert (!empty || empty && count == 0);
|
||||
w_empty: cover (ren && !wen && count == 1);
|
||||
|
||||
// can we corrupt our data?
|
||||
w_overfill: cover ($past(rskip) && raddr);
|
||||
w_underfill: cover ($past(wskip) && waddr);
|
||||
end else begin
|
||||
// waddr and raddr are zero while reset is low
|
||||
a_reset: assert (!waddr && !raddr);
|
||||
w_reset: cover (~rst_n);
|
||||
|
||||
// outputs are zero while reset is low
|
||||
a_zero_out: assert (!empty && !full && !count);
|
||||
end
|
||||
end
|
||||
|
||||
`ifdef VERIFIC
|
||||
// if we have verific we can also do the following additional tests
|
||||
always @(posedge clk) begin
|
||||
if (rst_n) begin
|
||||
// read/write enables enable
|
||||
ap_raddr2: assert property (ren |=> $changed(raddr));
|
||||
ap_waddr2: assert property (wen |=> $changed(waddr));
|
||||
|
||||
// read/write needs enable UNLESS full/empty
|
||||
ap_raddr3: assert property (!ren && !full |=> $stable(raddr));
|
||||
ap_waddr3: assert property (!wen && !empty |=> $stable(waddr));
|
||||
|
||||
// can we corrupt our data?
|
||||
ap_overfill: assert property (wen && full |=> $changed(raddr));
|
||||
ap_underfill: assert property (ren && empty |=> $changed(waddr));
|
||||
|
||||
// change data when writing (and only when writing) so we can line
|
||||
// up reads with writes
|
||||
assume property (wen |=> $changed(wdata));
|
||||
assume property (!wen |=> $stable(wdata));
|
||||
end
|
||||
end
|
||||
`else // !VERIFIC
|
||||
// without verific we are more limited in describing the above assumption
|
||||
always @(posedge clk) begin
|
||||
assume ((wen && wdata != $past(wdata))
|
||||
|| (!wen && wdata == $past(wdata)));
|
||||
end
|
||||
`endif // VERIFIC
|
||||
|
||||
`endif // FORMAL
|
||||
|
||||
endmodule
|
Loading…
Add table
Add a link
Reference in a new issue