aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib
diff options
context:
space:
mode:
authorWade Fife <wade.fife@ettus.com>2021-03-09 15:38:58 -0600
committerAaron Rossetto <aaron.rossetto@ni.com>2021-06-03 11:26:54 -0500
commitc6035320215f270d7658cfb6195a96a0b84d6aa7 (patch)
treefa0ee70b261291022d723e9e6f85512975bf89cb /fpga/usrp3/lib
parentc64258e09b221d0bfeb55e01085a20e37c5b62ba (diff)
downloaduhd-c6035320215f270d7658cfb6195a96a0b84d6aa7.tar.gz
uhd-c6035320215f270d7658cfb6195a96a0b84d6aa7.tar.bz2
uhd-c6035320215f270d7658cfb6195a96a0b84d6aa7.zip
fpga: lib: Pipeline ctrlport_timer
This pipelines ctrlport_timer to eliminate the long combinational path caused by the time comparisons. This change also removes the PRECISION_BITS parameter and converts it to a signal named time_ignore_bits.
Diffstat (limited to 'fpga/usrp3/lib')
-rw-r--r--fpga/usrp3/lib/rfnoc/utils/ctrlport_timer.v105
1 files changed, 81 insertions, 24 deletions
diff --git a/fpga/usrp3/lib/rfnoc/utils/ctrlport_timer.v b/fpga/usrp3/lib/rfnoc/utils/ctrlport_timer.v
index 293ee6559..52f4a90ca 100644
--- a/fpga/usrp3/lib/rfnoc/utils/ctrlport_timer.v
+++ b/fpga/usrp3/lib/rfnoc/utils/ctrlport_timer.v
@@ -1,9 +1,10 @@
//
-// Copyright 2018 Ettus Research, A National Instruments Company
+// Copyright 2021 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: ctrlport_timer
+//
// Description:
// The Control-Port timer module converts an asynchronous timed
// transaction into a synchronous blocking transaction. This
@@ -15,23 +16,23 @@
// updates every time the time strobe is asserted.
//
// Parameters:
-// - PRECISION_BITS : The number of bits to ignore when performing a
-// time comparison to determine execution time.
-// - EXEC_LATE_CMDS : If a command is late, a TSERR response is sent.
-// If EXEC_LATE_CMDS = 1, then the late command will
-// be passed to the output regardless of the TSERR.
+// - EXEC_LATE_CMDS : If EXEC_LATE_CMDS = 0 and a command is late, then a
+// TSERR response is returned. If EXEC_LATE_CMDS = 1, then
+// a late command will be passed to the output as if it
+// were on time.
//
// Signals:
-// - time_now* : The time_now signal is the current time and the stb
-// signal indicates that the time_now is valid.
-// - s_ctrlport_* : The slave Control-Port bus.
-// This must have the has_time and time signals.
-// - m_ctrlport_* : The master Control-Port bus.
-// This will not have the has_time and time signals.
+// - time_now* : The time_now signal is the current time and the stb
+// signal indicates that the time_now is valid.
+// - time_ignore_bits : Number of least-significant bits to ignore when doing
+// time comparisons. This should be a constant.
+// - s_ctrlport_* : The slave Control-Port bus.
+// This must have the has_time and time signals.
+// - m_ctrlport_* : The master Control-Port bus.
+// This will not have the has_time and time signals.
module ctrlport_timer #(
- parameter PRECISION_BITS = 0,
- parameter [0:0] EXEC_LATE_CMDS = 0
+ parameter [0:0] EXEC_LATE_CMDS = 1
)(
// Clocks and Resets
input wire clk,
@@ -39,6 +40,7 @@ module ctrlport_timer #(
// Timestamp (synchronous to clk)
input wire [63:0] time_now,
input wire time_now_stb,
+ input wire [3:0] time_ignore_bits,
// Control Port Master (Request)
input wire s_ctrlport_req_wr,
input wire s_ctrlport_req_rd,
@@ -68,11 +70,13 @@ module ctrlport_timer #(
// Control triggers:
// - pending: A command is waiting on the input port
- // - ontime: The timed command is due for execution (on time)
+ // - has_time: The command is timed
+ // - on_time: The timed command is due for execution (on time)
// - late: The timed command is late
// - exec: Execute the command (pass it to the output)
// - consume: Consume the input command
- wire pending, ontime, late, exec, consume;
+ reg pending, has_time, on_time, late;
+ wire exec, consume, valid;
// Cached values for input command
wire cached_req_wr, cached_req_rd;
wire [19:0] cached_req_addr;
@@ -80,6 +84,7 @@ module ctrlport_timer #(
wire [3:0] cached_req_byte_en;
wire cached_req_has_time;
wire [63:0] cached_req_time;
+ wire cached_req_valid;
axi_fifo_flop #(.WIDTH(1+1+20+32+4+1+64)) req_cache_i (
.clk(clk), .reset(rst), .clear(1'b0),
@@ -88,18 +93,70 @@ module ctrlport_timer #(
.i_tvalid(s_ctrlport_req_wr | s_ctrlport_req_rd), .i_tready(),
.o_tdata({cached_req_wr, cached_req_rd, cached_req_addr, cached_req_data,
cached_req_byte_en, cached_req_has_time, cached_req_time}),
- .o_tvalid(pending), .o_tready(consume),
+ .o_tvalid(cached_req_valid), .o_tready(consume),
.occupied(), .space()
);
- // Command is on time
- assign ontime = cached_req_has_time && pending && time_now_stb &&
- (cached_req_time[63:PRECISION_BITS] == time_now[63:PRECISION_BITS]);
- // Command is late
- assign late = cached_req_has_time && pending && time_now_stb &&
- (cached_req_time[63:PRECISION_BITS] < time_now[63:PRECISION_BITS]);
+ // Create a mask so that we can ignore the lower time_ignore_bits of the time.
+ wire [63:0] mask = (~64'd0 << time_ignore_bits);
+
+ // Pipeline registers
+ reg has_time_0;
+ reg has_time_1;
+ reg valid_0;
+ reg valid_1;
+ reg [63:0] time_0;
+ reg time_stb_1, time_stb_0;
+ reg [63:0] req_time_0;
+ reg on_time_1;
+ reg late_1;
+
+ // This always block pipelines the time comparisons and other condition
+ // checks, so we don't have a long combinational path here. This adds some
+ // delay to the execution of timed commands, but this block is not intended
+ // for cycle-accurate register updates.
+ always @(posedge clk) begin
+ if (rst || consume) begin
+ has_time_0 <= 'bX;
+ time_stb_0 <= 'bX;
+ time_0 <= 'bX;
+ req_time_0 <= 'bX;
+ has_time_1 <= 'bX;
+ time_stb_1 <= 'bX;
+ on_time_1 <= 'bX;
+ late_1 <= 'bX;
+ has_time <= 'bX;
+ on_time <= 'bX;
+ // These need to be zeroed, to clear the pipeline:
+ valid_0 <= 1'b0;
+ valid_1 <= 1'b0;
+ pending <= 1'b0;
+ late <= 1'b0;
+ end else begin
+ // Stage 0
+ valid_0 <= cached_req_valid;
+ has_time_0 <= cached_req_has_time;
+ time_stb_0 <= time_now_stb;
+ time_0 <= time_now & mask;
+ req_time_0 <= cached_req_time & mask;
+
+ // Stage 1
+ valid_1 <= valid_0;
+ has_time_1 <= has_time_0;
+ time_stb_1 <= time_stb_0;
+ on_time_1 <= req_time_0 == time_0;
+ late_1 <= req_time_0 < time_0;
+
+ // Stage 3
+ pending <= valid_1;
+ has_time <= has_time_1;
+ on_time <= valid_1 && has_time_1 && time_stb_1 && on_time_1;
+ late <= valid_1 && has_time_1 && time_stb_1 && late_1;
+ end
+ end
+
// Logic to pass cmd forward
- assign exec = pending && (!cached_req_has_time || ontime || (EXEC_LATE_CMDS && late));
+ assign exec = pending && (!has_time || on_time || (EXEC_LATE_CMDS && late));
assign consume = exec || late;
assign m_ctrlport_req_wr = cached_req_wr & exec;