aboutsummaryrefslogtreecommitdiffstats
path: root/sdr_lib/tx_control.v
diff options
context:
space:
mode:
Diffstat (limited to 'sdr_lib/tx_control.v')
-rw-r--r--sdr_lib/tx_control.v160
1 files changed, 160 insertions, 0 deletions
diff --git a/sdr_lib/tx_control.v b/sdr_lib/tx_control.v
new file mode 100644
index 000000000..0c4ab1a52
--- /dev/null
+++ b/sdr_lib/tx_control.v
@@ -0,0 +1,160 @@
+
+`define DSP_CORE_TX_BASE 128
+
+module tx_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 underrun,
+
+ // To Buffer interface
+ input [31:0] rd_dat_i,
+ input rd_sop_i,
+ input rd_eop_i,
+ output rd_read_o,
+ output rd_done_o,
+ output rd_error_o,
+
+ // To DSP Core
+ output [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
+ );
+
+ // Buffer interface to internal FIFO
+ wire write_data, write_ctrl, full_data, full_ctrl;
+ wire read_data, read_ctrl, empty_data, empty_ctrl;
+ wire clear_state;
+ reg [1:0] xfer_state;
+ reg [2:0] held_flags;
+
+ localparam XFER_IDLE = 0;
+ localparam XFER_1 = 1;
+ localparam XFER_2 = 2;
+ localparam XFER_DATA = 3;
+
+ always @(posedge clk)
+ if(rst)
+ xfer_state <= XFER_IDLE;
+ else
+ if(clear_state)
+ xfer_state <= XFER_IDLE;
+ else
+ case(xfer_state)
+ XFER_IDLE :
+ if(rd_sop_i)
+ xfer_state <= XFER_1;
+ XFER_1 :
+ begin
+ xfer_state <= XFER_2;
+ held_flags <= rd_dat_i[2:0];
+ end
+ XFER_2 :
+ if(~full_ctrl)
+ xfer_state <= XFER_DATA;
+ XFER_DATA :
+ if(rd_eop_i & ~full_data)
+ xfer_state <= XFER_IDLE;
+ endcase // case(xfer_state)
+
+ assign write_data = (xfer_state == XFER_DATA) & ~full_data;
+ assign write_ctrl = (xfer_state == XFER_2) & ~full_ctrl;
+
+ assign rd_read_o = (xfer_state == XFER_1) | write_data | write_ctrl;
+ assign rd_done_o = 0; // Always take everything we're given
+ assign rd_error_o = 0; // Should we indicate overruns here?
+
+ wire [31:0] data_o;
+ wire sop_o, eop_o, eob, sob, send_imm;
+ wire [31:0] sendtime;
+ wire [4:0] occ_ctrl;
+
+ cascadefifo2 #(.WIDTH(34),.SIZE(FIFOSIZE)) txctrlfifo
+ (.clk(clk),.rst(rst),.clear(clear_state),
+ .datain({rd_sop_i,rd_eop_i,rd_dat_i}), .write(write_data), .full(full_data),
+ .dataout({sop_o,eop_o,data_o}), .read(read_data), .empty(empty_data),
+ .space(), .occupied(fifo_occupied) );
+ assign fifo_full = full_data;
+ assign fifo_empty = empty_data;
+
+ shortfifo #(.WIDTH(35)) ctrlfifo
+ (.clk(clk),.rst(rst),.clear(clear_state),
+ .datain({held_flags[2:0],rd_dat_i}), .write(write_ctrl), .full(full_ctrl),
+ .dataout({send_imm,sob,eob,sendtime}), .read(read_ctrl), .empty(empty_ctrl),
+ .space(), .occupied(occ_ctrl) );
+
+ // Internal FIFO to DSP interface
+ reg [2:0] ibs_state;
+
+ localparam IBS_IDLE = 0;
+ localparam IBS_WAIT = 1;
+ localparam IBS_RUNNING = 2;
+ localparam IBS_CONT_BURST = 3;
+ localparam IBS_UNDERRUN = 7;
+
+ wire [32:0] delta_time = {1'b0,sendtime}-{1'b0,master_time};
+
+ wire too_late = (delta_time[32:31] == 2'b11);
+ wire go_now = ( master_time == sendtime );
+
+ always @(posedge clk)
+ if(rst)
+ ibs_state <= IBS_IDLE;
+ else
+ case(ibs_state)
+ IBS_IDLE :
+ if(~empty_ctrl & ~empty_data)
+ ibs_state <= IBS_WAIT;
+ IBS_WAIT :
+ if(send_imm)
+ ibs_state <= IBS_RUNNING;
+ else if(too_late)
+ ibs_state <= IBS_UNDERRUN;
+ else if(go_now)
+ ibs_state <= IBS_RUNNING;
+ IBS_RUNNING :
+ if(strobe)
+ if(empty_data)
+ ibs_state <= IBS_UNDERRUN;
+ else if(eop_o)
+ if(eob)
+ ibs_state <= IBS_IDLE;
+ else
+ ibs_state <= IBS_CONT_BURST;
+ IBS_CONT_BURST :
+ if(~empty_ctrl) // & ~empty_data)
+ ibs_state <= IBS_RUNNING;
+ else if(strobe)
+ ibs_state <= IBS_UNDERRUN;
+ IBS_UNDERRUN : // FIXME Should probably clean everything out
+ if(clear_state)
+ ibs_state <= IBS_IDLE;
+ endcase // case(ibs_state)
+
+ assign read_ctrl = (ibs_state == IBS_RUNNING) & strobe & eop_o; // & ~empty_ctrl;
+ assign read_data = (ibs_state == IBS_RUNNING) & strobe & ~empty_data;
+ assign run = (ibs_state == IBS_RUNNING) | (ibs_state == IBS_CONT_BURST);
+ assign underrun = (ibs_state == IBS_UNDERRUN);
+
+ wire [7:0] interp_rate;
+ setting_reg #(.my_addr(`DSP_CORE_TX_BASE+3)) sr_3
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(),.changed(clear_state));
+
+ assign sample = data_o;
+
+ assign debug = { {16'b0},
+ { read_data, write_data, read_ctrl, write_ctrl, xfer_state[1:0],full_ctrl,empty_ctrl },
+ { occ_ctrl, eop_o, clear_state, underrun} };
+
+endmodule // tx_control