eth_capture.sv (5036B)
1 // Copyright 2014 Brian Swetland <swetland@frotz.net> 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 `timescale 1ns / 1ps 16 17 module eth_capture( 18 // interface from eth_rmii_rx 19 input clk50, 20 input rxsop, 21 input rxeop, 22 input [7:0]rxdata, 23 input rxvalid, 24 25 // interface to axi 26 input clk, 27 input reset, 28 input enable, 29 axi_ifc.master axi_dma 30 ); 31 32 parameter BASE_ADDR = 32'h10000000; 33 34 wire active; 35 sync_oneway sync_enable( 36 .txclk(clk), 37 .txdat(enable), 38 .rxclk(clk50), 39 .rxdat(active) 40 ); 41 42 wire [31:0]w_data; 43 wire w_valid; 44 wire w_eop; 45 wire [11:0]bytecount; 46 47 reg [63:0]clk50_count = 0; 48 reg [63:0]rxtimestamp = 0; 49 always @(posedge clk50) begin 50 clk50_count <= clk50_count + 1; 51 if (rxsop) begin 52 rxtimestamp <= clk50_count; 53 end 54 end 55 56 pkt_bytes_to_words cap0( 57 .clk(clk50), 58 .rxdata(rxdata), 59 .rxvalid(rxvalid & active), 60 .rxeop(rxeop & active), 61 .data(w_data), 62 .bytecount(bytecount), 63 .eop(w_eop), 64 .valid(w_valid) 65 ); 66 67 typedef enum { DATA, EOP0, EOP1, EOP2 } state_t; 68 state_t state = DATA; 69 state_t next_state; 70 71 reg [20:0]cfifo_in = 0; 72 reg [31:0]dfifo_in = 0; 73 reg [20:0]next_cfifo_in; 74 reg [31:0]next_dfifo_in; 75 reg cfifo_wr = 0; 76 reg dfifo_wr = 0; 77 reg next_cfifo_wr; 78 reg next_dfifo_wr; 79 reg [3:0]dcount = 15; 80 reg [3:0]next_dcount; 81 82 // ADDR: window(10) packet(10) chunk(6) off(6) 83 reg [9:0]dbase = 0; 84 reg [9:0]next_dbase; 85 reg [5:0]daddr = 1; 86 reg [5:0]next_daddr; 87 88 wire [3:0]dcount_plus_one = (dcount + 1); 89 90 always_comb begin 91 next_state = state; 92 next_dcount = dcount; 93 next_daddr = daddr; 94 next_dbase = dbase; 95 next_cfifo_in = cfifo_in; 96 next_dfifo_in = dfifo_in; 97 next_cfifo_wr = 0; 98 next_dfifo_wr = 0; 99 case (state) 100 DATA: begin 101 if (w_valid) begin 102 next_dcount = dcount_plus_one; 103 next_dfifo_in = w_data; 104 next_dfifo_wr = 1; 105 if (dcount_plus_one == 15) begin 106 next_cfifo_in = { 1'b0, 4'd15, dbase, daddr }; 107 next_cfifo_wr = 1; 108 next_daddr = daddr + 1; 109 end 110 end else if (w_eop) begin 111 next_state = EOP0; 112 next_dfifo_in = rxtimestamp[31:0]; 113 next_dfifo_wr = 1; 114 if (dcount != 15) begin 115 next_cfifo_in = { 1'b0, dcount, dbase, daddr }; 116 next_cfifo_wr = 1; 117 end 118 end 119 end 120 EOP0: begin 121 next_state = EOP1; 122 next_dfifo_in = rxtimestamp[63:32]; 123 next_dfifo_wr = 1; 124 end 125 EOP1: begin 126 next_state = EOP2; 127 next_dfifo_in = { 20'h00000, bytecount }; 128 next_dfifo_wr = 1; 129 end 130 EOP2: begin 131 next_state = DATA; 132 next_dcount = 15; 133 next_daddr = 1; 134 next_dbase = dbase + 1; 135 next_dfifo_in = 32'h00000001; // status 136 next_dfifo_wr = 1; 137 next_cfifo_in = { 1'b1, 4'd3, dbase, 6'd0 }; 138 next_cfifo_wr = 1; 139 end 140 endcase 141 end 142 143 always_ff @(posedge clk50) begin 144 state <= next_state; 145 dcount <= next_dcount; 146 daddr <= next_daddr; 147 dbase <= next_dbase; 148 cfifo_in <= next_cfifo_in; 149 dfifo_in <= next_dfifo_in; 150 cfifo_wr <= next_cfifo_wr; 151 dfifo_wr <= next_dfifo_wr; 152 end 153 154 reg fifo_reset = 0; 155 156 wire [31:0]dfifo_data; 157 wire dfifo_rd; 158 wire dfifo_empty; 159 wire dfifo_active; 160 161 wire [20:0]cfifo_data; 162 reg cfifo_rd = 0; 163 wire cfifo_empty; 164 wire cfifo_active; 165 166 // on reset request, assert fifo_reset until both fifos 167 // have started the sequence (fifo_active=0) 168 always @(posedge clk) begin 169 if (dfifo_active & cfifo_active) begin 170 if (reset) begin 171 fifo_reset <= 1; 172 end 173 end else if (~dfifo_active & ~cfifo_active) begin 174 fifo_reset <= 0; 175 end 176 end 177 178 // CMD: wrstatus wrdata count(12) 179 xilinx_async_fifo #( 180 .WIDTH(32) 181 ) dfifo ( 182 .wrclk(clk50), 183 .rdclk(clk), 184 .reset(fifo_reset), 185 .wr_data(dfifo_in), 186 .wr_en(dfifo_wr), 187 .rd_en(dfifo_rd), 188 .rd_data(dfifo_data), 189 .o_empty(dfifo_empty), 190 .o_ready(), 191 .o_active(dfifo_active) 192 ); 193 194 // CMD: burst(4) addr(16) -- addr is A[21:6] 195 196 xilinx_async_fifo #( 197 .WIDTH(21) 198 ) cfifo ( 199 .wrclk(clk50), 200 .rdclk(clk), 201 .reset(fifo_reset), 202 .wr_data(cfifo_in), 203 .wr_en(cfifo_wr), 204 .rd_en(cfifo_rd), 205 .rd_data(cfifo_data), 206 .o_empty(cfifo_empty), 207 .o_ready(), 208 .o_active(cfifo_active) 209 ); 210 211 reg [31:0]dma_base = BASE_ADDR; 212 213 // status writes are 4 words at byte offset 48 214 // data writes are always at byte offset 0 215 wire [5:0]dma_byte = cfifo_data[20] ? 6'd48 : 6'd0; 216 217 wire [31:0]dma_addr = { dma_base[31:22], cfifo_data[15:0], dma_byte }; 218 wire [3:0]dma_len = cfifo_data[19:16]; 219 wire dma_start = (~cfifo_empty) & (~dma_busy); 220 wire dma_busy; 221 222 always @(posedge clk) begin 223 if (cfifo_active & dfifo_active) begin 224 if (dma_start) begin 225 cfifo_rd <= 1; 226 end else begin 227 cfifo_rd <= 0; 228 end 229 end 230 end 231 232 axi_dma_writer dma0( 233 .clk(clk), 234 .m(axi_dma), 235 .addr(dma_addr), 236 .burstlen(dma_len), 237 .start(dma_start), 238 .busy(dma_busy), 239 .data(dfifo_data), 240 .advance(dfifo_rd) 241 ); 242 243 endmodule