mirror of
https://github.com/fairwaves/UHD-Fairwaves.git
synced 2025-11-02 04:53:25 +00:00
413 lines
14 KiB
Verilog
413 lines
14 KiB
Verilog
//
|
|
// 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 XPORT_HDR = 1, //extra transport hdr line
|
|
parameter PROT_DEST = 0, //protocol framer destination
|
|
parameter PROT_HDR = 1, //needs a protocol header?
|
|
parameter ACK_SID = 0, //stream ID for packet ACK
|
|
parameter DEPTH = 6 //size of fifo in addr bit width
|
|
)
|
|
(
|
|
//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 command_fifo_full, command_fifo_empty;
|
|
wire command_fifo_read, command_fifo_write;
|
|
wire [15:0] command_fifo_occupied;
|
|
|
|
longfifo #(.WIDTH(128), .SIZE(DEPTH)) command_fifo (
|
|
.clk(clock), .rst(reset), .clear(clear),
|
|
.datain({in_command_ticks, in_command_hdr, in_command_data}),
|
|
.dataout({out_command_ticks, out_command_hdr, out_command_data}),
|
|
.write(command_fifo_write), .full(command_fifo_full), //input interface
|
|
.empty(command_fifo_empty), .read(command_fifo_read), //output interface
|
|
.occupied(command_fifo_occupied)
|
|
);
|
|
|
|
//------------------------------------------------------------------
|
|
//-- 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;
|
|
wire [15:0] result_fifo_occupied;
|
|
|
|
longfifo #(.WIDTH(64), .SIZE(DEPTH)) 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
|
|
.occupied(result_fifo_occupied)
|
|
);
|
|
|
|
//------------------------------------------------------------------
|
|
//-- 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;
|
|
|
|
localparam START_STATE = (XPORT_HDR)? READ_LINE0 : VITA_HDR;
|
|
|
|
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;
|
|
|
|
always @(posedge clock) begin
|
|
if (reset) begin
|
|
in_state <= START_STATE;
|
|
end
|
|
else begin
|
|
case (in_state)
|
|
|
|
READ_LINE0: begin
|
|
if (reading) 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 <= START_STATE;
|
|
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;
|
|
|
|
reg [63:0] vita_time_reg;
|
|
always @(posedge clock)
|
|
vita_time_reg <= vita_time;
|
|
|
|
wire late, now;
|
|
`ifndef FIFO_CTRL_NO_TIME
|
|
time_compare time_compare(
|
|
.time_now(vita_time_reg), .trigger_time(command_ticks_reg), .late(late), .now(now));
|
|
`else
|
|
assign late = 1;
|
|
assign now = 1;
|
|
`endif
|
|
|
|
//these config flags are available only in the LOAD_CMD state (where we wait)
|
|
wire time_wait = out_command_hdr[9];
|
|
wire skip_late = out_command_hdr[10]; //TODO (implement)
|
|
reg cmd_was_late;
|
|
|
|
//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 = (time_wait)? (late || now) : 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;
|
|
cmd_was_late <= late; //TODO do something with
|
|
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;
|
|
localparam WRITE_RB_DATA2 = 5;
|
|
localparam WRITE_RB_DATA3 = 6;
|
|
|
|
//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;
|
|
reg [31:0] last_result_hdr;
|
|
|
|
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;
|
|
last_result_hdr <= 32'b0;
|
|
end
|
|
else if (writing && out_data[33]) begin
|
|
out_state <= WRITE_PKT_HDR;
|
|
last_result_hdr <= out_result_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] = 24; //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;
|
|
WRITE_RB_DATA2: out_data_int <= last_result_hdr;
|
|
WRITE_RB_DATA3: out_data_int <= {result_fifo_occupied, command_fifo_occupied};
|
|
default: out_data_int <= 0;
|
|
endcase //state
|
|
end
|
|
|
|
assign out_data[35:34] = 2'b0;
|
|
assign out_data[33] = (out_state == WRITE_RB_DATA3);
|
|
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, time_wait //4
|
|
};
|
|
|
|
endmodule //settings_fifo_ctrl
|