From e2d1387df805d6a0bcfdfe7f4983b39d51b7429f Mon Sep 17 00:00:00 2001 From: Blaise Tine Date: Wed, 31 Jan 2024 00:39:37 -0800 Subject: [PATCH] elastic buffers classification --- hw/rtl/libs/VX_bypass_buffer.sv | 31 +++++--- hw/rtl/libs/VX_elastic_buffer.sv | 35 ++++----- hw/rtl/libs/VX_pipe_buffer.sv | 63 +++++++++++++++ hw/rtl/libs/VX_skid_buffer.sv | 131 +++++++------------------------ hw/rtl/libs/VX_stream_buffer | 128 ++++++++++++++++++++++++++++++ hw/rtl/libs/VX_toggle_buffer.sv | 70 +++++++++++++++++ 6 files changed, 323 insertions(+), 135 deletions(-) create mode 100644 hw/rtl/libs/VX_pipe_buffer.sv create mode 100644 hw/rtl/libs/VX_stream_buffer create mode 100644 hw/rtl/libs/VX_toggle_buffer.sv diff --git a/hw/rtl/libs/VX_bypass_buffer.sv b/hw/rtl/libs/VX_bypass_buffer.sv index 7e723a45..4eefce44 100644 --- a/hw/rtl/libs/VX_bypass_buffer.sv +++ b/hw/rtl/libs/VX_bypass_buffer.sv @@ -11,6 +11,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +// A bypass elastic buffer operates at full bandwidth where pop can happen if the buffer is empty but is going full +// It has the following benefits: +// + Full-bandwidth throughput +// + use only one register for storage +// It has the following limitations: +// + data_out is not registered +// + ready_in and ready_out are coupled + `include "VX_platform.vh" `TRACING_OFF @@ -35,30 +43,27 @@ module VX_bypass_buffer #( assign data_out = data_in; end else begin reg [DATAW-1:0] buffer; - reg buffer_valid; + reg has_data; always @(posedge clk) begin if (reset) begin - buffer_valid <= 0; + has_data <= 0; end else begin if (ready_out) begin - buffer_valid <= 0; - end - if (valid_in && ~ready_out) begin - `ASSERT(!buffer_valid, ("runtime error")); - buffer_valid <= 1; + has_data <= 0; + end else if (~has_data) begin + has_data <= valid_in; end end - - if (valid_in && ~ready_out) begin + if (~has_data) begin buffer <= data_in; end end - assign ready_in = ready_out || !buffer_valid; - assign data_out = buffer_valid ? buffer : data_in; - assign valid_out = valid_in || buffer_valid; + assign ready_in = ready_out || ~has_data; + assign data_out = has_data ? buffer : data_in; + assign valid_out = valid_in || has_data; end endmodule -`TRACING_ON \ No newline at end of file +`TRACING_ON diff --git a/hw/rtl/libs/VX_elastic_buffer.sv b/hw/rtl/libs/VX_elastic_buffer.sv index 8cd8a3ab..c6af5197 100644 --- a/hw/rtl/libs/VX_elastic_buffer.sv +++ b/hw/rtl/libs/VX_elastic_buffer.sv @@ -42,34 +42,33 @@ module VX_elastic_buffer #( end else if (SIZE == 1) begin - wire stall = valid_out && ~ready_out; - - VX_pipe_register #( - .DATAW (1 + DATAW), - .RESETW (1) - ) pipe_register ( - .clk (clk), - .reset (reset), - .enable (~stall), - .data_in ({valid_in, data_in}), - .data_out ({valid_out, data_out}) + VX_pipe_buffer #( + .DATAW (DATAW) + ) pipe_buffer ( + .clk (clk), + .reset (reset), + .valid_in (valid_in), + .data_in (data_in), + .ready_in (ready_in), + .valid_out (valid_out), + .data_out (data_out), + .ready_out (ready_out) ); - assign ready_in = ~stall; - end else if (SIZE == 2) begin VX_skid_buffer #( .DATAW (DATAW), + .FULL_BW (OUT_REG != 2), .OUT_REG (OUT_REG) ) skid_buffer ( .clk (clk), .reset (reset), - .valid_in (valid_in), + .valid_in (valid_in), + .data_in (data_in), .ready_in (ready_in), - .data_in (data_in), - .data_out (data_out), .valid_out (valid_out), + .data_out (data_out), .ready_out (ready_out) ); @@ -111,10 +110,10 @@ module VX_elastic_buffer #( .clk (clk), .reset (reset), .valid_in (~empty), - .ready_in (ready_out_t), .data_in (data_out_t), - .data_out (data_out), + .ready_in (ready_out_t), .valid_out (valid_out), + .data_out (data_out), .ready_out (ready_out) ); diff --git a/hw/rtl/libs/VX_pipe_buffer.sv b/hw/rtl/libs/VX_pipe_buffer.sv new file mode 100644 index 00000000..dfdbc43c --- /dev/null +++ b/hw/rtl/libs/VX_pipe_buffer.sv @@ -0,0 +1,63 @@ +// Copyright 2024 blaise +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the 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. + +// A pipelined elastic buffer operates at full bandwidth where push can happen if the buffer is not empty but is going empty +// It has the following benefits: +// + Full-bandwidth throughput +// + use only one register for storage +// + data_out is fully registered +// It has the following limitations: +// + ready_in and ready_out are coupled + +`include "VX_platform.vh" + +`TRACING_OFF +module VX_pipe_buffer #( + parameter DATAW = 1, + parameter PASSTHRU = 0 +) ( + input wire clk, + input wire reset, + input wire valid_in, + output wire ready_in, + input wire [DATAW-1:0] data_in, + output wire [DATAW-1:0] data_out, + input wire ready_out, + output wire valid_out +); + if (PASSTHRU != 0) begin + `UNUSED_VAR (clk) + `UNUSED_VAR (reset) + assign ready_in = ready_out; + assign valid_out = valid_in; + assign data_out = data_in; + end else begin + wire stall = valid_out && ~ready_out; + + VX_pipe_register #( + .DATAW (1 + DATAW), + .RESETW (1) + ) pipe_register ( + .clk (clk), + .reset (reset), + .enable (~stall), + .data_in ({valid_in, data_in}), + .data_out ({valid_out, data_out}) + ); + + assign ready_in = ~stall; + end + +endmodule +`TRACING_ON diff --git a/hw/rtl/libs/VX_skid_buffer.sv b/hw/rtl/libs/VX_skid_buffer.sv index a6876f5c..4816c1c2 100644 --- a/hw/rtl/libs/VX_skid_buffer.sv +++ b/hw/rtl/libs/VX_skid_buffer.sv @@ -17,6 +17,7 @@ module VX_skid_buffer #( parameter DATAW = 32, parameter PASSTHRU = 0, + parameter FULL_BW = 0, parameter OUT_REG = 0 ) ( input wire clk, @@ -30,8 +31,6 @@ module VX_skid_buffer #( input wire ready_out, output wire valid_out ); - `STATIC_ASSERT ((OUT_REG <= 2), ("invalid parameter")) - if (PASSTHRU != 0) begin `UNUSED_VAR (clk) @@ -41,112 +40,36 @@ module VX_skid_buffer #( assign data_out = data_in; assign ready_in = ready_out; - end else if (OUT_REG == 0) begin + end else if (FULL_BW != 0) begin - reg [1:0][DATAW-1:0] shift_reg; - reg valid_out_r, ready_in_r, rd_ptr_r; - - wire push = valid_in && ready_in; - wire pop = valid_out_r && ready_out; - - always @(posedge clk) begin - if (reset) begin - valid_out_r <= 0; - ready_in_r <= 1; - rd_ptr_r <= 1; - end else begin - if (push) begin - if (!pop) begin - ready_in_r <= rd_ptr_r; - valid_out_r <= 1; - end - end else if (pop) begin - ready_in_r <= 1; - valid_out_r <= rd_ptr_r; - end - rd_ptr_r <= rd_ptr_r ^ (push ^ pop); - end - end - - always @(posedge clk) begin - if (push) begin - shift_reg[1] <= shift_reg[0]; - shift_reg[0] <= data_in; - end - end - - assign ready_in = ready_in_r; - assign valid_out = valid_out_r; - assign data_out = shift_reg[rd_ptr_r]; - - end else if (OUT_REG == 1) begin - - // Full-bandwidth operation: input is consummed every cycle. - // However, data_out register has an additional multiplexer. - - reg [DATAW-1:0] data_out_r; - reg [DATAW-1:0] buffer; - reg valid_out_r; - reg use_buffer; - - wire push = valid_in && ready_in; - wire stall_out = valid_out_r && ~ready_out; - - always @(posedge clk) begin - if (reset) begin - valid_out_r <= 0; - use_buffer <= 0; - end else begin - if (ready_out) begin - use_buffer <= 0; - end else if (valid_in && valid_out) begin - use_buffer <= 1; - end - if (~stall_out) begin - valid_out_r <= valid_in || use_buffer; - end - end - end - - always @(posedge clk) begin - if (push) begin - buffer <= data_in; - end - if (~stall_out) begin - data_out_r <= use_buffer ? buffer : data_in; - end - end - - assign ready_in = ~use_buffer; - assign valid_out = valid_out_r; - assign data_out = data_out_r; + VX_stream_buffer #( + .DATAW (DATAW), + .OUT_REG (OUT_REG) + ) stream_buffer ( + .clk (clk), + .reset (reset), + .valid_in (valid_in), + .data_in (data_in), + .ready_in (ready_in), + .valid_out (valid_out), + .data_out (data_out), + .ready_out (ready_out) + ); end else begin - // Half-bandwidth operation: input is consummed every other cycle. - // However, data_out register has no additional multiplexer. - - reg [DATAW-1:0] data_out_r; - reg has_data; - - always @(posedge clk) begin - if (reset) begin - has_data <= 0; - end else begin - if (~has_data) begin - has_data <= valid_in; - end else if (ready_out) begin - has_data <= 0; - end - end - if (~has_data) begin - data_out_r <= data_in; - end - end - - assign ready_in = ~has_data; - assign valid_out = has_data; - assign data_out = data_out_r; + VX_toggle_buffer #( + .DATAW (DATAW) + ) toggle_buffer ( + .clk (clk), + .reset (reset), + .valid_in (valid_in), + .data_in (data_in), + .ready_in (ready_in), + .valid_out (valid_out), + .data_out (data_out), + .ready_out (ready_out) + ); end diff --git a/hw/rtl/libs/VX_stream_buffer b/hw/rtl/libs/VX_stream_buffer new file mode 100644 index 00000000..3bcc5d39 --- /dev/null +++ b/hw/rtl/libs/VX_stream_buffer @@ -0,0 +1,128 @@ +// Copyright 2024 blaise +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the 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. + +// A stream elastic buffer operates at full-bandwidth where push and pop can happen simultaneously +// It has the following benefits: +// + full-bandwidth throughput +// + ready_in and ready_out are decoupled +// + data_out can be fully registered +// It has the following limitations: +// - requires two registers for storage + +`include "VX_platform.vh" + +`TRACING_OFF +module VX_stream_buffer #( + parameter DATAW = 1, + parameter OUT_REG = 0, + parameter PASSTHRU = 0 +) ( + input wire clk, + input wire reset, + input wire valid_in, + output wire ready_in, + input wire [DATAW-1:0] data_in, + output wire [DATAW-1:0] data_out, + input wire ready_out, + output wire valid_out +); + if (PASSTHRU != 0) begin + `UNUSED_VAR (clk) + `UNUSED_VAR (reset) + assign ready_in = ready_out; + assign valid_out = valid_in; + assign data_out = data_in; + end else begin + if (OUT_REG != 0) begin + + reg [DATAW-1:0] data_out_r; + reg [DATAW-1:0] buffer; + reg valid_out_r; + reg use_buffer; + + wire push = valid_in && ready_in; + wire stall_out = valid_out_r && ~ready_out; + + always @(posedge clk) begin + if (reset) begin + valid_out_r <= 0; + use_buffer <= 0; + end else begin + if (ready_out) begin + use_buffer <= 0; + end else if (valid_in && valid_out) begin + use_buffer <= 1; + end + if (~stall_out) begin + valid_out_r <= valid_in || use_buffer; + end + end + end + + always @(posedge clk) begin + if (push) begin + buffer <= data_in; + end + if (~stall_out) begin + data_out_r <= use_buffer ? buffer : data_in; + end + end + + assign ready_in = ~use_buffer; + assign valid_out = valid_out_r; + assign data_out = data_out_r; + + end else begin + + reg [1:0][DATAW-1:0] shift_reg; + reg valid_out_r, ready_in_r, rd_ptr_r; + + wire push = valid_in && ready_in; + wire pop = valid_out_r && ready_out; + + always @(posedge clk) begin + if (reset) begin + valid_out_r <= 0; + ready_in_r <= 1; + rd_ptr_r <= 1; + end else begin + if (push) begin + if (!pop) begin + ready_in_r <= rd_ptr_r; + valid_out_r <= 1; + end + end else if (pop) begin + ready_in_r <= 1; + valid_out_r <= rd_ptr_r; + end + rd_ptr_r <= rd_ptr_r ^ (push ^ pop); + end + end + + always @(posedge clk) begin + if (push) begin + shift_reg[1] <= shift_reg[0]; + shift_reg[0] <= data_in; + end + end + + assign ready_in = ready_in_r; + assign valid_out = valid_out_r; + assign data_out = shift_reg[rd_ptr_r]; + end + end + +endmodule +`TRACING_ON + diff --git a/hw/rtl/libs/VX_toggle_buffer.sv b/hw/rtl/libs/VX_toggle_buffer.sv new file mode 100644 index 00000000..e67a7d74 --- /dev/null +++ b/hw/rtl/libs/VX_toggle_buffer.sv @@ -0,0 +1,70 @@ +// Copyright 2024 blaise +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the 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. + +// A toggle elastic buffer operates at half-bandwidth where push can only trigger after pop +// It has the following benefits: +// + use only one register for storage +// + ready_in and ready_out are decoupled +// + data_out is fully registered +// It has the following limitations: +// - Half-bandwidth throughput + +`include "VX_platform.vh" + +`TRACING_OFF +module VX_toggle_buffer #( + parameter DATAW = 1, + parameter PASSTHRU = 0 +) ( + input wire clk, + input wire reset, + input wire valid_in, + output wire ready_in, + input wire [DATAW-1:0] data_in, + output wire [DATAW-1:0] data_out, + input wire ready_out, + output wire valid_out +); + if (PASSTHRU != 0) begin + `UNUSED_VAR (clk) + `UNUSED_VAR (reset) + assign ready_in = ready_out; + assign valid_out = valid_in; + assign data_out = data_in; + end else begin + reg [DATAW-1:0] buffer; + reg has_data; + + always @(posedge clk) begin + if (reset) begin + has_data <= 0; + end else begin + if (~has_data) begin + has_data <= valid_in; + end else if (ready_out) begin + has_data <= 0; + end + end + if (~has_data) begin + buffer <= data_in; + end + end + + assign ready_in = ~has_data; + assign valid_out = has_data; + assign data_out = buffer; + end + +endmodule +`TRACING_ON