// // 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