Copied wb_1master back from quad radio
[debian/gnuradio] / usrp2 / fpga / simple_gemac / simple_gemac_tx.v
1
2 module simple_gemac_tx
3   (input clk125, input reset,
4    output GMII_GTX_CLK, output reg GMII_TX_EN, output reg GMII_TX_ER, output reg [7:0] GMII_TXD,
5    output tx_clk, input [7:0] tx_data, input tx_valid, input tx_error, output tx_ack,
6    input [7:0] ifg, input [47:0] mac_addr,
7    input pause_req, input [15:0] pause_time,
8    input pause_apply, output reg paused
9    );
10
11    reg tx_en_pre, tx_er_pre;
12    reg [7:0] txd_pre;
13    
14    assign GMII_GTX_CLK  = clk125;
15    assign tx_clk        = clk125;
16    
17    reg [7:0] tx_state;
18    reg [7:0] ifg_ctr;
19    reg [15:0] frame_len_ctr;
20    reg [7:0] pause_ctr, pause_dat;
21
22    wire in_ifg               = (ifg_ctr != 0);
23
24    wire [31:0] crc_out;
25    
26    localparam MIN_FRAME_LEN  = 64 + 8 - 4; // Min frame length includes preamble but not CRC
27    localparam MAX_FRAME_LEN  = 8192;       // How big are the jumbo frames we want to handle?
28    always @(posedge tx_clk)
29      if(reset |(tx_state == TX_IDLE))
30        frame_len_ctr        <= 0;
31      else
32        frame_len_ctr        <= frame_len_ctr + 1;
33    
34    localparam TX_IDLE        = 0;
35    localparam TX_PREAMBLE    = 1;
36    localparam TX_SOF_DEL     = TX_PREAMBLE + 7;
37    localparam TX_FIRSTBYTE   = TX_SOF_DEL + 1;
38    localparam TX_IN_FRAME    = TX_FIRSTBYTE + 1;
39    localparam TX_IN_FRAME_2  = TX_IN_FRAME + 1;
40    localparam TX_PAD         = TX_IN_FRAME_2 + 1;
41    localparam TX_CRC_0       = 16;
42    localparam TX_CRC_1       = TX_CRC_0 + 1;
43    localparam TX_CRC_2       = TX_CRC_0 + 2;
44    localparam TX_CRC_3       = TX_CRC_0 + 3;
45    localparam TX_ERROR       = 32;
46    localparam TX_PAUSE       = 55;
47    localparam TX_PAUSE_SOF   = TX_PAUSE + 7;
48    localparam TX_PAUSE_FIRST = TX_PAUSE_SOF + 1;
49    localparam TX_PAUSE_END   = TX_PAUSE_SOF + 18;
50
51    reg send_pause;
52    reg [15:0] pause_time_held;
53
54    always @(posedge tx_clk)
55      if(reset)
56        send_pause      <= 0;
57      else if(pause_req)
58        send_pause      <= 1;
59      else if(tx_state == TX_PAUSE)
60        send_pause      <= 0;
61
62    always @(posedge tx_clk)
63      if(pause_req)
64        pause_time_held <= pause_time;
65    
66    always @(posedge tx_clk)
67      if(reset)
68        tx_state        <= TX_IDLE;
69      else 
70        case(tx_state)
71          TX_IDLE :
72            if(~in_ifg)
73              if(send_pause)
74                tx_state <= TX_PAUSE;
75              else if(tx_valid & ~pause_apply)
76                tx_state <= TX_PREAMBLE;
77          TX_FIRSTBYTE :
78            if(tx_error)
79              tx_state <= TX_ERROR;   // underrun
80            else if(~tx_valid)
81              tx_state <= TX_PAD;
82            else
83              tx_state <= TX_IN_FRAME;
84          TX_IN_FRAME :
85            if(tx_error)
86              tx_state <= TX_ERROR;   // underrun
87            else if(~tx_valid)
88              tx_state <= TX_PAD;
89            else if(frame_len_ctr == MIN_FRAME_LEN - 1)
90              tx_state <= TX_IN_FRAME_2;
91          TX_IN_FRAME_2 :
92            if(tx_error)
93              tx_state <= TX_ERROR;   // underrun
94            else if(~tx_valid)
95              tx_state <= TX_CRC_0;
96          TX_PAD :
97            if(frame_len_ctr == MIN_FRAME_LEN)
98              tx_state <= TX_CRC_0;
99          TX_CRC_3 :
100            tx_state <= TX_IDLE;
101          TX_ERROR :
102            tx_state <= TX_IDLE;
103          TX_PAUSE_END :
104            tx_state <= TX_PAD;
105          default :
106            tx_state <= tx_state + 1;
107        endcase // case (tx_state)
108
109    always @(posedge tx_clk)
110      if(reset)
111        begin
112           tx_en_pre <= 0;
113           tx_er_pre <= 0;
114           txd_pre   <= 0;
115        end
116      else
117        casex(tx_state)
118          TX_IDLE :
119            begin
120               tx_en_pre <= 0;
121               tx_er_pre <= 0;
122               txd_pre <= 0;
123            end
124          TX_PREAMBLE, TX_PAUSE :
125            begin
126               txd_pre    <= 8'h55;
127               tx_en_pre <= 1;
128            end
129          TX_SOF_DEL, TX_PAUSE_SOF :
130            txd_pre <= 8'hD5;
131          TX_FIRSTBYTE, TX_IN_FRAME, TX_IN_FRAME_2 :
132            txd_pre <= tx_valid ? tx_data : 0;
133          TX_ERROR :
134            begin
135               tx_er_pre <= 1;
136               txd_pre    <= 0;
137            end
138          TX_CRC_3 :
139            tx_en_pre <= 0;
140          TX_PAD :
141            txd_pre <= 0;
142          TX_PAUSE_FIRST, 8'b01xx_xxxx :  // In Pause Frame
143            txd_pre <= pause_dat;
144        endcase // case (tx_state)
145
146    localparam SGE_FLOW_CTRL_ADDR  = 48'h01_80_C2_00_00_01;
147    always @(posedge tx_clk)
148      case(tx_state)
149        TX_PAUSE_SOF :
150          pause_dat    <= SGE_FLOW_CTRL_ADDR[47:40];  // Note everything must be 1 cycle early
151        TX_PAUSE_SOF + 1:
152          pause_dat    <= SGE_FLOW_CTRL_ADDR[39:32];
153        TX_PAUSE_SOF + 2:
154          pause_dat    <= SGE_FLOW_CTRL_ADDR[31:24];
155        TX_PAUSE_SOF + 3:
156          pause_dat    <= SGE_FLOW_CTRL_ADDR[23:16];
157        TX_PAUSE_SOF + 4:
158          pause_dat    <= SGE_FLOW_CTRL_ADDR[15:8];
159        TX_PAUSE_SOF + 5:
160          pause_dat    <= SGE_FLOW_CTRL_ADDR[7:0];
161        TX_PAUSE_SOF + 6:
162          pause_dat    <= mac_addr[47:40];
163        TX_PAUSE_SOF + 7:
164          pause_dat    <= mac_addr[39:32];
165        TX_PAUSE_SOF + 8:
166          pause_dat    <= mac_addr[31:24];
167        TX_PAUSE_SOF + 9:
168          pause_dat    <= mac_addr[23:16];
169        TX_PAUSE_SOF + 10:
170          pause_dat    <= mac_addr[15:8];
171        TX_PAUSE_SOF + 11:
172          pause_dat <= mac_addr[7:0];
173        TX_PAUSE_SOF + 12:
174          pause_dat <= 8'h88;   // Type = 8808 = MAC ctrl frame
175        TX_PAUSE_SOF + 13:
176          pause_dat <= 8'h08;
177        TX_PAUSE_SOF + 14:
178          pause_dat <= 8'h00;   // Opcode = 0001 = PAUSE
179        TX_PAUSE_SOF + 15:
180          pause_dat <= 8'h01;
181        TX_PAUSE_SOF + 16:
182          pause_dat <= pause_time_held[15:8];
183        TX_PAUSE_SOF + 17:
184          pause_dat <= pause_time_held[7:0];
185      endcase // case (tx_state)
186    
187    wire start_ifg   = (tx_state == TX_CRC_3);
188    always @(posedge tx_clk)
189      if(reset)
190        ifg_ctr     <= 100;
191      else if(start_ifg)
192        ifg_ctr     <= ifg;
193      else if(ifg_ctr != 0)
194        ifg_ctr     <= ifg_ctr - 1;
195
196    wire clear_crc   = (tx_state == TX_IDLE);
197
198    wire calc_crc    = 
199         (tx_state==TX_IN_FRAME) |
200         (tx_state==TX_IN_FRAME_2) |
201         (tx_state==TX_PAD) |
202         (tx_state[6]);
203
204    crc crc(.clk(tx_clk), .reset(reset), .clear(clear_crc),
205             .data(txd_pre), .calc(calc_crc), .crc_out(crc_out));
206
207    assign tx_ack    = (tx_state == TX_FIRSTBYTE);
208
209    always @(posedge tx_clk) 
210      begin
211         GMII_TX_EN <= tx_en_pre;
212         GMII_TX_ER <= tx_er_pre;
213         case(tx_state)
214           TX_CRC_0 :
215             GMII_TXD <= crc_out[31:24];
216           TX_CRC_1 :
217             GMII_TXD <= crc_out[23:16];
218           TX_CRC_2 :
219             GMII_TXD <= crc_out[15:8];
220           TX_CRC_3 :
221             GMII_TXD <= crc_out[7:0];
222           default :
223             GMII_TXD <= txd_pre;
224         endcase // case (tx_state)
225      end
226
227    // report that we are paused only when we get back to IDLE
228    always @(posedge tx_clk)
229      if(reset)
230        paused        <= 0;
231      else if(~pause_apply)
232        paused        <= 0;
233      else if(tx_state == TX_IDLE)
234        paused        <= 1;
235    
236 endmodule // simple_gemac_tx
237
238 // Testing code
239 /*
240     reg [7:0] crc_ctr;
241    reg calc_crc_d1;
242    always @(posedge tx_clk) 
243      calc_crc_d1 <= calc_crc;
244    
245    always @(posedge tx_clk)
246      if(reset)
247        crc_ctr   <= 0;
248      else if(calc_crc)
249        crc_ctr   <= crc_ctr+1;
250      else if(calc_crc_d1)
251        $display("CRC COUNT = %d",crc_ctr);
252      else
253        crc_ctr <= 0;
254 */