diff options
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/utils/ctrlport_timer.v')
-rw-r--r-- | fpga/usrp3/lib/rfnoc/utils/ctrlport_timer.v | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/rfnoc/utils/ctrlport_timer.v b/fpga/usrp3/lib/rfnoc/utils/ctrlport_timer.v new file mode 100644 index 000000000..293ee6559 --- /dev/null +++ b/fpga/usrp3/lib/rfnoc/utils/ctrlport_timer.v @@ -0,0 +1,122 @@ +// +// Copyright 2018 Ettus Research, A National Instruments Company +// +// 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 +// module will use the input req_has_time and req_time fields and +// produce an output transaction that will execute when the requested +// time is current. The module does not pass the has_time and time +// signals out because they are no longer relevant. The current time +// is an input to this module, and must be a monotonic counter that +// 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. +// +// 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. + +module ctrlport_timer #( + parameter PRECISION_BITS = 0, + parameter [0:0] EXEC_LATE_CMDS = 0 +)( + // Clocks and Resets + input wire clk, + input wire rst, + // Timestamp (synchronous to clk) + input wire [63:0] time_now, + input wire time_now_stb, + // Control Port Master (Request) + input wire s_ctrlport_req_wr, + input wire s_ctrlport_req_rd, + input wire [19:0] s_ctrlport_req_addr, + input wire [31:0] s_ctrlport_req_data, + input wire [3:0] s_ctrlport_req_byte_en, + input wire s_ctrlport_req_has_time, + input wire [63:0] s_ctrlport_req_time, + // Control Port Slave (Response) + output wire s_ctrlport_resp_ack, + output wire [1:0] s_ctrlport_resp_status, + output wire [31:0] s_ctrlport_resp_data, + // Control Port Master (Request) + output wire m_ctrlport_req_wr, + output wire m_ctrlport_req_rd, + output wire [19:0] m_ctrlport_req_addr, + output wire [31:0] m_ctrlport_req_data, + output wire [3:0] m_ctrlport_req_byte_en, + // Control Port Master (Response) + input wire m_ctrlport_resp_ack, + input wire [1:0] m_ctrlport_resp_status, + input wire [31:0] m_ctrlport_resp_data +); + + `include "../core/rfnoc_chdr_utils.vh" + `include "../core/rfnoc_axis_ctrl_utils.vh" + + // Control triggers: + // - pending: A command is waiting on the input port + // - ontime: 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; + // Cached values for input command + wire cached_req_wr, cached_req_rd; + wire [19:0] cached_req_addr; + wire [31:0] cached_req_data; + wire [3:0] cached_req_byte_en; + wire cached_req_has_time; + wire [63:0] cached_req_time; + + axi_fifo_flop #(.WIDTH(1+1+20+32+4+1+64)) req_cache_i ( + .clk(clk), .reset(rst), .clear(1'b0), + .i_tdata({s_ctrlport_req_wr, s_ctrlport_req_rd, s_ctrlport_req_addr, s_ctrlport_req_data, + s_ctrlport_req_byte_en, s_ctrlport_req_has_time, s_ctrlport_req_time}), + .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), + .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]); + // Logic to pass cmd forward + assign exec = pending && (!cached_req_has_time || ontime || (EXEC_LATE_CMDS && late)); + assign consume = exec || late; + + assign m_ctrlport_req_wr = cached_req_wr & exec; + assign m_ctrlport_req_rd = cached_req_rd & exec; + assign m_ctrlport_req_addr = cached_req_addr; + assign m_ctrlport_req_data = cached_req_data; + assign m_ctrlport_req_byte_en = cached_req_byte_en; + + wire [1:0] resp_status = (late && !exec) ? AXIS_CTRL_STS_TSERR : m_ctrlport_resp_status; + axi_fifo_flop #(.WIDTH(2+32)) resp_cache_i ( + .clk(clk), .reset(rst), .clear(1'b0), + .i_tdata({resp_status, m_ctrlport_resp_data}), + .i_tvalid(m_ctrlport_resp_ack || (late && !exec)), .i_tready(), + .o_tdata({s_ctrlport_resp_status, s_ctrlport_resp_data}), + .o_tvalid(s_ctrlport_resp_ack), .o_tready(s_ctrlport_resp_ack), + .occupied(), .space() + ); + +endmodule // ctrlport_timer + |