3
0
Fork 0
mirror of https://github.com/YosysHQ/sby.git synced 2025-04-05 22:14:08 +00:00

More literalincludes

Tidying up of newstart.rst and fifo.sv to include as much code as possible by reference.
Should reduce repetition and make it easier if changes occur in source.
This commit is contained in:
KrystalDelusion 2022-07-04 11:53:40 +12:00
parent c9fbfa3684
commit cc27d27c05
3 changed files with 99 additions and 108 deletions

View file

@ -1,17 +1,14 @@
// address generator/counter
module addr_gen (
input en, clk, rst_n,
module addr_gen
#( parameter MAX_DATA=16
) ( input en, clk, rst_n,
output reg [3:0] addr
);
parameter MAX_DATA = 16;
initial begin
addr <= 0;
end
initial addr <= 0;
// async reset
// increment address when enabled
always @(posedge clk or negedge rst_n) begin
always @(posedge clk or negedge rst_n)
if (~rst_n)
addr <= 0;
else if (en)
@ -19,52 +16,47 @@ module addr_gen (
addr <= 0;
else
addr <= addr + 1;
end
endmodule
// Define our top level fifo entity
module fifo (
input wen, ren, clk, rst_n,
module fifo
#( parameter MAX_DATA=16
) ( input wen, ren, clk, rst_n,
input [7:0] wdata,
output [7:0] rdata,
output [4:0] count,
output full, empty
);
parameter MAX_DATA = 16;
// wire up our sub modules
wire [3:0] waddr, raddr;
wire wskip, rskip;
// fifo storage
// 8 bit data, fifo depth 16 / 4 bit address
// reset not defined
// async read, sync write
wire [3:0] waddr, raddr;
reg [7:0] data [MAX_DATA-1:0];
always @(posedge clk) begin
always @(posedge clk)
if (wen)
data[waddr] <= wdata;
end
assign rdata = data[raddr];
// end storage
addr_gen #(.MAX_DATA(MAX_DATA)) fifo_writer (
// addr_gen for both write and read addresses
addr_gen #(.MAX_DATA(MAX_DATA))
fifo_writer (
.en (wen || wskip),
.clk (clk ),
.rst_n (rst_n),
.addr (waddr)
);
addr_gen #(.MAX_DATA(MAX_DATA)) fifo_reader (
addr_gen #(.MAX_DATA(MAX_DATA))
fifo_reader (
.en (ren || rskip),
.clk (clk ),
.rst_n (rst_n),
.addr (raddr)
);
// internals
// status signals
reg [4:0] data_count;
initial begin
data_count <= 0;
end
initial data_count <= 0;
always @(posedge clk or negedge rst_n) begin
if (~rst_n)
@ -79,6 +71,8 @@ module fifo (
assign empty = (data_count == 0) && rst_n;
assign count = data_count;
// overflow protection
wire wskip, rskip;
`ifndef NO_FULL_SKIP
// write while full => overwrite oldest data, move read pointer
assign rskip = wen && !ren && data_count >= MAX_DATA;
@ -116,22 +110,22 @@ module fifo (
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);
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);
|| 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));
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);
@ -165,6 +159,7 @@ module fifo (
ap_waddr3: assert property (!wen && !empty |=> $stable(waddr));
// can we corrupt our data?
// these should already be covered by ap_{r,w}addr2
ap_overfill: assert property (wen && full |=> $changed(raddr));
ap_underfill: assert property (ren && empty |=> $changed(waddr));

View file

@ -1,18 +1,15 @@
// address generator/counter
module addr_gen (
input en, clk, rst_n,
module addr_gen
#( parameter MAX_DATA=16,
parameter ADDR_BITS=5
) ( 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
initial addr <= 0;
// async reset
// increment address when enabled
always @(posedge clk or negedge rst_n) begin
always @(posedge clk or negedge rst_n)
if (~rst_n)
addr <= 0;
else if (en)
@ -20,35 +17,29 @@ module addr_gen (
addr <= 0;
else
addr <= addr + 1;
end
endmodule
// Define our top level fifo entity
module fifo (
input wen, ren, clk, rst_n,
module fifo
#( parameter MAX_DATA=16,
parameter ADDR_BITS=5
) ( 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
// async read, sync write
wire [3:0] waddr, raddr;
reg [7:0] data [MAX_DATA-1:0];
always @(posedge clk) begin
always @(posedge clk)
if (wen)
data[waddr] <= wdata;
end
assign rdata = data[raddr];
// end storage
// addr_gen for both write and read addresses
addr_gen #(.MAX_DATA(MAX_DATA), .ADDR_BITS(ADDR_BITS))
fifo_writer (
.en (wen || wskip),
@ -65,11 +56,9 @@ module fifo (
.addr (raddr)
);
// internals
// status signals
reg [ADDR_BITS:0] data_count;
initial begin
data_count <= 0;
end
initial data_count <= 0;
always @(posedge clk or negedge rst_n) begin
if (~rst_n)
@ -84,6 +73,8 @@ module fifo (
assign empty = (data_count == 0) && rst_n;
assign count = data_count;
// overflow protection
wire wskip, rskip;
`ifndef NO_FULL_SKIP
// write while full => overwrite oldest data, move read pointer
assign rskip = wen && !ren && data_count >= MAX_DATA;
@ -121,22 +112,22 @@ module fifo (
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);
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);
|| 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));
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);

