diff options
Diffstat (limited to 'fpga/usrp2/control_lib/settings_fifo_ctrl.v')
-rw-r--r-- | fpga/usrp2/control_lib/settings_fifo_ctrl.v | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/fpga/usrp2/control_lib/settings_fifo_ctrl.v b/fpga/usrp2/control_lib/settings_fifo_ctrl.v new file mode 100644 index 000000000..160112169 --- /dev/null +++ b/fpga/usrp2/control_lib/settings_fifo_ctrl.v @@ -0,0 +1,391 @@ +// +// Copyright 2012 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +// A settings and readback bus controlled via fifo36 interface + +module settings_fifo_ctrl + #( + parameter FIFO_DEPTH = 6, //64 entries depth + parameter PROT_DEST = 0, //protocol framer destination + parameter PROT_HDR = 1, //needs a protocol header? + parameter ACK_SID = 0 //stream ID for packet ACK + ) + ( + //clock and synchronous reset for all interfaces + input clock, input reset, input clear, + + //current system time + input [63:0] vita_time, + + //ready signal for multiple peripherals + input perfs_ready, + + //input fifo36 interface control + input [35:0] in_data, input in_valid, output in_ready, + + //output fifo36 interface status + output [35:0] out_data, output out_valid, input out_ready, + + //32-bit settings bus outputs + output strobe, output [7:0] addr, output [31:0] data, + + //16X 32-bit inputs for readback + input [31:0] word00, + input [31:0] word01, + input [31:0] word02, + input [31:0] word03, + input [31:0] word04, + input [31:0] word05, + input [31:0] word06, + input [31:0] word07, + input [31:0] word08, + input [31:0] word09, + input [31:0] word10, + input [31:0] word11, + input [31:0] word12, + input [31:0] word13, + input [31:0] word14, + input [31:0] word15, + + //debug output + output [31:0] debug + ); + + wire reading = in_valid && in_ready; + wire writing = out_valid && out_ready; + + //------------------------------------------------------------------ + //-- The command fifo: + //-- Stores an individual register access command per line. + //------------------------------------------------------------------ + wire [63:0] in_command_ticks, out_command_ticks; + wire [31:0] in_command_hdr, out_command_hdr; + wire [31:0] in_command_data, out_command_data; + wire in_command_has_time, out_command_has_time; + wire command_fifo_full, command_fifo_empty; + wire command_fifo_read, command_fifo_write; + + medfifo #(.WIDTH(129), .DEPTH(FIFO_DEPTH-4)) command_fifo ( + .clk(clock), .rst(reset), .clear(clear), + .datain({in_command_ticks, in_command_hdr, in_command_data, in_command_has_time}), + .dataout({out_command_ticks, out_command_hdr, out_command_data, out_command_has_time}), + .write(command_fifo_write), .full(command_fifo_full), //input interface + .empty(command_fifo_empty), .read(command_fifo_read) //output interface + ); + + //------------------------------------------------------------------ + //-- The result fifo: + //-- Stores an individual result of a command per line. + //------------------------------------------------------------------ + wire [31:0] in_result_hdr, out_result_hdr; + wire [31:0] in_result_data, out_result_data; + wire result_fifo_full, result_fifo_empty; + wire result_fifo_read, result_fifo_write; + + medfifo #(.WIDTH(64), .DEPTH(FIFO_DEPTH-4)) result_fifo ( + .clk(clock), .rst(reset), .clear(clear), + .datain({in_result_hdr, in_result_data}), + .dataout({out_result_hdr, out_result_data}), + .write(result_fifo_write), .full(result_fifo_full), //input interface + .empty(result_fifo_empty), .read(result_fifo_read) //output interface + ); + + //------------------------------------------------------------------ + //-- Input state machine: + //-- Read input packet and fill a command fifo entry. + //------------------------------------------------------------------ + localparam READ_LINE0 = 0; + localparam VITA_HDR = 1; + localparam VITA_SID = 2; + localparam VITA_CID0 = 3; + localparam VITA_CID1 = 4; + localparam VITA_TSI = 5; + localparam VITA_TSF0 = 6; + localparam VITA_TSF1 = 7; + localparam READ_HDR = 8; + localparam READ_DATA = 9; + localparam WAIT_EOF = 10; + localparam STORE_CMD = 11; + + reg [4:0] in_state; + + //holdover from current read inputs + reg [31:0] in_data_reg, in_hdr_reg; + reg [63:0] in_ticks_reg; + wire has_sid = in_data[28]; + wire has_cid = in_data[27]; + wire has_tsi = in_data[23:22] != 0; + wire has_tsf = in_data[21:20] != 0; + reg has_sid_reg, has_cid_reg, has_tsi_reg, has_tsf_reg; + + assign in_ready = (in_state < STORE_CMD); + assign command_fifo_write = (in_state == STORE_CMD); + assign in_command_ticks = in_ticks_reg; + assign in_command_data = in_data_reg; + assign in_command_hdr = in_hdr_reg; + assign in_command_has_time = has_tsf_reg; + + always @(posedge clock) begin + if (reset) begin + in_state <= READ_LINE0; + end + else begin + case (in_state) + + READ_LINE0: begin + if (reading/* && in_data[32]*/) in_state <= VITA_HDR; + end + + VITA_HDR: begin + if (reading) begin + if (has_sid) in_state <= VITA_SID; + else if (has_cid) in_state <= VITA_CID0; + else if (has_tsi) in_state <= VITA_TSI; + else if (has_tsf) in_state <= VITA_TSF0; + else in_state <= READ_HDR; + end + has_sid_reg <= has_sid; + has_cid_reg <= has_cid; + has_tsi_reg <= has_tsi; + has_tsf_reg <= has_tsf; + end + + VITA_SID: begin + if (reading) begin + if (has_cid_reg) in_state <= VITA_CID0; + else if (has_tsi_reg) in_state <= VITA_TSI; + else if (has_tsf_reg) in_state <= VITA_TSF0; + else in_state <= READ_HDR; + end + end + + VITA_CID0: begin + if (reading) in_state <= VITA_CID1; + end + + VITA_CID1: begin + if (reading) begin + if (has_tsi_reg) in_state <= VITA_TSI; + else if (has_tsf_reg) in_state <= VITA_TSF0; + else in_state <= READ_HDR; + end + end + + VITA_TSI: begin + if (reading) begin + if (has_tsf_reg) in_state <= VITA_TSF0; + else in_state <= READ_HDR; + end + end + + VITA_TSF0: begin + if (reading) in_state <= VITA_TSF1; + in_ticks_reg[63:32] <= in_data; + end + + VITA_TSF1: begin + if (reading) in_state <= READ_HDR; + in_ticks_reg[31:0] <= in_data; + end + + READ_HDR: begin + if (reading) in_state <= READ_DATA; + in_hdr_reg <= in_data[31:0]; + end + + READ_DATA: begin + if (reading) in_state <= (in_data[33])? STORE_CMD : WAIT_EOF; + in_data_reg <= in_data[31:0]; + end + + WAIT_EOF: begin + if (reading && in_data[33]) in_state <= STORE_CMD; + end + + STORE_CMD: begin + if (~command_fifo_full) in_state <= READ_LINE0; + end + + endcase //in_state + end + end + + //------------------------------------------------------------------ + //-- Command state machine: + //-- Read a command fifo entry, act on it, produce result. + //------------------------------------------------------------------ + localparam LOAD_CMD = 0; + localparam EVENT_CMD = 1; + + reg cmd_state; + reg [31:0] rb_data; + + reg [63:0] command_ticks_reg; + reg [31:0] command_hdr_reg; + reg [31:0] command_data_reg; + + wire now, early, late, too_early; + `ifndef FIFO_CTRL_NO_TIME + time_compare time_compare( + .time_now(vita_time), .trigger_time(command_ticks_reg), + .now(now), .early(early), .late(late), .too_early(too_early)); + `else + assign now = 0; + assign late = 1; + `endif + + //action occurs in the event state and when there is fifo space (should always be true) + //the third condition is that all peripherals in the perfs signal are ready/active high + //the fourth condition is that is an event time has been set, action is delayed until that time + wire time_ready = (out_command_has_time)? (now || late) : 1; + wire action = (cmd_state == EVENT_CMD) && ~result_fifo_full && perfs_ready && time_ready; + + assign command_fifo_read = action; + assign result_fifo_write = action; + assign in_result_hdr = command_hdr_reg; + assign in_result_data = rb_data; + + always @(posedge clock) begin + if (reset) begin + cmd_state <= LOAD_CMD; + end + else begin + case (cmd_state) + + LOAD_CMD: begin + if (~command_fifo_empty) cmd_state <= EVENT_CMD; + command_ticks_reg <= out_command_ticks; + command_hdr_reg <= out_command_hdr; + command_data_reg <= out_command_data; + end + + EVENT_CMD: begin // poking and peeking happens here! + if (action || clear) cmd_state <= LOAD_CMD; + end + + endcase //cmd_state + end + end + + //------------------------------------------------------------------ + //-- assign to settings bus interface + //------------------------------------------------------------------ + reg strobe_reg; + assign strobe = strobe_reg; + assign data = command_data_reg; + assign addr = command_hdr_reg[7:0]; + wire poke = command_hdr_reg[8]; + + always @(posedge clock) begin + if (reset || clear) strobe_reg <= 0; + else strobe_reg <= action && poke; + end + + //------------------------------------------------------------------ + //-- readback mux + //------------------------------------------------------------------ + always @(posedge clock) begin + case (out_command_hdr[3:0]) + 0 : rb_data <= word00; + 1 : rb_data <= word01; + 2 : rb_data <= word02; + 3 : rb_data <= word03; + 4 : rb_data <= word04; + 5 : rb_data <= word05; + 6 : rb_data <= word06; + 7 : rb_data <= word07; + 8 : rb_data <= word08; + 9 : rb_data <= word09; + 10: rb_data <= word10; + 11: rb_data <= word11; + 12: rb_data <= word12; + 13: rb_data <= word13; + 14: rb_data <= word14; + 15: rb_data <= word15; + endcase // case(addr_reg[3:0]) + end + + //------------------------------------------------------------------ + //-- Output state machine: + //-- Read a command fifo entry, act on it, produce ack packet. + //------------------------------------------------------------------ + localparam WRITE_PROT_HDR = 0; + localparam WRITE_VRT_HDR = 1; + localparam WRITE_VRT_SID = 2; + localparam WRITE_RB_HDR = 3; + localparam WRITE_RB_DATA = 4; + + //the state for the start of packet condition + localparam WRITE_PKT_HDR = (PROT_HDR)? WRITE_PROT_HDR : WRITE_VRT_HDR; + + reg [2:0] out_state; + + assign out_valid = ~result_fifo_empty; + assign result_fifo_read = out_data[33] && writing; + + always @(posedge clock) begin + if (reset) begin + out_state <= WRITE_PKT_HDR; + end + else if (writing && out_data[33]) begin + out_state <= WRITE_PKT_HDR; + end + else if (writing) begin + out_state <= out_state + 1; + end + end + + //------------------------------------------------------------------ + //-- assign to output fifo interface + //------------------------------------------------------------------ + wire [31:0] prot_hdr; + assign prot_hdr[15:0] = 16; //bytes in proceeding vita packet + assign prot_hdr[16] = 1; //yes frame + assign prot_hdr[18:17] = PROT_DEST; + assign prot_hdr[31:19] = 0; //nothing + + reg [31:0] out_data_int; + always @* begin + case (out_state) + WRITE_PROT_HDR: out_data_int <= prot_hdr; + WRITE_VRT_HDR: out_data_int <= {12'b010100000000, out_result_hdr[19:16], 2'b0, prot_hdr[15:2]}; + WRITE_VRT_SID: out_data_int <= ACK_SID; + WRITE_RB_HDR: out_data_int <= out_result_hdr; + WRITE_RB_DATA: out_data_int <= out_result_data; + default: out_data_int <= 0; + endcase //state + end + + assign out_data[35:34] = 2'b0; + assign out_data[33] = (out_state == WRITE_RB_DATA); + assign out_data[32] = (out_state == WRITE_PKT_HDR); + assign out_data[31:0] = out_data_int; + + //------------------------------------------------------------------ + //-- debug outputs + //------------------------------------------------------------------ + assign debug = { + in_state, out_state, //8 + in_valid, in_ready, in_data[33:32], //4 + out_valid, out_ready, out_data[33:32], //4 + command_fifo_empty, command_fifo_full, //2 + command_fifo_read, command_fifo_write, //2 + addr, //8 + strobe_reg, strobe, poke, out_command_has_time //4 + }; + +endmodule //settings_fifo_ctrl |