summaryrefslogtreecommitdiffstats
path: root/sdr_lib/rx_control.v
diff options
context:
space:
mode:
Diffstat (limited to 'sdr_lib/rx_control.v')
-rw-r--r--sdr_lib/rx_control.v213
1 files changed, 213 insertions, 0 deletions
diff --git a/sdr_lib/rx_control.v b/sdr_lib/rx_control.v
new file mode 100644
index 000000000..d41a28bcf
--- /dev/null
+++ b/sdr_lib/rx_control.v
@@ -0,0 +1,213 @@
+
+`define DSP_CORE_RX_BASE 160
+
+module rx_control
+ #(parameter FIFOSIZE = 10)
+ (input clk, input rst,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ input [31:0] master_time,
+ output overrun,
+
+ // To Buffer interface
+ output [31:0] wr_dat_o,
+ output wr_write_o,
+ output wr_done_o,
+ output wr_error_o,
+
+ input wr_ready_i,
+ input wr_full_i,
+
+ // From DSP Core
+ input [31:0] sample,
+ output run,
+ input strobe,
+
+ // FIFO Levels
+ output [15:0] fifo_occupied,
+ output fifo_full,
+ output fifo_empty,
+
+ // Debug
+ output [31:0] debug_rx
+ );
+
+ wire [31:0] new_time, new_command;
+ wire sc_pre1, clear_overrun;
+ wire [31:0] rcvtime_pre;
+ reg [31:0] rcvtime;
+ wire [8:0] lines_per_frame;
+ wire [20:0] numlines;
+ wire send_imm_pre, chain_pre;
+ reg send_imm, chain;
+ wire full_ctrl, read_ctrl, empty_ctrl, write_ctrl;
+
+ setting_reg #(.my_addr(`DSP_CORE_RX_BASE+3)) sr_3
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(new_time),.changed(sc_pre1));
+
+ setting_reg #(.my_addr(`DSP_CORE_RX_BASE+4)) sr_4
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(new_command),.changed());
+
+ setting_reg #(.my_addr(`DSP_CORE_RX_BASE+5)) sr_5
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(),.changed(clear_overrun));
+
+ reg sc_pre2;
+ always @(posedge clk)
+ sc_pre2 <= sc_pre1;
+ assign write_ctrl = sc_pre1 & ~sc_pre2;
+
+ shortfifo #(.WIDTH(64)) commandfifo
+ (.clk(clk),.rst(rst),.clear(clear_overrun),
+ .datain({new_command,new_time}), .write(write_ctrl), .full(full_ctrl),
+ .dataout({send_imm_pre,chain_pre,numlines,lines_per_frame,rcvtime_pre}),
+ .read(read_ctrl), .empty(empty_ctrl) );
+
+ // Buffer interface to internal FIFO
+ wire write, full, read, empty;
+ wire sop_o, eop_o;
+
+ reg xfer_state;
+ localparam XFER_IDLE = 1'b0;
+ localparam XFER_GO = 1'b1;
+
+ always @(posedge clk)
+ if(rst)
+ xfer_state <= XFER_IDLE;
+ else
+ if(clear_overrun)
+ xfer_state <= XFER_IDLE;
+ else
+ case(xfer_state)
+ XFER_IDLE :
+ if(wr_ready_i)
+ xfer_state <= XFER_GO;
+ XFER_GO :
+ if((eop_o | wr_full_i) & wr_write_o)
+ xfer_state <= XFER_IDLE;
+ default :
+ xfer_state <= XFER_IDLE;
+ endcase // case(xfer_state)
+
+ assign wr_write_o = (xfer_state == XFER_GO) & ~empty;
+ assign wr_done_o = (eop_o & wr_write_o);
+ assign wr_error_o = 0; // FIXME add check here for eop if we have wr_full_i once we have IBS
+
+ assign read = wr_write_o | (~empty & ~sop_o); // FIXME what if there is junk between packets?
+
+ wire [33:0] fifo_line;
+
+ // Internal FIFO, size 9 is 2K, size 10 is 4K
+ cascadefifo2 #(.WIDTH(34),.SIZE(FIFOSIZE)) rxfifo
+ (.clk(clk),.rst(rst),.clear(clear_overrun),
+ .datain(fifo_line), .write(write), .full(full),
+ .dataout({sop_o,eop_o,wr_dat_o}), .read(read), .empty(empty),
+ .space(),.occupied(fifo_occupied) );
+ assign fifo_full = full;
+ assign fifo_empty = empty;
+
+ // Internal FIFO to DSP interface
+ reg [22:0] lines_left;
+ reg [8:0] lines_left_frame;
+ localparam IBS_IDLE = 0;
+ localparam IBS_WAITING = 1;
+ localparam IBS_FIRSTLINE = 2;
+ localparam IBS_RUNNING = 3;
+ localparam IBS_OVERRUN = 4;
+
+ reg [2:0] ibs_state;
+
+ wire [32:0] delta_time = {1'b0,rcvtime}-{1'b0,master_time};
+ wire too_late = (delta_time[32:31] == 2'b11) & ~send_imm;
+ wire go_now = send_imm | ( master_time == rcvtime );
+
+ always @(posedge clk)
+ if(rst)
+ begin
+ ibs_state <= IBS_IDLE;
+ lines_left <= 0;
+ lines_left_frame <= 0;
+ rcvtime <= 0;
+ send_imm <= 0;
+ chain <= 0;
+ end
+ else
+ if(clear_overrun)
+ begin
+ ibs_state <= IBS_IDLE;
+ lines_left <= 0;
+ lines_left_frame <= 0;
+ rcvtime <= 0;
+ send_imm <= 0;
+ chain <= 0;
+ end
+ else
+ case(ibs_state)
+ IBS_IDLE :
+ if(~empty_ctrl)
+ begin
+ lines_left <= numlines;
+ lines_left_frame <= lines_per_frame;
+ rcvtime <= rcvtime_pre;
+ ibs_state <= IBS_WAITING;
+ send_imm <= send_imm_pre;
+ chain <= chain_pre;
+ end
+ IBS_WAITING :
+ if(go_now)
+ ibs_state <= IBS_FIRSTLINE;
+ else if(too_late)
+ ibs_state <= IBS_OVERRUN;
+ IBS_FIRSTLINE :
+ if(full | strobe)
+ ibs_state <= IBS_OVERRUN;
+ else
+ ibs_state <= IBS_RUNNING;
+ IBS_RUNNING :
+ if(strobe)
+ if(full)
+ ibs_state <= IBS_OVERRUN;
+ else
+ begin
+ lines_left <= lines_left - 1;
+ if(lines_left == 1)
+ if(~chain)
+ ibs_state <= IBS_IDLE;
+ else if(empty_ctrl)
+ ibs_state <= IBS_OVERRUN;
+ else
+ begin
+ lines_left <= numlines;
+ lines_left_frame <= lines_per_frame;
+ rcvtime <= rcvtime_pre;
+ ibs_state <= IBS_FIRSTLINE;
+ send_imm <= send_imm_pre;
+ chain <= chain_pre;
+ end
+ else if(lines_left_frame == 1)
+ begin
+ lines_left_frame <= lines_per_frame;
+ ibs_state <= IBS_FIRSTLINE;
+ end
+ else
+ lines_left_frame <= lines_left_frame - 1;
+ end // else: !if(full)
+ endcase // case(ibs_state)
+
+ assign fifo_line = (ibs_state == IBS_FIRSTLINE) ? {1'b1,1'b0,master_time} :
+ {1'b0,((lines_left==1)|(lines_left_frame==1)),sample};
+
+ assign write = ((ibs_state == IBS_FIRSTLINE) | strobe) & ~full; // & (ibs_state == IBS_RUNNING) should strobe only when running
+ assign overrun = (ibs_state == IBS_OVERRUN);
+ assign run = (ibs_state == IBS_RUNNING) | (ibs_state == IBS_FIRSTLINE);
+ assign read_ctrl = ( (ibs_state == IBS_IDLE) |
+ ((ibs_state == IBS_RUNNING) & strobe & ~full & (lines_left==1) & chain) )
+ & ~empty_ctrl;
+
+ assign debug_rx = { 6'd0,send_imm,chain,
+ wr_write_o, wr_done_o, wr_ready_i, wr_full_i,xfer_state,eop_o, sop_o, run,
+ write,full,read,empty,write_ctrl,full_ctrl,read_ctrl,empty_ctrl,
+ sc_pre1, clear_overrun, go_now, too_late, overrun, ibs_state[2:0] };
+endmodule // rx_control