1// 2// Copyright 2018 Ettus Research, A National Instruments Company 3// 4// SPDX-License-Identifier: LGPL-3.0-or-later 5// 6// Module: ctrlport_timer 7// Description: 8// The Control-Port timer module converts an asynchronous timed 9// transaction into a synchronous blocking transaction. This 10// module will use the input req_has_time and req_time fields and 11// produce an output transaction that will execute when the requested 12// time is current. The module does not pass the has_time and time 13// signals out because they are no longer relevant. The current time 14// is an input to this module, and must be a monotonic counter that 15// updates every time the time strobe is asserted. 16// 17// Parameters: 18// - PRECISION_BITS : The number of bits to ignore when performing a 19// time comparison to determine execution time. 20// - EXEC_LATE_CMDS : If a command is late, a TSERR response is sent. 21// If EXEC_LATE_CMDS = 1, then the late command will 22// be passed to the output regardless of the TSERR. 23// 24// Signals: 25// - time_now* : The time_now signal is the current time and the stb 26// signal indicates that the time_now is valid. 27// - s_ctrlport_* : The slave Control-Port bus. 28// This must have the has_time and time signals. 29// - m_ctrlport_* : The master Control-Port bus. 30// This will not have the has_time and time signals. 31 32module ctrlport_timer #( 33 parameter PRECISION_BITS = 0, 34 parameter [0:0] EXEC_LATE_CMDS = 0 35)( 36 // Clocks and Resets 37 input wire clk, 38 input wire rst, 39 // Timestamp (synchronous to clk) 40 input wire [63:0] time_now, 41 input wire time_now_stb, 42 // Control Port Master (Request) 43 input wire s_ctrlport_req_wr, 44 input wire s_ctrlport_req_rd, 45 input wire [19:0] s_ctrlport_req_addr, 46 input wire [31:0] s_ctrlport_req_data, 47 input wire [3:0] s_ctrlport_req_byte_en, 48 input wire s_ctrlport_req_has_time, 49 input wire [63:0] s_ctrlport_req_time, 50 // Control Port Slave (Response) 51 output wire s_ctrlport_resp_ack, 52 output wire [1:0] s_ctrlport_resp_status, 53 output wire [31:0] s_ctrlport_resp_data, 54 // Control Port Master (Request) 55 output wire m_ctrlport_req_wr, 56 output wire m_ctrlport_req_rd, 57 output wire [19:0] m_ctrlport_req_addr, 58 output wire [31:0] m_ctrlport_req_data, 59 output wire [3:0] m_ctrlport_req_byte_en, 60 // Control Port Master (Response) 61 input wire m_ctrlport_resp_ack, 62 input wire [1:0] m_ctrlport_resp_status, 63 input wire [31:0] m_ctrlport_resp_data 64); 65 66 `include "../core/rfnoc_chdr_utils.vh" 67 `include "../core/rfnoc_axis_ctrl_utils.vh" 68 69 // Control triggers: 70 // - pending: A command is waiting on the input port 71 // - ontime: The timed command is due for execution (on time) 72 // - late: The timed command is late 73 // - exec: Execute the command (pass it to the output) 74 // - consume: Consume the input command 75 wire pending, ontime, late, exec, consume; 76 // Cached values for input command 77 wire cached_req_wr, cached_req_rd; 78 wire [19:0] cached_req_addr; 79 wire [31:0] cached_req_data; 80 wire [3:0] cached_req_byte_en; 81 wire cached_req_has_time; 82 wire [63:0] cached_req_time; 83 84 axi_fifo_flop #(.WIDTH(1+1+20+32+4+1+64)) req_cache_i ( 85 .clk(clk), .reset(rst), .clear(1'b0), 86 .i_tdata({s_ctrlport_req_wr, s_ctrlport_req_rd, s_ctrlport_req_addr, s_ctrlport_req_data, 87 s_ctrlport_req_byte_en, s_ctrlport_req_has_time, s_ctrlport_req_time}), 88 .i_tvalid(s_ctrlport_req_wr | s_ctrlport_req_rd), .i_tready(), 89 .o_tdata({cached_req_wr, cached_req_rd, cached_req_addr, cached_req_data, 90 cached_req_byte_en, cached_req_has_time, cached_req_time}), 91 .o_tvalid(pending), .o_tready(consume), 92 .occupied(), .space() 93 ); 94 95 // Command is on time 96 assign ontime = cached_req_has_time && pending && time_now_stb && 97 (cached_req_time[63:PRECISION_BITS] == time_now[63:PRECISION_BITS]); 98 // Command is late 99 assign late = cached_req_has_time && pending && time_now_stb && 100 (cached_req_time[63:PRECISION_BITS] < time_now[63:PRECISION_BITS]); 101 // Logic to pass cmd forward 102 assign exec = pending && (!cached_req_has_time || ontime || (EXEC_LATE_CMDS && late)); 103 assign consume = exec || late; 104 105 assign m_ctrlport_req_wr = cached_req_wr & exec; 106 assign m_ctrlport_req_rd = cached_req_rd & exec; 107 assign m_ctrlport_req_addr = cached_req_addr; 108 assign m_ctrlport_req_data = cached_req_data; 109 assign m_ctrlport_req_byte_en = cached_req_byte_en; 110 111 wire [1:0] resp_status = (late && !exec) ? AXIS_CTRL_STS_TSERR : m_ctrlport_resp_status; 112 axi_fifo_flop #(.WIDTH(2+32)) resp_cache_i ( 113 .clk(clk), .reset(rst), .clear(1'b0), 114 .i_tdata({resp_status, m_ctrlport_resp_data}), 115 .i_tvalid(m_ctrlport_resp_ack || (late && !exec)), .i_tready(), 116 .o_tdata({s_ctrlport_resp_status, s_ctrlport_resp_data}), 117 .o_tvalid(s_ctrlport_resp_ack), .o_tready(s_ctrlport_resp_ack), 118 .occupied(), .space() 119 ); 120 121endmodule // ctrlport_timer 122 123