1//
2// Copyright 2012 Ettus Research LLC
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16//
17
18// A settings and readback bus controlled via fifo36 interface
19
20module settings_fifo_ctrl
21    #(
22        parameter XPORT_HDR = 1, //extra transport hdr line
23        parameter PROT_DEST = 0, //protocol framer destination
24        parameter PROT_HDR = 1, //needs a protocol header?
25        parameter ACK_SID = 0 //stream ID for packet ACK
26    )
27    (
28        //clock and synchronous reset for all interfaces
29        input clock, input reset, input clear,
30
31        //current system time
32        input [63:0] vita_time,
33
34        //ready signal for multiple peripherals
35        input perfs_ready,
36
37        //input fifo36 interface control
38        input [35:0] in_data, input in_valid, output in_ready,
39
40        //output fifo36 interface status
41        output [35:0] out_data, output out_valid, input out_ready,
42
43        //32-bit settings bus outputs
44        output strobe, output [7:0] addr, output [31:0] data,
45
46        //16X 32-bit inputs for readback
47        input [31:0] word00,
48        input [31:0] word01,
49        input [31:0] word02,
50        input [31:0] word03,
51        input [31:0] word04,
52        input [31:0] word05,
53        input [31:0] word06,
54        input [31:0] word07,
55        input [31:0] word08,
56        input [31:0] word09,
57        input [31:0] word10,
58        input [31:0] word11,
59        input [31:0] word12,
60        input [31:0] word13,
61        input [31:0] word14,
62        input [31:0] word15,
63
64        //debug output
65        output [31:0] debug
66    );
67
68    wire reading = in_valid && in_ready;
69    wire writing = out_valid && out_ready;
70
71    //------------------------------------------------------------------
72    //-- The command fifo:
73    //-- Stores an individual register access command per line.
74    //------------------------------------------------------------------
75    wire [63:0] in_command_ticks, out_command_ticks;
76    wire [31:0] in_command_hdr, out_command_hdr;
77    wire [31:0] in_command_data, out_command_data;
78    wire in_command_has_time, out_command_has_time;
79    wire command_fifo_full, command_fifo_empty;
80    wire command_fifo_read, command_fifo_write;
81
82    wire [128:0] fifo2_datain, fifo3_datain, fifo4_datain;
83    wire fifo1_empty, fifo2_empty, fifo3_empty;
84    wire fifo2_full, fifo3_full, fifo4_full;
85    wire fifo1_to_fifo2, fifo2_to_fifo3, fifo3_to_fifo4;
86
87    shortfifo #(.WIDTH(129)) command_fifo (
88        .clk(clock), .rst(reset), .clear(clear),
89        .datain({in_command_ticks, in_command_hdr, in_command_data, in_command_has_time}),
90        .dataout(fifo2_datain),
91        .write(command_fifo_write), .full(command_fifo_full), //input interface
92        .empty(fifo1_empty), .read(fifo1_to_fifo2)  //output interface
93    );
94
95    shortfifo #(.WIDTH(129)) command_fifo2 (
96        .clk(clock), .rst(reset), .clear(clear),
97        .datain(fifo2_datain),
98        .dataout(fifo3_datain),
99        .write(fifo1_to_fifo2), .full(fifo2_full), //input interface
100        .empty(fifo2_empty), .read(fifo2_to_fifo3)  //output interface
101    );
102
103    shortfifo #(.WIDTH(129)) command_fifo3 (
104        .clk(clock), .rst(reset), .clear(clear),
105        .datain(fifo3_datain),
106        .dataout(fifo4_datain),
107        .write(fifo2_to_fifo3), .full(fifo3_full), //input interface
108        .empty(fifo3_empty), .read(fifo3_to_fifo4)  //output interface
109    );
110
111    shortfifo #(.WIDTH(129)) command_fifo4 (
112        .clk(clock), .rst(reset), .clear(clear),
113        .datain(fifo4_datain),
114        .dataout({out_command_ticks, out_command_hdr, out_command_data, out_command_has_time}),
115        .write(fifo3_to_fifo4), .full(fifo4_full), //input interface
116        .empty(command_fifo_empty), .read(command_fifo_read)  //output interface
117    );
118
119    assign fifo1_to_fifo2 = ~fifo2_full & ~fifo1_empty;
120    assign fifo2_to_fifo3 = ~fifo3_full & ~fifo2_empty;
121    assign fifo3_to_fifo4 = ~fifo4_full & ~fifo3_empty;
122
123    //------------------------------------------------------------------
124    //-- The result fifo:
125    //-- Stores an individual result of a command per line.
126    //------------------------------------------------------------------
127    wire [31:0] in_result_hdr, out_result_hdr;
128    wire [31:0] in_result_data, out_result_data;
129    wire result_fifo_full, result_fifo_empty;
130    wire result_fifo_read, result_fifo_write;
131
132    shortfifo #(.WIDTH(64)) result_fifo (
133        .clk(clock), .rst(reset), .clear(clear),
134        .datain({in_result_hdr, in_result_data}),
135        .dataout({out_result_hdr, out_result_data}),
136        .write(result_fifo_write), .full(result_fifo_full), //input interface
137        .empty(result_fifo_empty), .read(result_fifo_read)  //output interface
138    );
139
140    //------------------------------------------------------------------
141    //-- Input state machine:
142    //-- Read input packet and fill a command fifo entry.
143    //------------------------------------------------------------------
144    localparam READ_LINE0     = 0;
145    localparam VITA_HDR       = 1;
146    localparam VITA_SID       = 2;
147    localparam VITA_CID0      = 3;
148    localparam VITA_CID1      = 4;
149    localparam VITA_TSI       = 5;
150    localparam VITA_TSF0      = 6;
151    localparam VITA_TSF1      = 7;
152    localparam READ_HDR       = 8;
153    localparam READ_DATA      = 9;
154    localparam WAIT_EOF       = 10;
155    localparam STORE_CMD      = 11;
156
157    localparam START_STATE = (XPORT_HDR)? READ_LINE0 : VITA_HDR;
158
159    reg [4:0] in_state;
160
161    //holdover from current read inputs
162    reg [31:0] in_data_reg, in_hdr_reg;
163    reg [63:0] in_ticks_reg;
164    wire has_sid = in_data[28];
165    wire has_cid = in_data[27];
166    wire has_tsi = in_data[23:22] != 0;
167    wire has_tsf = in_data[21:20] != 0;
168    reg has_sid_reg, has_cid_reg, has_tsi_reg, has_tsf_reg;
169
170    assign in_ready = (in_state < STORE_CMD);
171    assign command_fifo_write  = (in_state == STORE_CMD);
172    assign in_command_ticks    = in_ticks_reg;
173    assign in_command_data     = in_data_reg;
174    assign in_command_hdr      = in_hdr_reg;
175    assign in_command_has_time = has_tsf_reg;
176
177    always @(posedge clock) begin
178        if (reset) begin
179            in_state <= START_STATE;
180        end
181        else begin
182            case (in_state)
183
184            READ_LINE0: begin
185                if (reading) in_state <= VITA_HDR;
186            end
187
188            VITA_HDR: begin
189                if (reading) begin
190                    if      (has_sid) in_state <= VITA_SID;
191                    else if (has_cid) in_state <= VITA_CID0;
192                    else if (has_tsi) in_state <= VITA_TSI;
193                    else if (has_tsf) in_state <= VITA_TSF0;
194                    else              in_state <= READ_HDR;
195                end
196                has_sid_reg <= has_sid;
197                has_cid_reg <= has_cid;
198                has_tsi_reg <= has_tsi;
199                has_tsf_reg <= has_tsf;
200            end
201
202            VITA_SID: begin
203                if (reading) begin
204                    if      (has_cid_reg) in_state <= VITA_CID0;
205                    else if (has_tsi_reg) in_state <= VITA_TSI;
206                    else if (has_tsf_reg) in_state <= VITA_TSF0;
207                    else                  in_state <= READ_HDR;
208                end
209            end
210
211            VITA_CID0: begin
212                if (reading) in_state <= VITA_CID1;
213            end
214
215            VITA_CID1: begin
216                if (reading) begin
217                    if      (has_tsi_reg) in_state <= VITA_TSI;
218                    else if (has_tsf_reg) in_state <= VITA_TSF0;
219                    else                  in_state <= READ_HDR;
220                end
221            end
222
223            VITA_TSI: begin
224                if (reading) begin
225                    if (has_tsf_reg) in_state <= VITA_TSF0;
226                    else             in_state <= READ_HDR;
227                end
228            end
229
230            VITA_TSF0: begin
231                if (reading) in_state <= VITA_TSF1;
232                in_ticks_reg[63:32] <= in_data;
233            end
234
235            VITA_TSF1: begin
236                if (reading) in_state <= READ_HDR;
237                in_ticks_reg[31:0] <= in_data;
238            end
239
240            READ_HDR: begin
241                if (reading) in_state <= READ_DATA;
242                in_hdr_reg <= in_data[31:0];
243            end
244
245            READ_DATA: begin
246                if (reading) in_state <= (in_data[33])? STORE_CMD : WAIT_EOF;
247                in_data_reg <= in_data[31:0];
248            end
249
250            WAIT_EOF: begin
251                if (reading && in_data[33]) in_state <= STORE_CMD;
252            end
253
254            STORE_CMD: begin
255                if (~command_fifo_full) in_state <= START_STATE;
256            end
257
258            endcase //in_state
259        end
260    end
261
262    //------------------------------------------------------------------
263    //-- Command state machine:
264    //-- Read a command fifo entry, act on it, produce result.
265    //------------------------------------------------------------------
266    localparam LOAD_CMD    = 0;
267    localparam EVENT_CMD   = 1;
268
269    reg cmd_state;
270    reg [31:0] rb_data;
271
272    reg [63:0] command_ticks_reg;
273    reg [31:0] command_hdr_reg;
274    reg [31:0] command_data_reg;
275
276    reg [63:0] vita_time_reg;
277    always @(posedge clock)
278        vita_time_reg <= vita_time;
279
280    wire late;
281    `ifndef FIFO_CTRL_NO_TIME
282    time_compare time_compare(
283        .time_now(vita_time_reg), .trigger_time(command_ticks_reg), .late(late));
284    `else
285    assign late = 1;
286    `endif
287
288    //action occurs in the event state and when there is fifo space (should always be true)
289    //the third condition is that all peripherals in the perfs signal are ready/active high
290    //the fourth condition is that is an event time has been set, action is delayed until that time
291    wire time_ready = (out_command_has_time)? late : 1;
292    wire action = (cmd_state == EVENT_CMD) && ~result_fifo_full && perfs_ready && time_ready;
293
294    assign command_fifo_read = action;
295    assign result_fifo_write = action;
296    assign in_result_hdr = command_hdr_reg;
297    assign in_result_data = rb_data;
298
299    always @(posedge clock) begin
300        if (reset) begin
301            cmd_state <= LOAD_CMD;
302        end
303        else begin
304            case (cmd_state)
305
306            LOAD_CMD: begin
307                if (~command_fifo_empty) cmd_state <= EVENT_CMD;
308                command_ticks_reg <= out_command_ticks;
309                command_hdr_reg <= out_command_hdr;
310                command_data_reg <= out_command_data;
311            end
312
313            EVENT_CMD: begin // poking and peeking happens here!
314                if (action || clear) cmd_state <= LOAD_CMD;
315            end
316
317            endcase //cmd_state
318        end
319    end
320
321    //------------------------------------------------------------------
322    //-- assign to settings bus interface
323    //------------------------------------------------------------------
324    reg strobe_reg;
325    assign strobe = strobe_reg;
326    assign data = command_data_reg;
327    assign addr = command_hdr_reg[7:0];
328    wire poke = command_hdr_reg[8];
329
330    always @(posedge clock) begin
331        if (reset || clear) strobe_reg <= 0;
332        else                strobe_reg <= action && poke;
333    end
334
335    //------------------------------------------------------------------
336    //-- readback mux
337    //------------------------------------------------------------------
338    always @(posedge clock) begin
339        case (out_command_hdr[3:0])
340            0 : rb_data <= word00;
341            1 : rb_data <= word01;
342            2 : rb_data <= word02;
343            3 : rb_data <= word03;
344            4 : rb_data <= word04;
345            5 : rb_data <= word05;
346            6 : rb_data <= word06;
347            7 : rb_data <= word07;
348            8 : rb_data <= word08;
349            9 : rb_data <= word09;
350            10: rb_data <= word10;
351            11: rb_data <= word11;
352            12: rb_data <= word12;
353            13: rb_data <= word13;
354            14: rb_data <= word14;
355            15: rb_data <= word15;
356        endcase // case(addr_reg[3:0])
357    end
358
359    //------------------------------------------------------------------
360    //-- Output state machine:
361    //-- Read a command fifo entry, act on it, produce ack packet.
362    //------------------------------------------------------------------
363    localparam WRITE_PROT_HDR = 0;
364    localparam WRITE_VRT_HDR  = 1;
365    localparam WRITE_VRT_SID  = 2;
366    localparam WRITE_RB_HDR   = 3;
367    localparam WRITE_RB_DATA  = 4;
368
369    //the state for the start of packet condition
370    localparam WRITE_PKT_HDR = (PROT_HDR)? WRITE_PROT_HDR : WRITE_VRT_HDR;
371
372    reg [2:0] out_state;
373
374    assign out_valid = ~result_fifo_empty;
375    assign result_fifo_read = out_data[33] && writing;
376
377    always @(posedge clock) begin
378        if (reset) begin
379            out_state <= WRITE_PKT_HDR;
380        end
381        else if (writing && out_data[33]) begin
382            out_state <= WRITE_PKT_HDR;
383        end
384        else if (writing) begin
385            out_state <= out_state + 1;
386        end
387    end
388
389    //------------------------------------------------------------------
390    //-- assign to output fifo interface
391    //------------------------------------------------------------------
392    wire [31:0] prot_hdr;
393    assign prot_hdr[15:0] = 16; //bytes in proceeding vita packet
394    assign prot_hdr[16] = 1; //yes frame
395    assign prot_hdr[18:17] = PROT_DEST;
396    assign prot_hdr[31:19] = 0; //nothing
397
398    reg [31:0] out_data_int;
399    always @* begin
400        case (out_state)
401            WRITE_PROT_HDR: out_data_int <= prot_hdr;
402            WRITE_VRT_HDR:  out_data_int <= {12'b010100000000, out_result_hdr[19:16], 2'b0, prot_hdr[15:2]};
403            WRITE_VRT_SID:  out_data_int <= ACK_SID;
404            WRITE_RB_HDR:   out_data_int <= out_result_hdr;
405            WRITE_RB_DATA:  out_data_int <= out_result_data;
406            default:        out_data_int <= 0;
407        endcase //state
408    end
409
410    assign out_data[35:34] = 2'b0;
411    assign out_data[33] = (out_state == WRITE_RB_DATA);
412    assign out_data[32] = (out_state == WRITE_PKT_HDR);
413    assign out_data[31:0] = out_data_int;
414
415    //------------------------------------------------------------------
416    //-- debug outputs
417    //------------------------------------------------------------------
418    assign debug = {
419        in_state, out_state, //8
420        in_valid, in_ready, in_data[33:32], //4
421        out_valid, out_ready, out_data[33:32], //4
422        command_fifo_empty, command_fifo_full, //2
423        command_fifo_read, command_fifo_write, //2
424        addr, //8
425        strobe_reg, strobe, poke, out_command_has_time //4
426    };
427
428endmodule //settings_fifo_ctrl
429