summaryrefslogtreecommitdiff
path: root/usrp2/fpga/eth/rtl/verilog/elastic_buffer.v
blob: 56c821b7ecf00d686106e341b558502953c5d45a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93


module elastic_buffer
  ( input rx_clk,
    input tx_clk,
    input rst,
    
    input [7:0] rxd,
    input 	rx_dv,
    input 	rx_er,
    input 	crs,
    input 	col,
    
    output [7:0] rxd_ret,
    output 	 rx_dv_ret,
    output 	 rx_er_ret,
    output 	 crs_ret,
    output 	 col_ret );

   reg [3:0] 	 addr_wr,addr_wr_gray,awg_d1,awg_d2,addr_wr_gray_ret,awgr_d1,addr_wr_ungray,addr_rd;
   
   reg [11:0] 	 buffer [0:15];
   integer 	 i;
   initial
     for(i=0;i<16;i=i+1)
       buffer[i] <= 0;
   
   reg [7:0] 	 rxd_d1, rxd_d2;
   reg 		 rx_dv_d1,rx_er_d1,crs_d1,col_d1, rx_dv_d2,rx_er_d2,crs_d2,col_d2;		 
   wire 	 rx_dv_ret_adv;
   reg 		 rx_dv_ontime;

   always @(posedge rx_clk)
     {col_d1,crs_d1,rx_er_d1,rx_dv_d1,rxd_d1} <= {col,crs,rx_er,rx_dv,rxd};

   always @(posedge rx_clk)
     {col_d2,crs_d2,rx_er_d2,rx_dv_d2,rxd_d2} <= {col_d1,crs_d1,rx_er_d1,rx_dv_d1,rxd_d1};
   
   always @(posedge rx_clk)
     buffer[addr_wr] <= {col_d2,crs_d2,rx_er_d2,rx_dv_d1,rxd_d2};
   
   always @(posedge rx_clk or posedge rst)
     if(rst) addr_wr <= 0;
     else addr_wr <= addr_wr + 1;
   
   always @(posedge rx_clk)
     begin
	addr_wr_gray <= {addr_wr[3],^addr_wr[3:2],^addr_wr[2:1],^addr_wr[1:0]};
	awg_d1 <= addr_wr_gray;
	awg_d2 <= awg_d1;
     end
   
   always @(posedge tx_clk)
     begin
	addr_wr_gray_ret <= awg_d2;
	awgr_d1 <= addr_wr_gray_ret;
	addr_wr_ungray <= {awgr_d1[3],^awgr_d1[3:2],^awgr_d1[3:1],^awgr_d1[3:0]};
     end

   wire [3:0] addr_delta = addr_rd-addr_wr_ungray;
   reg 	[1:0] direction;
   localparam retard = 2'd0;
   localparam good = 2'd1;
   localparam advance = 2'd2;
   localparam wayoff = 2'd3;
   
   always @*
     case(addr_delta)
       4'd1, 4'd2, 4'd3, 4'd4, 4'd5 : direction <= retard;
       4'd15, 4'd14, 4'd13, 4'd12, 4'd11 : direction <= advance;
       4'd0 : direction <= good;
       default : direction <= wayoff;
     endcase // case(addr_delta)
	
   always @(posedge tx_clk or posedge rst)
     if(rst)
       addr_rd <= 0;
     else if(rx_dv_ret_adv | rx_dv_ontime)
       addr_rd <= addr_rd + 1;
     else
       case(direction)
	 retard : addr_rd <= addr_rd;
	 advance : addr_rd <= addr_rd + 2;
	 good : addr_rd <= addr_rd + 1;
	 wayoff : addr_rd <= addr_wr_ungray;
       endcase // case(direction)
   
   assign     {col_ret,crs_ret,rx_er_ret,rx_dv_ret_adv,rxd_ret} = buffer[addr_rd];
   always @(posedge tx_clk)
     rx_dv_ontime <= rx_dv_ret_adv;

   assign 	 rx_dv_ret = rx_dv_ontime;
endmodule // elastic_buffer