Skip to content
Draft
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
2 changes: 2 additions & 0 deletions Bender.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ sources:
- rtl/basic/hwpe_stream_demux_static.sv
- rtl/basic/hwpe_stream_deserialize.sv
- rtl/basic/hwpe_stream_fence.sv
- rtl/basic/hwpe_stream_fence_asymmetric.sv
- rtl/basic/hwpe_stream_merge.sv
- rtl/basic/hwpe_stream_mux_static.sv
- rtl/basic/hwpe_stream_serialize.sv
Expand All @@ -32,6 +33,7 @@ sources:
- rtl/streamer/hwpe_stream_addressgen.sv
- rtl/streamer/hwpe_stream_addressgen_v2.sv
- rtl/streamer/hwpe_stream_addressgen_v3.sv
- rtl/streamer/hwpe_stream_addressgen_v4.sv
- rtl/streamer/hwpe_stream_sink_realign.sv
- rtl/streamer/hwpe_stream_source_realign.sv
- rtl/streamer/hwpe_stream_strbgen.sv
Expand Down
165 changes: 165 additions & 0 deletions rtl/basic/hwpe_stream_fence_asymmetric.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* hwpe_stream_fence_aymmetric.sv
* Arpan Suravi Prasad <prasadar@iis.ee.ethz.ch>
*
* Copyright (C) 2014-2018 ETH Zurich, University of Bologna
* Copyright and related rights are licensed under the Solderpad Hardware
* License, Version 0.51 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
* or agreed to in writing, software, hardware and materials distributed under
* this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

/**
* The **hwpe_stream_fence_asymmetric** module is used to synchronize the handshake between
* `NB_STREAMS` streams.
* This is necessary, for example, when 2 asymmetric(different datawidth) streams are produced
* from separate TCDM accesses and have to be joined into a single, wider
* stream.
*
* .. _wavedrom_hwpe_stream_fence:
* .. wavedrom:: wavedrom/hwpe_stream_fence.json
* :width: 85 %
* :caption: Example of **hwpe_stream_fence** operation.
*
* .. tabularcolumns:: |l|l|J|
* .. _hwpe_stream_fence_params:
* .. table:: **hwpe_stream_fence** design-time parameters.
*
* +------------------+-------------+---------------------------------------------+
* | **Name** | **Default** | **Description** |
* +------------------+-------------+---------------------------------------------+
* | *NB_STREAMS* | 2 | Number of input/output HWPE-Stream streams. |
* +------------------+-------------+---------------------------------------------+
* | *DATA_WIDTH* | 32 | Width of the HWPE-Stream streams. |
* +------------------+-------------+---------------------------------------------+
*/

import hwpe_stream_package::*;

module hwpe_stream_fence_asymmetric #(
localparam int unsigned NB_STREAMS = 2,
parameter int unsigned ELEM_WIDTH_0 = 32,
parameter int unsigned ELEM_WIDTH_1 = 32,
parameter int unsigned DATA_WIDTH_0 = 32,
parameter int unsigned DATA_WIDTH_1 = 32
)
(
input logic clk_i,
input logic rst_ni,
input logic clear_i,
input logic bypass_i,

hwpe_stream_intf_stream.sink push_0_i,
hwpe_stream_intf_stream.sink push_1_i,
hwpe_stream_intf_stream.source pop_0_o,
hwpe_stream_intf_stream.source pop_1_o
);

logic [NB_STREAMS-1:0] in_valid;
logic out_valid;
logic [NB_STREAMS-1:0] fence_state_q, fence_state_d;
logic [DATA_WIDTH_0-1:0] data_0_d, data_0_q;
logic [DATA_WIDTH_1-1:0] data_1_d, data_1_q;
logic [DATA_WIDTH_0/ELEM_WIDTH_0-1:0] strb_0_d, strb_0_q;
logic [DATA_WIDTH_1/ELEM_WIDTH_1-1:0] strb_1_d, strb_1_q;

logic [NB_STREAMS-1:0] in_strm_hs, out_strm_hs;

assign in_strm_hs[0] = push_0_i.ready & push_0_i.valid;
assign in_strm_hs[1] = push_1_i.ready & push_1_i.valid;

assign out_strm_hs[0] = pop_0_o.ready & pop_0_o.valid;
assign out_strm_hs[1] = pop_1_o.ready & pop_1_o.valid;

assign in_valid[0] = push_0_i.valid;
assign in_valid[1] = push_1_i.valid;

