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
|
// Radio Control Processor
// Accepts compressed vita extension context packets of the following form:
// { VITA Compressed Header, Stream ID }
// { Optional 64 bit time }
// { 16'h0, setting bus address [15:0], setting [31:0] }
//
// If there is a timestamp, packet is held until that time comes.
// Goes immediately if there is no timestamp or if time has passed.
// Sends out setting to setting bus, and then generates a response packet
// with the same sequence number, the src/dest swapped streamid, and the actual time
// the setting was sent.
//
// Note -- if t0 is the requested time, the actual send time on the setting bus is t0 + 1 cycle.
// Note 2 -- if t1 is the actual time the setting bus, t1+2 is the reported time.
module radio_ctrl_proc
(input clk, input reset, input clear,
input [63:0] ctrl_tdata, input ctrl_tlast, input ctrl_tvalid, output reg ctrl_tready,
output reg [63:0] resp_tdata, output reg resp_tlast, output resp_tvalid, input resp_tready,
input [63:0] vita_time,
output set_stb, output [7:0] set_addr, output [31:0] set_data,
input ready,
input [63:0] readback,
output [31:0] debug);
localparam RC_HEAD = 4'd0;
localparam RC_TIME = 4'd1;
localparam RC_DATA = 4'd2;
localparam RC_DUMP = 4'd3;
localparam RC_RESP_HEAD = 4'd4;
localparam RC_RESP_TIME = 4'd5;
localparam RC_RESP_DATA = 4'd6;
wire IS_EC = ctrl_tdata[63];
wire HAS_TIME = ctrl_tdata[61];
reg HAS_TIME_reg;
reg [3:0] rc_state;
reg [63:0] cmd_time;
wire now, late, go;
reg [11:0] seqnum;
reg [31:0] sid;
always @(posedge clk)
if(reset)
begin
rc_state <= RC_HEAD;
HAS_TIME_reg <= 1'b0;
sid <= 32'd0;
seqnum <= 12'd0;
end
else
case(rc_state)
RC_HEAD :
if(ctrl_tvalid)
begin
sid <= ctrl_tdata[31:0];
seqnum <= ctrl_tdata[59:48];
HAS_TIME_reg <= HAS_TIME;
if(IS_EC)
if(HAS_TIME)
rc_state <= RC_TIME;
else
rc_state <= RC_DATA;
else
if(~ctrl_tlast)
rc_state <= RC_DUMP;
end
RC_TIME :
if(ctrl_tvalid)
if(ctrl_tlast)
rc_state <= RC_RESP_HEAD;
else if(go)
rc_state <= RC_DATA;
RC_DATA :
if(ctrl_tvalid)
if(ready)
if(ctrl_tlast)
rc_state <= RC_RESP_HEAD;
else
rc_state <= RC_DUMP;
RC_DUMP :
if(ctrl_tvalid)
if(ctrl_tlast)
rc_state <= RC_RESP_HEAD;
RC_RESP_HEAD :
if(resp_tready)
rc_state <= RC_RESP_TIME;
RC_RESP_TIME :
if(resp_tready)
rc_state <= RC_RESP_DATA;
RC_RESP_DATA:
if(resp_tready)
rc_state <= RC_HEAD;
default :
rc_state <= RC_HEAD;
endcase // case (rc_state)
always @*
case (rc_state)
RC_HEAD : ctrl_tready <= 1'b1;
RC_TIME : ctrl_tready <= ctrl_tlast | go;
RC_DATA : ctrl_tready <= ready;
RC_DUMP : ctrl_tready <= 1'b1;
default : ctrl_tready <= 1'b0;
endcase // case (rc_state)
time_compare time_compare
(.clk(clk), .reset(reset), .time_now(vita_time), .trigger_time(ctrl_tdata), .now(now), .early(), .late(late), .too_early());
assign go = now | late;
assign set_stb = (rc_state == RC_DATA) & ready & ctrl_tvalid;
assign set_addr = ctrl_tdata[39:32];
assign set_data = ctrl_tdata[31:0];
always @*
case (rc_state)
RC_RESP_HEAD : { resp_tlast, resp_tdata } <= {1'b0, 4'hA, seqnum, 16'd24, sid[15:0], sid[31:16] };
RC_RESP_TIME : { resp_tlast, resp_tdata } <= {1'b0, vita_time};
RC_RESP_DATA : { resp_tlast, resp_tdata } <= {1'b1, readback};
default : { resp_tlast, resp_tdata } <= 65'h0;
endcase // case (rc_state)
assign resp_tvalid = (rc_state == RC_RESP_HEAD) | (rc_state == RC_RESP_TIME) | (rc_state == RC_RESP_DATA);
endmodule // radio_ctrl_proc
|