1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 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
|