Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stream FIFO: Add a passthrough variant #215

Merged
merged 1 commit into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ tests:
- clk_mux_glitch_free_tb
- id_queue_tb
- isochronous_crossing_tb
- passthrough_stream_fifo_tb
- popcount_tb
- rr_arb_tree_tb
- stream_omega_net_tb
Expand Down
2 changes: 2 additions & 0 deletions Bender.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ sources:
- src/mv_filter.sv
- src/onehot_to_bin.sv
- src/plru_tree.sv
- src/passthrough_stream_fifo.sv
- src/popcount.sv
- src/rr_arb_tree.sv
- src/rstgen_bypass.sv
Expand Down Expand Up @@ -127,6 +128,7 @@ sources:
- test/fifo_tb.sv
- test/graycode_tb.sv
- test/id_queue_tb.sv
- test/passthrough_stream_fifo_tb.sv
- test/popcount_tb.sv
- test/rr_arb_tree_tb.sv
- test/stream_test.sv
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## Unreleased
### Added
- Add `passthrough_stream_fifo`: stream FIFO which does not cut the timing path, this allows it to do a simultaneous push and pop when full.

## 1.32.0 - 2023-09-26
### Added
- Add `stream_join_dynamic`: `stream_join` with a dynamically configurable subset selection.
Expand Down
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,20 +109,21 @@ Please note that cells with status *deprecated* are not to be used for new desig

### Data Structures

| Name | Description | Status | Superseded By |
| -------------------------- | ----------------------------------------------------------------------- | ------------ | ------------- |
| `cb_filter` | Counting-Bloom-Filter with combinational lookup | active | |
| `fifo` | FIFO register with upper threshold | *deprecated* | `fifo_v3` |
| `fifo_v2` | FIFO register with upper and lower threshold | *deprecated* | `fifo_v3` |
| `fifo_v3` | FIFO register with generic fill counts | active | |
| `stream_fifo` | FIFO register with ready/valid interface | active | |
| `stream_fifo_optimal_wrap` | Wrapper that optimally selects either a spill register or a FIFO | active | |
| `generic_fifo` | FIFO register without thresholds | *deprecated* | `fifo_v3` |
| `generic_fifo_adv` | FIFO register without thresholds | *deprecated* | `fifo_v3` |
| `sram` | SRAM behavioral model | active | |
| `plru_tree` | Pseudo least recently used tree | active | |
| `unread` | Empty module to sink unconnected outputs into | active | |
| `read` | Dummy module that prevents a signal from being removed during synthesis | active | |
| Name | Description | Status | Superseded By |
| -------------------------- | --------------------------------------------------------------------------- | ------------ | ------------- |
| `cb_filter` | Counting-Bloom-Filter with combinational lookup | active | |
| `fifo` | FIFO register with upper threshold | *deprecated* | `fifo_v3` |
| `fifo_v2` | FIFO register with upper and lower threshold | *deprecated* | `fifo_v3` |
| `fifo_v3` | FIFO register with generic fill counts | active | |
| `passthrough_stream_fifo` | FIFO register with ready/valid interface and same-cycle push/pop when full | active | |
| `stream_fifo` | FIFO register with ready/valid interface | active | |
| `stream_fifo_optimal_wrap` | Wrapper that optimally selects either a spill register or a FIFO | active | |
| `generic_fifo` | FIFO register without thresholds | *deprecated* | `fifo_v3` |
| `generic_fifo_adv` | FIFO register without thresholds | *deprecated* | `fifo_v3` |
| `sram` | SRAM behavioral model | active | |
| `plru_tree` | Pseudo least recently used tree | active | |
| `unread` | Empty module to sink unconnected outputs into | active | |
| `read` | Dummy module that prevents a signal from being removed during synthesis | active | |


## Header Contents
Expand Down
1 change: 1 addition & 0 deletions common_cells.core
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ filesets:
- src/mv_filter.sv
- src/onehot_to_bin.sv
- src/plru_tree.sv
- src/passthrough_stream_fifo.sv
- src/popcount.sv
- src/rr_arb_tree.sv
- src/rstgen_bypass.sv
Expand Down
122 changes: 122 additions & 0 deletions src/passthrough_stream_fifo.sv
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
1 change: 1 addition & 0 deletions src_files.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ common_cells_all:
- src/mv_filter.sv
- src/onehot_to_bin.sv
- src/plru_tree.sv
- src/passthrough_stream_fifo.sv
- src/popcount.sv
- src/rr_arb_tree.sv
- src/rstgen_bypass.sv
Expand Down
135 changes: 135 additions & 0 deletions test/passthrough_stream_fifo_tb.sv
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
Loading