Added firmware support for adc_mux to handle swapping I/Q, etc.
[debian/gnuradio] / usrp2 / fpga / sdr_lib / tx_control.v
1
2 `define DSP_CORE_TX_BASE 128
3
4 module tx_control
5   #(parameter FIFOSIZE = 10)
6     (input clk, input rst,
7      input set_stb, input [7:0] set_addr, input [31:0] set_data,
8      
9      input [31:0] master_time, 
10      output underrun,
11      
12      // To Buffer interface
13      input [31:0] rd_dat_i,
14      input rd_sop_i,
15      input rd_eop_i,
16      output rd_read_o,
17      output rd_done_o,
18      output rd_error_o,
19      
20      // To DSP Core
21      output [31:0] sample,
22      output run,
23      input strobe,
24
25      // FIFO Levels
26      output [15:0] fifo_occupied,
27      output fifo_full,
28      output fifo_empty,
29
30      // Debug
31      output [31:0] debug
32      );
33
34    // Buffer interface to internal FIFO
35    wire     write_data, write_ctrl, full_data, full_ctrl;
36    wire     read_data, read_ctrl, empty_data, empty_ctrl;
37    wire     clear_state;
38    reg [1:0] xfer_state;
39    reg [2:0] held_flags;
40    
41    localparam XFER_IDLE = 0;
42    localparam XFER_1 = 1;
43    localparam XFER_2 = 2;
44    localparam XFER_DATA = 3;
45    
46    always @(posedge clk)
47      if(rst)
48        xfer_state <= XFER_IDLE;
49      else
50        if(clear_state)
51          xfer_state <= XFER_IDLE;
52        else
53          case(xfer_state)
54            XFER_IDLE :
55              if(rd_sop_i)
56                xfer_state <= XFER_1;
57            XFER_1 :
58              begin
59                 xfer_state <= XFER_2;
60                 held_flags <= rd_dat_i[2:0];
61              end
62            XFER_2 :
63              if(~full_ctrl)
64                xfer_state <= XFER_DATA;
65            XFER_DATA :
66              if(rd_eop_i & ~full_data)
67                xfer_state <= XFER_IDLE;
68          endcase // case(xfer_state)
69    
70    assign write_data = (xfer_state == XFER_DATA) & ~full_data;
71    assign write_ctrl = (xfer_state == XFER_2) & ~full_ctrl;
72
73    assign rd_read_o = (xfer_state == XFER_1) | write_data | write_ctrl;
74    assign rd_done_o = 0;  // Always take everything we're given
75    assign rd_error_o = 0;  // Should we indicate overruns here?
76    
77    wire [31:0] data_o;
78    wire        sop_o, eop_o, eob, sob, send_imm;
79    wire [31:0] sendtime;
80    wire [4:0]  occ_ctrl;
81    
82    cascadefifo2 #(.WIDTH(34),.SIZE(FIFOSIZE)) txctrlfifo
83      (.clk(clk),.rst(rst),.clear(clear_state),
84       .datain({rd_sop_i,rd_eop_i,rd_dat_i}), .write(write_data), .full(full_data),
85       .dataout({sop_o,eop_o,data_o}), .read(read_data), .empty(empty_data),
86       .space(), .occupied(fifo_occupied) );
87    assign      fifo_full = full_data;
88    assign      fifo_empty = empty_data;
89
90    shortfifo #(.WIDTH(35)) ctrlfifo
91      (.clk(clk),.rst(rst),.clear(clear_state),
92       .datain({held_flags[2:0],rd_dat_i}), .write(write_ctrl), .full(full_ctrl),
93       .dataout({send_imm,sob,eob,sendtime}), .read(read_ctrl), .empty(empty_ctrl),
94       .space(), .occupied(occ_ctrl) );
95
96    // Internal FIFO to DSP interface
97    reg [2:0]   ibs_state;
98    
99    localparam  IBS_IDLE = 0;
100    localparam  IBS_WAIT = 1;
101    localparam  IBS_RUNNING = 2;
102    localparam  IBS_CONT_BURST = 3;
103    localparam  IBS_UNDERRUN = 7;
104
105    wire [32:0] delta_time = {1'b0,sendtime}-{1'b0,master_time};
106    
107    wire        too_late = (delta_time[32:31] == 2'b11);
108    wire        go_now = ( master_time == sendtime );
109    
110    always @(posedge clk)
111      if(rst)
112        ibs_state <= IBS_IDLE;
113      else
114        case(ibs_state)
115          IBS_IDLE :
116            if(~empty_ctrl & ~empty_data)
117              ibs_state <= IBS_WAIT;
118          IBS_WAIT :
119            if(send_imm)
120              ibs_state <= IBS_RUNNING;
121            else if(too_late)
122              ibs_state <= IBS_UNDERRUN;
123            else if(go_now)
124              ibs_state <= IBS_RUNNING;
125          IBS_RUNNING :
126            if(strobe)
127              if(empty_data)
128                ibs_state <= IBS_UNDERRUN;
129              else if(eop_o)
130                if(eob)
131                  ibs_state <= IBS_IDLE;
132                else
133                  ibs_state <= IBS_CONT_BURST;
134          IBS_CONT_BURST :
135            if(~empty_ctrl)  //  & ~empty_data)
136              ibs_state <= IBS_RUNNING;
137            else if(strobe)
138              ibs_state <= IBS_UNDERRUN;
139          IBS_UNDERRUN :   // FIXME Should probably clean everything out
140            if(clear_state)
141              ibs_state <= IBS_IDLE;
142        endcase // case(ibs_state)
143
144    assign      read_ctrl = (ibs_state == IBS_RUNNING) & strobe & eop_o;  // & ~empty_ctrl;
145    assign      read_data = (ibs_state == IBS_RUNNING) & strobe & ~empty_data;
146    assign      run = (ibs_state == IBS_RUNNING) | (ibs_state == IBS_CONT_BURST);
147    assign      underrun = (ibs_state == IBS_UNDERRUN);
148
149    wire [7:0]  interp_rate;
150    setting_reg #(.my_addr(`DSP_CORE_TX_BASE+3)) sr_3
151      (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
152       .in(set_data),.out(),.changed(clear_state));
153
154    assign      sample = data_o;
155
156    assign      debug = { {16'b0},
157                          { read_data, write_data, read_ctrl, write_ctrl, xfer_state[1:0],full_ctrl,empty_ctrl },
158                          { occ_ctrl, eop_o, clear_state, underrun} };
159    
160 endmodule // tx_control