diff options
author | Wade Fife <wade.fife@ettus.com> | 2021-03-09 15:38:58 -0600 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2021-06-03 11:26:54 -0500 |
commit | c6035320215f270d7658cfb6195a96a0b84d6aa7 (patch) | |
tree | fa0ee70b261291022d723e9e6f85512975bf89cb /fpga/usrp3/lib | |
parent | c64258e09b221d0bfeb55e01085a20e37c5b62ba (diff) | |
download | uhd-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.v | 105 |
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; |