diff options
Diffstat (limited to 'fpga/usrp3/lib/vita/new_rx_control.v')
-rw-r--r-- | fpga/usrp3/lib/vita/new_rx_control.v | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/vita/new_rx_control.v b/fpga/usrp3/lib/vita/new_rx_control.v new file mode 100644 index 000000000..810fa1ce9 --- /dev/null +++ b/fpga/usrp3/lib/vita/new_rx_control.v @@ -0,0 +1,242 @@ +// +// Copyright 2013 Ettus Research LLC +// + + +// HALT brings RX to an idle state as quickly as possible if RX is running +// without running the risk of leaving a packet fragment in downstream FIFO's. +// HALT also flushes all remaining pending commands in the commmand FIFO. +// Unlike STOP, HALT doesn't ever create an ERROR packet. + + +module new_rx_control + #(parameter BASE=0) + (input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + + input [63:0] vita_time, + + // DDC connections + output run, output eob, + input strobe, input full, + input [11:0] seqnum, + input [31:0] sid, + + output [63:0] err_tdata, output err_tlast, output err_tvalid, input err_tready, + output [31:0] debug + ); + + wire [31:0] command_i; + wire [63:0] time_i; + wire store_command; + + wire send_imm, chain, reload, stop; + wire [27:0] numlines; + wire [63:0] rcvtime; + + wire now, early, late; + wire command_valid; + reg command_ready; + + reg chain_sav, reload_sav; + + + reg clear_halt; + reg halt; + wire set_halt; + + reg [63:0] err_tdata_int; + wire err_tlast_int; + wire err_tvalid_int; + wire err_tready_int; + + + setting_reg #(.my_addr(BASE)) sr_cmd + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(command_i),.changed()); + + setting_reg #(.my_addr(BASE+1)) sr_time_h + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(time_i[63:32]),.changed()); + + setting_reg #(.my_addr(BASE+2)) sr_time_l + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(time_i[31:0]),.changed(store_command)); + + setting_reg #(.my_addr(BASE+3)) sr_rx_halt + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), + .in(set_data),.out(),.changed(set_halt)); + + always @(posedge clk) + if (reset | clear | clear_halt) + halt <= 1'b0; + else + halt <= set_halt; + + + axi_fifo_short #(.WIDTH(96)) commandfifo + (.clk(clk),.reset(reset),.clear(clear | clear_halt), + .i_tdata({command_i,time_i}), .i_tvalid(store_command), .i_tready(), + .o_tdata({send_imm,chain,reload,stop,numlines,rcvtime}), + .o_tvalid(command_valid), .o_tready(command_ready), + .occupied(), .space() ); + + time_compare + time_compare (.clk(clk), .reset(reset), .time_now(vita_time), .trigger_time(rcvtime), .now(now), .early(early), .late(late)); + + localparam IBS_IDLE = 0; + localparam IBS_RUNNING = 1; + + localparam IBS_OVERRUN = 2; + localparam IBS_OVR_TIME = 3; + localparam IBS_OVR_DATA = 4; + + localparam IBS_BROKENCHAIN = 5; + localparam IBS_BRK_TIME = 6; + localparam IBS_BRK_DATA = 7; + + localparam IBS_LATECMD = 8; + localparam IBS_LATE_TIME = 9; + localparam IBS_LATE_DATA = 10; + + localparam IBS_ZEROLEN = 11; + localparam IBS_ZERO_TIME = 12; + localparam IBS_ZERO_DATA = 13; + + reg [3:0] ibs_state; + reg [27:0] lines_left, repeat_lines; + + + always @(posedge clk) + if(reset | clear) + begin + ibs_state <= IBS_IDLE; + chain_sav <= 1'b0; + reload_sav <= 1'b0; + clear_halt <= 1'b0; + end + else + case(ibs_state) + IBS_IDLE : begin + clear_halt <= 1'b0; // Incase we got here through a HALT. + if(command_valid) + if(stop) + ibs_state <= IBS_IDLE;//IBS_ZEROLEN; + else if(late & ~send_imm) + ibs_state <= IBS_LATECMD; + else if(now | send_imm) + begin + ibs_state <= IBS_RUNNING; + lines_left <= numlines; + repeat_lines <= numlines; + chain_sav <= chain; + reload_sav <= reload; + end + end // case: IBS_IDLE + + IBS_RUNNING : // need to check for full + if(strobe) + if(full) + ibs_state <= IBS_OVERRUN; + else + if(lines_left == 1) + // Provide Halt mechanism used to bring RX into known IDLE state + // at re-initialization. + if (halt) + begin + ibs_state <= IBS_IDLE; + clear_halt <= 1'b1; + end + else if(chain_sav) + if(command_valid) + begin + lines_left <= numlines; + repeat_lines <= numlines; + chain_sav <= chain; + reload_sav <= reload; + if(stop) + ibs_state <= IBS_IDLE; + end + else if(reload_sav) + lines_left <= repeat_lines; + else + ibs_state <= IBS_BROKENCHAIN; + else + ibs_state <= IBS_IDLE; + else + lines_left <= lines_left - 28'd1; + + + IBS_OVERRUN: if(err_tready_int) ibs_state <= IBS_OVR_TIME; + IBS_OVR_TIME: if(err_tready_int) ibs_state <= IBS_OVR_DATA; + IBS_OVR_DATA: if(err_tready_int) ibs_state <= IBS_IDLE; + + IBS_BROKENCHAIN: if(err_tready_int) ibs_state <= IBS_BRK_TIME; + IBS_BRK_TIME: if(err_tready_int) ibs_state <= IBS_BRK_DATA; + IBS_BRK_DATA: if(err_tready_int) ibs_state <= IBS_IDLE; + + IBS_LATECMD: if(err_tready_int) ibs_state <= IBS_LATE_TIME; + IBS_LATE_TIME: if(err_tready_int) ibs_state <= IBS_LATE_DATA; + IBS_LATE_DATA: if(err_tready_int) ibs_state <= IBS_IDLE; + + IBS_ZEROLEN: if(err_tready_int) ibs_state <= IBS_ZERO_TIME; + IBS_ZERO_TIME: if(err_tready_int) ibs_state <= IBS_ZERO_DATA; + IBS_ZERO_DATA: if(err_tready_int) ibs_state <= IBS_IDLE; + + default: ibs_state <= IBS_IDLE; + + endcase // case (ibs_state) + + always @* + case(ibs_state) + IBS_IDLE : command_ready <= stop | late | now | send_imm; + IBS_RUNNING : command_ready <= strobe & (lines_left == 1) & chain_sav; + default : command_ready <= 1'b0; + endcase // case (ibs_state) + + assign run = (ibs_state == IBS_RUNNING); + assign eob = strobe & (lines_left == 1) & ( ~chain_sav | (command_valid & stop) | (~command_valid & ~reload_sav) | halt); + + always @* + case (ibs_state) + IBS_OVERRUN : err_tdata_int <= { 4'hA, seqnum, 16'd24, sid }; + IBS_OVR_TIME : err_tdata_int <= vita_time; + IBS_OVR_DATA : err_tdata_int <= {32'h8, 32'b0}; + + IBS_BROKENCHAIN : err_tdata_int <= { 4'hA, seqnum, 16'd24, sid }; + IBS_BRK_TIME : err_tdata_int <= vita_time; + IBS_BRK_DATA : err_tdata_int <= {32'h4, 32'b0}; + + IBS_LATECMD : err_tdata_int <= { 4'hA, seqnum, 16'd24, sid }; + IBS_LATE_TIME : err_tdata_int <= vita_time; + IBS_LATE_DATA : err_tdata_int <= {32'h2, 32'b0}; + + IBS_ZEROLEN : err_tdata_int <= { 4'hA, seqnum, 16'd24, sid }; + IBS_ZERO_TIME : err_tdata_int <= vita_time; + IBS_ZERO_DATA : err_tdata_int <= {32'hd, 32'b0}; + + default : err_tdata_int <= {32'he, 32'b0}; + endcase // case (ibs_state) + + assign err_tlast_int = (ibs_state == IBS_OVR_DATA) + | (ibs_state == IBS_BRK_DATA) + | (ibs_state == IBS_LATE_DATA) + | (ibs_state == IBS_ZERO_DATA); + + assign err_tvalid_int = ibs_state >= IBS_OVERRUN; + + + assign debug[3:0] = ibs_state; + assign debug[7:4] = {2'b0, command_valid, command_ready}; + + axi_fifo_short #(.WIDTH(65)) output_fifo + ( + .clk(clk), .reset(reset), .clear(clear), + .i_tdata({err_tlast_int,err_tdata_int}), .i_tvalid(err_tvalid_int), .i_tready(err_tready_int), + .o_tdata({err_tlast,err_tdata}), .o_tvalid(err_tvalid), .o_tready(err_tready), + .space(), .occupied() + ); + + + +endmodule // new_rx_control |