// Can take element if there is nothing registered or if registered there is a handshake
assign push_0_i.ready = ~fence_state_q[0] || fence_state_q[0] & out_strm_hs[0];
assign push_1_i.ready = ~fence_state_q[1] || fence_state_q[1] & out_strm_hs[1];

assign out_valid = &( fence_state_q | in_valid);

assign pop_0_o.valid = bypass_i ? push_0_i.valid | fence_state_q[0] : out_valid;
assign pop_1_o.valid = bypass_i ? push_1_i.valid | fence_state_q[1] : out_valid;

assign pop_0_o.data = fence_state_q[0] ? data_0_q: push_0_i.data;
assign pop_1_o.data = fence_state_q[1] ? data_1_q: push_1_i.data;

assign pop_0_o.strb = fence_state_q[0] ? strb_0_q: push_0_i.data;
assign pop_1_o.strb = fence_state_q[1] ? strb_1_q: push_1_i.strb;

always_comb begin
fence_state_d[0] = fence_state_q[0];
data_0_d = data_0_q;
strb_0_d = strb_0_q;
if(in_strm_hs[0] & out_strm_hs[0]) begin
fence_state_d[0] = fence_state_q[0];
data_0_d = fence_state_q[0] ? push_0_i.data : data_0_q;
strb_0_d = fence_state_q[0] ? push_0_i.strb : strb_0_q;
end else if (in_strm_hs[0] & ~out_strm_hs[0]) begin
fence_state_d[0] = 1'b1;
data_0_d = push_0_i.data;
strb_0_d = push_0_i.strb;
end else if (~in_strm_hs[0] & out_strm_hs[0]) begin
fence_state_d[0] = 1'b0;
data_0_d = '0;
strb_0_d = '0;
end
end

always_comb begin
fence_state_d[1] = fence_state_q[1];
data_1_d = data_1_q;
strb_1_d = strb_1_q;
if(in_strm_hs[1] & out_strm_hs[1]) begin
fence_state_d[1] = fence_state_q[1];
data_1_d = fence_state_q[1] ? push_1_i.data : data_1_q;
strb_1_d = fence_state_q[1] ? push_1_i.strb : strb_1_q;
end else if (in_strm_hs[1] & ~out_strm_hs[1]) begin
fence_state_d[1] = 1'b1;
data_1_d = push_1_i.data;
strb_1_d = push_1_i.strb;
end else if (~in_strm_hs[1] & out_strm_hs[1]) begin
fence_state_d[1] = 1'b0;
data_1_d = '0;
strb_1_d = '0;
end
end

always_ff @(posedge clk_i or negedge rst_ni)
begin
if(~rst_ni) begin
data_0_q <= '0;
data_1_q <= '0;
strb_0_q <= '0;
strb_1_q <= '0;
end else if(clear_i) begin
data_0_q <= '0;
data_1_q <= '0;
strb_0_q <= '0;
strb_1_q <= '0;
end else begin
data_0_q <= data_0_d;
data_1_q <= data_1_d;
strb_0_q <= strb_0_d;
strb_1_q <= strb_1_d;
end
end


always_ff @(posedge clk_i or negedge rst_ni)
begin
if(~rst_ni)
fence_state_q <= '0;
else if(clear_i)
fence_state_q <= '0;
else
fence_state_q <= fence_state_d;
end

