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
|