diff options
Diffstat (limited to 'eth/rtl/verilog/elastic_buffer.v')
-rw-r--r-- | eth/rtl/verilog/elastic_buffer.v | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/eth/rtl/verilog/elastic_buffer.v b/eth/rtl/verilog/elastic_buffer.v new file mode 100644 index 000000000..56c821b7e --- /dev/null +++ b/eth/rtl/verilog/elastic_buffer.v @@ -0,0 +1,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 |