endmodule // hwpe_stream_fence
29 changes: 21 additions & 8 deletions rtl/basic/hwpe_stream_serialize.sv
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ module hwpe_stream_serialize #(
parameter int unsigned NB_IN_STREAMS = 2,
parameter int unsigned CONTIG_LIMIT = 1024,
parameter int unsigned DATA_WIDTH = 32,
parameter int unsigned ELEMENT_WIDTH = 8,
parameter int unsigned MODE = 0,
localparam int unsigned NUM_ELEMENTS = DATA_WIDTH/ELEMENT_WIDTH,
parameter logic SYNC_READY = 1'b0
)
(
Expand All @@ -80,15 +83,15 @@ module hwpe_stream_serialize #(
// boilerplate for SystemVerilog compliance
logic [NB_IN_STREAMS-1:0][DATA_WIDTH-1:0] push_data;
logic [NB_IN_STREAMS-1:0] push_valid;
logic [NB_IN_STREAMS-1:0][DATA_WIDTH/8-1:0] push_strb;
logic [NB_IN_STREAMS-1:0][NUM_ELEMENTS-1:0] push_strb;
logic [NB_IN_STREAMS-1:0] push_ready;

generate
for(genvar ii=0; ii<NB_IN_STREAMS; ii++) begin : stream_binding

assign push_data [ii] = push_i[ii].data;
assign push_strb [ii] = push_i[ii].strb;
assign push_valid[ii] = push_i[ii].valid;
assign push_valid[ii] = push_i[ii].valid & stream_cnt_en;
assign push_i[ii].ready = push_ready[ii];

end
Expand All @@ -99,9 +102,16 @@ module hwpe_stream_serialize #(
assign pop_o.valid = push_valid[stream_cnt_q];
assign pop_o.strb = push_strb [stream_cnt_q];

logic last_stream;

if(MODE == 0)
assign last_stream = 1'b0;
else
assign last_stream = (contig_cnt_q == ctrl_i.nb_contig_m1 - 1) ? stream_cnt_en & pop_o.ready : 1'b0;

if(SYNC_READY) begin : sync_ready_gen
for(genvar ii=0; ii<NB_IN_STREAMS; ii++) begin : sync_ready_loop_gen
assign push_ready[ii] = (stream_cnt_q == NB_IN_STREAMS-1) ? stream_cnt_en & pop_o.ready : 1'b0;
assign push_ready[ii] = (stream_cnt_q == NB_IN_STREAMS-1) || (contig_cnt_q == ctrl_i.nb_contig_m1 - 1) ? stream_cnt_en & pop_o.ready : 1'b0;
end
end
else begin : no_sync_ready_gen
Expand All @@ -121,7 +131,7 @@ module hwpe_stream_serialize #(
else if(clear_i) begin
stream_cnt_q <= '0;
end
else if(stream_cnt_en & pop_o.valid & pop_o.ready) begin
else begin
stream_cnt_q <= stream_cnt_d;
end
end
Expand All @@ -134,7 +144,7 @@ module hwpe_stream_serialize #(
end
else begin
if(stream_cnt_q < NB_IN_STREAMS-1) begin
stream_cnt_d = stream_cnt_q + 1;
stream_cnt_d = last_stream ? '0 : stream_cnt_q + (stream_cnt_en & pop_o.valid & pop_o.ready);
end
else begin
stream_cnt_d = '0;
Expand All @@ -151,7 +161,7 @@ module hwpe_stream_serialize #(
else if(clear_i) begin
contig_cnt_q <= '0;
end
else if(pop_o.valid & pop_o.ready) begin
else begin
contig_cnt_q <= contig_cnt_d;
end
end
Expand All @@ -160,13 +170,16 @@ module hwpe_stream_serialize #(
begin : contig_counter_comb
contig_cnt_d = '0;
if(contig_cnt_q < ctrl_i.nb_contig_m1) begin
contig_cnt_d = contig_cnt_q + 1;
contig_cnt_d = last_stream ? '0 : contig_cnt_q + (pop_o.valid & pop_o.ready);
end
else begin
contig_cnt_d = '0;
end
end

assign stream_cnt_en = contig_cnt_q < ctrl_i.nb_contig_m1 ? 1'b0 : 1'b1;
if(MODE == 0)
assign stream_cnt_en = contig_cnt_q < ctrl_i.nb_contig_m1 ? 1'b0 : 1'b1;
else
assign stream_cnt_en = contig_cnt_q <= ctrl_i.nb_contig_m1 ? 1'b1 : 1'b0;

endmodule // hwpe_stream_serialize
17 changes: 10 additions & 7 deletions rtl/fifo/hwpe_stream_fifo.sv
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import hwpe_stream_package::*;

module hwpe_stream_fifo #(
parameter int unsigned DATA_WIDTH = 32,
parameter int unsigned ELEMENT_WIDTH = 8,
parameter int unsigned FIFO_DEPTH = 8,
parameter int unsigned LATCH_FIFO = 0,
parameter int unsigned LATCH_FIFO_TEST_WRAP = 0
Expand All @@ -81,6 +82,8 @@ module hwpe_stream_fifo #(
hwpe_stream_intf_stream.sink push_i,
hwpe_stream_intf_stream.source pop_o
);
localparam int unsigned STRB_WIDTH = DATA_WIDTH / ELEMENT_WIDTH;
localparam int unsigned DATA_STRB_WIDTH = DATA_WIDTH + STRB_WIDTH;

// Local Parameter
localparam ADDR_DEPTH = (FIFO_DEPTH==1) ? 1 : $clog2(FIFO_DEPTH);
Expand All @@ -90,7 +93,7 @@ module hwpe_stream_fifo #(

