-
Notifications
You must be signed in to change notification settings - Fork 145
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Stream FIFO: Add a passthrough variant
- Loading branch information
1 parent
69d40a5
commit 18a6833
Showing
8 changed files
with
281 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// Copyright 2024 ETH Zurich and University of Bologna. | ||
// Solderpad Hardware License, Version 0.51, see LICENSE for details. | ||
// SPDX-License-Identifier: SHL-0.51 | ||
|
||
// Authors: | ||
// - Thomas Benz <[email protected]> | ||
// - Tobias Senti <[email protected]> | ||
|
||
`include "common_cells/assertions.svh" | ||
`include "common_cells/registers.svh" | ||
|
||
/// Stream FIFO that does not cut the timing path. When full; pushing data is allowed if in | ||
/// the same cycle data is popped. Creates longer timing paths but can use buffer space more | ||
/// efficiently. | ||
module passthrough_stream_fifo #( | ||
/// Depth can be arbitrary from 2 to 2**32 | ||
parameter int unsigned Depth = 32'd8, | ||
/// Print information when the simulation launches | ||
parameter bit PrintInfo = 1'b0, | ||
/// If the FIFO is full, allow reading and writing in the same cycle | ||
parameter bit SameCycleRW = 1'b1, | ||
/// Type of the FIFO | ||
parameter type type_t = logic | ||
) ( | ||
/// Clock | ||
input logic clk_i, | ||
/// Asynchronous reset active low | ||
input logic rst_ni, | ||
/// Fifo flush | ||
input logic flush_i, | ||
/// Bypass clock gate | ||
input logic testmode_i, | ||
/// data to push into the FIFO | ||
input type_t data_i, | ||
/// input data valid | ||
input logic valid_i, | ||
/// FIFO is not full | ||
output logic ready_o, | ||
/// output data | ||
output type_t data_o, | ||
/// FIFO is not empty | ||
output logic valid_o, | ||
/// pop head from FIFO | ||
input logic ready_i | ||
); | ||
/// Bit Width of the read and write pointers | ||
/// One additional bit to detect overflows | ||
localparam int unsigned PointerWidth = $clog2(Depth) + 1; | ||
|
||
// Read and write pointers | ||
logic [PointerWidth-1:0] read_ptr_d, read_ptr_q; | ||
logic [PointerWidth-1:0] write_ptr_d, write_ptr_q; | ||
|
||
// Data | ||
type_t [Depth-1 :0] data_d, data_q; | ||
|
||
// Enable storage | ||
logic load_data; | ||
|
||
assign data_o = data_q[read_ptr_q[PointerWidth-2:0]]; | ||
|
||
// Logic | ||
always_comb begin | ||
// Default | ||
load_data = 1'b0; | ||
read_ptr_d = read_ptr_q; | ||
write_ptr_d = write_ptr_q; | ||
data_d = data_q; | ||
|
||
if (flush_i) begin // Flush | ||
read_ptr_d = '0; | ||
write_ptr_d = '0; | ||
valid_o = 1'b0; | ||
ready_o = 1'b0; | ||
end else begin | ||
// Read | ||
valid_o = read_ptr_q[PointerWidth-1] == write_ptr_q[PointerWidth-1] | ||
? read_ptr_q[PointerWidth-2:0] != write_ptr_q[PointerWidth-2:0] : 1'b1; | ||
if (ready_i) begin | ||
if (read_ptr_q[PointerWidth-2:0] == (Depth-1)) begin | ||
// On overflow reset pointer to zero and flip imaginary bit | ||
read_ptr_d[PointerWidth-2:0] = '0; | ||
read_ptr_d[PointerWidth-1] = !read_ptr_q[PointerWidth-1]; | ||
end else begin | ||
// Increment counter | ||
read_ptr_d = read_ptr_q + 'd1; | ||
end | ||
end | ||
|
||
// Write -> Also able to write if we read in the same cycle | ||
ready_o = (read_ptr_q[PointerWidth-1] == write_ptr_q[PointerWidth-1] | ||
? 1'b1 : write_ptr_q[PointerWidth-2:0] != read_ptr_q[PointerWidth-2:0]) | ||
|| (SameCycleRW && ready_i && valid_o); | ||
|
||
if (valid_i) begin | ||
load_data = 1'b1; | ||
data_d[write_ptr_q[PointerWidth-2:0]] = data_i; | ||
|
||
if (write_ptr_q[PointerWidth-2:0] == (Depth-1)) begin | ||
// On overflow reset pointer to zero and flip imaginary bit | ||
write_ptr_d[PointerWidth-2:0] = '0; | ||
write_ptr_d[PointerWidth-1] = !write_ptr_q[PointerWidth-1]; | ||
end else begin | ||
// Increment pointer | ||
write_ptr_d = write_ptr_q + 'd1; | ||
end | ||
end | ||
end | ||
end | ||
|
||
// Flip Flops | ||
`FF( read_ptr_q, read_ptr_d, '0, clk_i, rst_ni) | ||
`FF(write_ptr_q, write_ptr_d, '0, clk_i, rst_ni) | ||
|
||
`FFL(data_q, data_d, load_data, '0, clk_i, rst_ni) | ||
|
||
// no full push | ||
`ASSERT_NEVER(CheckFullPush, (!ready_o & valid_i), clk_i, !rst_ni) | ||
// empty pop | ||
`ASSERT_NEVER(CheckEmptyPop, (!valid_o & ready_i), clk_i, !rst_ni) | ||
|
||
endmodule |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
// Copyright 2024 ETH Zurich and University of Bologna. | ||
// Solderpad Hardware License, Version 0.51, see LICENSE for details. | ||
// SPDX-License-Identifier: SHL-0.51 | ||
|
||
// Authors: | ||
// - Tobias Senti <[email protected]> | ||
|
||
`timescale 1ns/1ns | ||
|
||
/// This modules verifies basic operation of the passthrough_stream_fifo_tb. | ||
module passthrough_stream_fifo_tb #( | ||
parameter int unsigned TCK = 10, | ||
parameter int unsigned DataWidth = 8, | ||
parameter int unsigned Depth = 10, | ||
parameter int unsigned NumStims = 1000, | ||
parameter int unsigned WriteProbability = 10, | ||
parameter int unsigned ReadProbability = 10, | ||
parameter bit SameCycleRW = 1'b1 | ||
) (); | ||
typedef logic [DataWidth-1:0] data_t; | ||
|
||
int unsigned applied_stims, acquired_stims; | ||
|
||
logic clk, rst_n; | ||
|
||
data_t in_data, out_data; | ||
logic in_valid, in_ready, out_valid, out_ready; | ||
|
||
// Data queues | ||
data_t app_queue[$], acq_queue[$]; | ||
|
||
//Clock generator | ||
clk_rst_gen #( | ||
.ClkPeriod ( TCK ), | ||
.RstClkCycles ( 1 ) | ||
) i_clk_rst_gen ( | ||
.clk_o ( clk ), | ||
.rst_no ( rst_n ) | ||
); | ||
|
||
// DUT | ||
passthrough_stream_fifo #( | ||
.Depth ( Depth ), | ||
.type_t ( data_t ), | ||
.PrintInfo ( 1'b1 ), | ||
.SameCycleRW ( SameCycleRW ) | ||
) i_passthrough_stream_fifo ( | ||
.clk_i ( clk ), | ||
.rst_ni ( rst_n ), | ||
.flush_i ( 1'b0 ), | ||
.testmode_i ( 1'b0 ), | ||
|
||
.data_i ( (in_valid && in_ready) ? in_data : 'x ), | ||
.valid_i ( in_valid && in_ready ), | ||
.ready_o ( in_ready ), | ||
|
||
.data_o ( out_data ), | ||
.valid_o ( out_valid ), | ||
.ready_i ( out_ready && out_valid ) | ||
); | ||
|
||
// Application | ||
initial begin | ||
applied_stims = 0; | ||
in_data = '0; | ||
in_valid = 1'b0; | ||
|
||
// Wait for reset | ||
wait(rst_n); | ||
|
||
$display("Started application!"); | ||
|
||
while(applied_stims < NumStims) begin | ||
@(negedge clk); | ||
in_valid = $urandom_range(0, WriteProbability) == 0; | ||
in_data = $urandom(); | ||
@(posedge clk); | ||
if (in_valid && in_ready) begin | ||
$display("%d Applied: %d", applied_stims, in_data); | ||
app_queue.push_back(in_data); | ||
applied_stims++; | ||
end | ||
end | ||
in_valid = 1'b0; | ||
|
||
$display("Applied %d stimuli", applied_stims); | ||
end | ||
|
||
// Acquisition | ||
initial begin | ||
acquired_stims = 0; | ||
out_ready = 1'b0; | ||
|
||
// Wait for reset | ||
wait(rst_n); | ||
|
||
$display("Started acquisition!"); | ||
|
||
forever begin | ||
@(negedge clk); | ||
out_ready = $urandom_range(0, ReadProbability) == 0; | ||
@(posedge clk); | ||
if (out_valid && out_ready) begin | ||
$display("%d Acquired: %d", acquired_stims, out_data); | ||
acq_queue.push_back(out_data); | ||
acquired_stims++; | ||
end | ||
end | ||
end | ||
|
||
// Response Checking | ||
initial begin | ||
int unsigned num_errors; | ||
data_t acq_data, app_data; | ||
|
||
num_errors = 0; | ||
|
||
while((acquired_stims < NumStims) || (applied_stims < NumStims)) begin | ||
wait((app_queue.size() != 0) && (acq_queue.size() != 0)); | ||
|
||
acq_data = acq_queue.pop_front(); | ||
app_data = app_queue.pop_front(); | ||
|
||
if (app_data != acq_data) begin | ||
$display("Missmatch! Applied: %d Acquired: %d", app_data, acq_data); | ||
num_errors++; | ||
end else begin | ||
$display("Match! Applied: %d Acquired: %d", app_data, acq_data); | ||
end | ||
end | ||
$display("Applied %d stimuli and acquired %d responses", applied_stims, acquired_stims); | ||
$display("Errors: %d", num_errors); | ||
$stop(); | ||
end | ||
endmodule |