diff options
Diffstat (limited to 'fpga/usrp3/lib/control/settings_bus_timed_2clk.v')
-rw-r--r-- | fpga/usrp3/lib/control/settings_bus_timed_2clk.v | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/control/settings_bus_timed_2clk.v b/fpga/usrp3/lib/control/settings_bus_timed_2clk.v new file mode 100644 index 000000000..2b62ffd26 --- /dev/null +++ b/fpga/usrp3/lib/control/settings_bus_timed_2clk.v @@ -0,0 +1,170 @@ +// +// Copyright 2018 Ettus Research, A National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: settings_bus_timed_2clk +// Description: +// - Stores settings bus transaction in a FIFO and +// releases them based on VITA time input +// - Also moves the settings bus to the timebase +// clock domain +// + +module settings_bus_timed_2clk #( + parameter SR_AWIDTH = 8, + parameter SR_DWIDTH = 32, + parameter RB_AWIDTH = 8, + parameter RB_DWIDTH = 64, + parameter TIMED_CMDS_EN = 0 +) ( + input sb_clk, // Settings bus clock + input sb_rst, // Reset (sb_clk) + input tb_clk, // Timebase clock + input tb_rst, // Reset (tb_clk) + + input [63:0] vita_time, // Current timebase time + + input s_set_stb, // Settings bus strobe + input [SR_AWIDTH-1:0] s_set_addr, // Settings address + input [SR_DWIDTH-1:0] s_set_data, // Settings data + input s_set_has_time, // Is this a timed command? + input [63:0] s_set_time, // Command time + output s_set_pending, // Is settings transaction pending? + input [RB_AWIDTH-1:0] s_rb_addr, // Readback address + output s_rb_stb, // Readback data strobe + output [RB_DWIDTH-1:0] s_rb_data, // Readback data value + + output m_set_stb, // Settings bus strobe + output [SR_AWIDTH-1:0] m_set_addr, // Settings address + output [SR_DWIDTH-1:0] m_set_data, // Settings data + output m_set_has_time, // Is this a timed command? + output [63:0] m_set_time, // Command time + input m_set_pending, // Is settings transaction pending? + output [RB_AWIDTH-1:0] m_rb_addr, // Readback address + input m_rb_stb, // Readback data strobe + input [RB_DWIDTH-1:0] m_rb_data // Readback data value +); + + // States for input and output state machines + localparam [2:0] ST_IDLE = 3'd0; // Nothing is happening on the bus + localparam [2:0] ST_SET_ISSUED = 3'd1; // A settings transaction has been issued + localparam [2:0] ST_SET_PENDING = 3'd2; // A settings transaction is pending + localparam [2:0] ST_RB_PENDING = 3'd3; // Waiting for readback data + localparam [2:0] ST_RB_DONE = 3'd4; // Readback data is valid + + wire rb_valid; + + // Input state machine + reg [2:0] in_state = ST_IDLE; + always @(posedge sb_clk) begin + if (sb_rst) begin + in_state <= ST_IDLE; + end else begin + case (in_state) + ST_IDLE: begin + if (s_set_stb) begin + in_state <= ST_SET_PENDING; + end + end + ST_SET_PENDING: begin + if (rb_valid) begin + in_state <= ST_RB_DONE; + end + end + ST_RB_DONE: begin + in_state <= ST_IDLE; + end + default: begin + in_state <= ST_IDLE; + end + endcase + end + end + assign s_set_pending = (in_state == ST_SET_PENDING); + assign s_rb_stb = (in_state == ST_RB_DONE); + + // Clock crossing FIFO (settings) + // TODO: Look into a more efficient implementation for a single element + // clock crossing FIFO. + wire set_pending, set_finished; + axi_fifo_2clk #( + .WIDTH(SR_AWIDTH+SR_DWIDTH+1+64+RB_AWIDTH), .SIZE(0) + ) sb_2clk_fifo_i ( + .i_aclk(sb_clk), .reset(sb_rst), + .i_tdata({s_set_addr, s_set_data, s_set_has_time, s_set_time, s_rb_addr}), + .i_tvalid(s_set_stb), .i_tready(/* Ignored: FIFO may not have an exact size*/), + .o_aclk(tb_clk), + .o_tdata({m_set_addr, m_set_data, m_set_has_time, m_set_time, m_rb_addr}), + .o_tvalid(set_pending), .o_tready(set_finished) + ); + + // Time compare logic + // If ~has_time then pass the transaction through, otherwise wait for time + // to tick up to command time + wire now, late; + wire go = ((TIMED_CMDS_EN == 1) && m_set_has_time) ? (now | late) : 1'b1; + + // If this is a timed command then vita_time == m_set_time one cycle before + // strobe is asserted i.e. timed strobe assertion has a one cycle latency + time_compare time_compare ( + .clk(tb_clk), .reset(tb_rst), + .time_now(vita_time), .trigger_time(m_set_time), + .now(now), .early(), .late(late), .too_early() + ); + + // Clock crossing FIFO (readback) + reg [RB_DWIDTH-1:0] cached_rb_data; + axi_fifo_2clk #( + .WIDTH(RB_DWIDTH), .SIZE(0) + ) rbdata_2clk_fifo_i ( + .reset(tb_rst), + .i_aclk(tb_clk), .i_tdata(cached_rb_data), .i_tvalid(set_finished), .i_tready(), + .o_aclk(sb_clk), .o_tdata(s_rb_data), .o_tvalid(rb_valid), .o_tready(s_rb_stb) + ); + + // Output state machine + reg [2:0] out_state = ST_IDLE; + always @(posedge tb_clk) begin + if (tb_rst) begin + out_state <= ST_IDLE; + end else begin + case (out_state) + ST_IDLE: begin + if (go & set_pending) begin + out_state <= ST_SET_ISSUED; + end + end + ST_SET_ISSUED: begin + out_state <= ST_SET_PENDING; + end + ST_SET_PENDING: begin + if (~m_set_pending) begin + if (m_rb_stb) begin + out_state <= ST_RB_DONE; + cached_rb_data <= m_rb_data; + end else begin + out_state <= ST_RB_PENDING; + end + end + end + ST_RB_PENDING: begin + if (m_rb_stb) begin + out_state <= ST_RB_DONE; + cached_rb_data <= m_rb_data; + end + end + ST_RB_DONE: begin + out_state <= ST_IDLE; + end + default: begin + out_state <= ST_IDLE; + end + endcase + end + end + + assign m_set_stb = (out_state == ST_SET_ISSUED); + assign set_finished = (out_state == ST_RB_DONE); + +endmodule |