logic [ADDR_DEPTH-1:0] pop_pointer_q, pop_pointer_d;
logic [ADDR_DEPTH-1:0] push_pointer_q, push_pointer_d;
logic [DATA_WIDTH+DATA_WIDTH/8-1:0] fifo_registers[FIFO_DEPTH-1:0];
logic [DATA_STRB_WIDTH-1:0] fifo_registers[FIFO_DEPTH-1:0];
integer i;

assign flags_o.empty = (cs == EMPTY) ? 1'b1 : 1'b0;
Expand Down Expand Up @@ -232,8 +235,8 @@ module hwpe_stream_fifo #(
endcase
end

logic [DATA_WIDTH+DATA_WIDTH/8-1:0] data_out_int;
logic [DATA_WIDTH+DATA_WIDTH/8-1:0] data_in_int;
logic [DATA_STRB_WIDTH-1:0] data_out_int;
logic [DATA_STRB_WIDTH-1:0] data_in_int;

generate
if(LATCH_FIFO == 0) begin : fifo_ff_gen
Expand Down Expand Up @@ -263,7 +266,7 @@ module hwpe_stream_fifo #(

hwpe_stream_fifo_scm #(
.ADDR_WIDTH ( ADDR_DEPTH ),
.DATA_WIDTH ( DATA_WIDTH + DATA_WIDTH/8 )
.DATA_WIDTH ( DATA_STRB_WIDTH )
) i_fifo_latch (
.clk ( clk_i ),
.rst_n ( rst_ni ),
Expand All @@ -282,7 +285,7 @@ module hwpe_stream_fifo #(

hwpe_stream_fifo_scm_test_wrap #(
.ADDR_WIDTH ( ADDR_DEPTH ),
.DATA_WIDTH ( DATA_WIDTH + DATA_WIDTH/8 )
.DATA_WIDTH ( DATA_STRB_WIDTH )
) i_fifo_latch (
.clk ( clk_i ),
.rst_n ( rst_ni ),
Expand All @@ -303,7 +306,7 @@ module hwpe_stream_fifo #(
end
endgenerate

assign pop_o.data = (pop_o.valid == 1'b1) ? data_out_int[DATA_WIDTH+DATA_WIDTH/8-1:DATA_WIDTH/8] : '0;
assign pop_o.strb = (pop_o.valid == 1'b1) ? data_out_int[DATA_WIDTH/8-1:0] : '0;
assign pop_o.data = (pop_o.valid == 1'b1) ? data_out_int[DATA_STRB_WIDTH-1:STRB_WIDTH] : '0;
assign pop_o.strb = (pop_o.valid == 1'b1) ? data_out_int[STRB_WIDTH-1:0] : '0;

endmodule // hwpe_stream_fifo
12 changes: 8 additions & 4 deletions rtl/hwpe_stream_interfaces.sv
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
interface hwpe_stream_intf_tcdm (
input logic clk
);
parameter int unsigned DATA_WIDTH = 32; // used to default to -1 and always overridden --> not well supported by some tools
parameter int unsigned ELEMENT_WIDTH = 8; // by default a byte as the element width
parameter int unsigned STRB_WIDTH = DATA_WIDTH/ELEMENT_WIDTH;
`ifndef SYNTHESIS
// the TRVR assert is disabled by default, as it is only valid for zero-latency
// accesses (e.g. using FIFO queues breaks this assumption)
Expand All @@ -30,9 +33,9 @@ interface hwpe_stream_intf_tcdm (
logic gnt;
logic [31:0] add;
logic wen;
logic [3:0] be;
logic [31:0] data;
logic [31:0] r_data;
logic [STRB_WIDTH-1:0] be;
logic [DATA_WIDTH-1:0] data;
logic [DATA_WIDTH-1:0] r_data;
logic r_valid;

modport master (
Expand Down Expand Up @@ -71,7 +74,8 @@ interface hwpe_stream_intf_stream
input logic clk
);
parameter int unsigned DATA_WIDTH = 32; // used to default to -1 and always overridden --> not well supported by some tools
parameter int unsigned STRB_WIDTH = DATA_WIDTH/8;
parameter int unsigned ELEMENT_WIDTH = 8; // by default a byte as the element width
parameter int unsigned STRB_WIDTH = DATA_WIDTH/ELEMENT_WIDTH;
`ifndef SYNTHESIS
parameter bit BYPASS_VCR_ASSERT = 1'b0;
parameter bit BYPASS_VDR_ASSERT = 1'b0;
Expand Down
Loading