View file

@ -33,7 +33,8 @@ First, the address generator module:
.. literalinclude:: ../examples/fifo/fifo.sv
:language: systemverilog
:lines: 1-23
:start-at: address generator
:end-at: endmodule
This module is instantiated twice; once for the write address and once for the
read address. In both cases, the address will start at and reset to 0, and will
@ -45,7 +46,9 @@ Next, the register file:
.. literalinclude:: ../examples/fifo/fifo.sv
:language: systemverilog
:lines: 39-47
:start-at: fifo storage
:end-before: end storage
:dedent:
Notice that this register design includes a synchronous write and asynchronous
read. Each word is 8 bits, and up to 16 words can be stored in the buffer.
@ -58,9 +61,11 @@ satisfy. For example, there must never be more than there is memory available.
By assigning a signal to count the number of values in the buffer, we can make
the following assertion in the code:
.. code-block:: systemverilog
a_oflow: assert (count <= MAX_DATA);
.. literalinclude:: ../examples/fifo/fifo.sv
:language: systemverilog
:start-at: a_oflow
:end-at: ;
:dedent:
It is also possible to use the prior value of a signal for comparison. This can
be used, for example, to ensure that the count is only able to increase or
@ -69,12 +74,11 @@ decrease by 1. A case must be added to handle resetting the count directly to
code; at least one of these conditions must be true at all times if our design
is to be correct.
.. code-block:: systemverilog
a_counts: assert (count == 0
|| count == $past(count)
|| count == $past(count) + 1
|| count == $past(count) - 1);
.. literalinclude:: ../examples/fifo/fifo.sv
:language: systemverilog
:start-at: a_counts
:end-at: ;
:dedent:
As our count signal is used independently of the read and write pointers, we
must verify that the count is always correct. While the write pointer will
@ -83,14 +87,17 @@ means that the write *address* could wrap around and appear *less than* the read
address. So we must first perform some simple arithmetic to find the absolute
difference in addresses, and then compare with the count signal.
.. code-block:: systemverilog
.. literalinclude:: ../examples/fifo/fifo.sv
:language: systemverilog
:start-at: assign addr_diff
:end-at: ;
:dedent:
assign addr_diff = waddr >= raddr
? waddr - raddr
: waddr + MAX_DATA - raddr;
a_count_diff: assert (count == addr_diff
|| count == MAX_DATA && addr_diff == 0);
.. literalinclude:: ../examples/fifo/fifo.sv
:language: systemverilog
:start-at: a_count_diff
:end-at: ;
:dedent:
SymbiYosys
**********
@ -130,14 +137,11 @@ to the ``a_count_diff`` assertion failing. Without this assertion, there is no
guarantee that data will be read in the same order it was written should an
overflow occur and the oldest data be written.
.. code-block:: systemverilog
`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;
`endif // NO_FULL_SKIP
.. literalinclude:: ../examples/fifo/fifo.sv
:language: systemverilog
:start-at: NO_FULL_SKIP
:end-at: endif
:lines: 1-5,9
The last few lines of output for the noskip task should be similar to the
following:
@ -257,11 +261,12 @@ increment or remain the same we do not need to specify that here. We can also
assert that if the enable is low, and the buffer is not full and potentially
requires a skip in the read address, then the read address will *not* change.
.. code-block:: systemverilog
ap_raddr2: assert property (ren |=> $changed(raddr));
ap_raddr3: assert property (!ren && !full |=> $stable(raddr));
.. literalinclude:: ../examples/fifo/fifo.sv
:language: systemverilog
:start-at: ap_raddr2
:end-at: ap_raddr3
:dedent:
:lines: 1,5
Further information
*******************