📄 rx_elastic_buffer.v
字号:
//----------------------------------------------------------------------
// File : rx_elastic_buffer.v
// Author : Xilinx Inc.
//----------------------------------------------------------------------
// Copyright (c) 2007 by Xilinx, Inc. All rights reserved.
// This text/file contains proprietary, confidential
// information of Xilinx, Inc., is distributed under license
// from Xilinx, Inc., and may be used, copied and/or
// disclosed only pursuant to the terms of a valid license
// agreement with Xilinx, Inc. Xilinx hereby grants you
// a license to use this text/file solely for design, simulation,
// implementation and creation of design files limited
// to Xilinx devices or technologies. Use with non-Xilinx
// devices or technologies is expressly prohibited and
// immediately terminates your license unless covered by
// a separate agreement.
//
// Xilinx is providing this design, code, or information
// "as is" solely for use in developing programs and
// solutions for Xilinx devices. By providing this design,
// code, or information as one possible implementation of
// this feature, application or standard, Xilinx is making no
// representation that this implementation is free from any
// claims of infringement. You are responsible for
// obtaining any rights you may require for your implementation.
// Xilinx expressly disclaims any warranty whatsoever with
// respect to the adequacy of the implementation, including
// but not limited to any warranties or representations that this
// implementation is free from claims of infringement, implied
// warranties of merchantability or fitness for a particular
// purpose.
//
// Xilinx products are not intended for use in life support
// appliances, devices, or systems. Use in such applications are
// expressly prohibited.
//
// This copyright and support notice must be retained as part
// of this text at all times. (c) Copyright 2007 Xilinx, Inc.
// All rights reserved.
//----------------------------------------------------------------------
// Description: This is the Receiver Elastic Buffer for the design
// example of the Virtex-5 Ethernet MAC Wrappers.
//
// The FIFO is created from Block Memory, is of data width
// 32 (2 characters wide plus status) and is of depth 64
// words. This is twice the size of the elastic buffer in
// the RocketIO which has been bypassed,
//
// When the write clock is a few parts per million faster
// than the read clock, the occupancy of the FIFO will
// increase and Idles should be removed.
//
// When the read clock is a few parts per million faster
// than the write clock, the occupancy of the FIFO will
// decrease and Idles should be inserted. The logic in
// this example design will always insert as many idles as
// necessary in every Inter-frame Gap period to restore the
// FIFO occupancy.
//
// Note: the Idle /I2/ sequence is used as the clock
// correction character. This is made up from a /K28.5/
// followed by a /D16.2/ character.
`timescale 1 ns/1 ps
module rx_elastic_buffer
(
// Signals received from the RocketIO on RXRECCLK.
rxrecclk,
reset,
rxchariscomma_rec,
rxcharisk_rec,
rxdisperr_rec,
rxnotintable_rec,
rxrundisp_rec,
rxdata_rec,
// Signals reclocked onto RXUSRCLK2.
rxusrclk2,
rxreset,
rxchariscomma_usr,
rxcharisk_usr,
rxdisperr_usr,
rxnotintable_usr,
rxrundisp_usr,
rxclkcorcnt_usr,
rxbuferr,
rxdata_usr
);
// port declarations
input rxrecclk;
input reset;
input rxchariscomma_rec;
input rxcharisk_rec;
input rxdisperr_rec;
input rxnotintable_rec;
input rxrundisp_rec;
input [7:0] rxdata_rec;
input rxusrclk2;
input rxreset;
output rxchariscomma_usr;
output rxcharisk_usr;
output rxdisperr_usr;
output rxnotintable_usr;
output rxrundisp_usr;
output [2:0] rxclkcorcnt_usr;
output rxbuferr;
output [7:0] rxdata_usr;
reg rxchariscomma_usr;
reg rxcharisk_usr;
reg rxdisperr_usr;
reg rxnotintable_usr;
reg rxrundisp_usr;
reg rxbuferr;
reg [7:0] rxdata_usr;
//--------------------------------------------------------------------
// Constants to set FIFO thresholds
//--------------------------------------------------------------------
// FIFO occupancy over this level: clock correct to remove Idles
wire [6:0] upper_threshold;
assign upper_threshold = 7'b1000001;
// FIFO occupancy less than this level: clock correct to insert Idles
wire [6:0] lower_threshold;
assign lower_threshold = 7'b0111111;
// FIFO occupancy less than this, we consider it to be an underflow
wire [6:0] underflow_threshold;
assign underflow_threshold = 7'b0000011;
// FIFO occupancy greater than this, we consider it to be an overflow
wire [6:0] overflow_threshold;
assign overflow_threshold = 7'b1111100;
//--------------------------------------------------------------------
// Signal Declarations
//--------------------------------------------------------------------
// Write domain logic (RXRECCLK)
reg [15:0] wr_data; // Formatted the data word from RocketIO signals.
reg [15:0] wr_data_reg; // wr_data registered and formatting completed.
reg [15:0] wr_data_reg_reg; // wr_data_reg registered : to be written to the BRAM.
reg [6:0] next_wr_addr; // Next FIFO write address (to reduce latency in gray code logic).
reg [6:0] wr_addr; // FIFO write address.
wire wr_enable; // write enable for FIFO.
reg [6:0] wr_addr_gray; // wr_addr is converted to a gray code.
reg [6:0] wr_rd_addr_gray; // read address pointer (gray coded) reclocked onto the write clock domain).
wire [6:0] wr_rd_addr; // wr_rd_addr_gray converted back to binary (on the write clock domain).
reg [6:0] wr_occupancy; // The occupancy of the FIFO in write clock domain.
wire filling; // FIFO is filling up: Idles should be removed.
// synthesis attribute ASYNC_REG of wr_rd_addr_gray is "TRUE";
wire k28p5_wr; // /K28.5/ character is detected on data prior to FIFO.
wire d16p2_wr; // /D16.2/ character is detected on data prior to FIFO.
reg [2:0] d16p2_wr_pipe; // k28p5_wr registered.
reg [2:0] k28p5_wr_pipe; // d16p2_wr registered.
reg remove_idle; // An Idle is removed before writing it into the FIFO.
reg remove_idle_reg; // remove_idle registered.
// Read domain logic (RXUSRCLK2)
wire [15:0] rd_data; // Date read out of the block RAM.
reg [15:0] rd_data_reg; // rd_data is registered for logic pipeline.
reg [6:0] next_rd_addr; // Next FIFO read address (to reduce latency in gray code logic).
reg [6:0] rd_addr; // FIFO read address.
wire rd_enable; // read enable for FIFO.
reg [6:0] rd_addr_gray; // rd_addr is converted to a gray code.
reg [6:0] rd_wr_addr_gray; // write address pointer (gray coded) reclocked onto the read clock domain).
wire [6:0] rd_wr_addr; // rd_wr_addr_gray converted back to binary (on the read clock domain).
reg [6:0] rd_occupancy; // The occupancy of the FIFO in read clock domain.
wire emptying; // FIFO is emptying: Idles should be inserted.
wire overflow; // FIFO has filled up to overflow.
wire underflow; // FIFO has emptied to underflow
// synthesis attribute ASYNC_REG of rd_wr_addr_gray is "TRUE";
reg even; // To control reading of data from upper or lower half of FIFO word.
wire k28p5_rd; // /K28.5/ character is detected on data post FIFO.
wire d16p2_rd; // /D16.2/ character is detected on data post FIFO.
reg insert_idle; // An Idle is inserted whilst reading it out of the FIFO.
reg insert_idle_reg; // insert_idle is registered.
reg rd_enable_reg; // Read enable is registered.
reg [2:0] rxclkcorcnt; // derive RXCLKCORCNT to mimic RocketIO behaviour.
//--------------------------------------------------------------------
// FIFO write logic (Idles are removed as necessary).
//--------------------------------------------------------------------
// Reclock the RocketIO data and format for storing in the BRAM.
always @(posedge rxrecclk)
begin : gen_wr_data
if (reset === 1'b1)
begin
wr_data <= 16'b0;
wr_data_reg <= 16'b0;
wr_data_reg_reg <= 16'b0;
end
else
begin
wr_data_reg_reg <= wr_data_reg;
wr_data_reg[15:14] <= wr_data[15:14];
wr_data_reg[13] <= remove_idle;
wr_data_reg[12:0] <= wr_data[12:0];
// format the lower word
wr_data[15:13] <= 3'b0; // unused
wr_data[12] <= rxchariscomma_rec;
wr_data[11] <= rxcharisk_rec;
wr_data[10] <= rxdisperr_rec;
wr_data[9] <= rxnotintable_rec;
wr_data[8] <= rxrundisp_rec;
wr_data[7:0] <= rxdata_rec[7:0];
end
end // gen_wr_data
// Detect /K28.5/ character in upper half of the word from RocketIO
assign k28p5_wr = (wr_data[7:0] == 8'b10111100 &&
wr_data[11] == 1'b1) ? 1'b1 : 1'b0;
// Detect /D16.2/ character in upper half of the word from RocketIO
assign d16p2_wr = (wr_data[7:0] == 8'b01010000 &&
wr_data[11] == 1'b0) ? 1'b1 : 1'b0;
always @(posedge rxrecclk)
begin : gen_k_d_pipe
if (reset === 1'b1)
begin
k28p5_wr_pipe <= 3'b000;
d16p2_wr_pipe <= 3'b000;
end
else
begin
k28p5_wr_pipe[2:1] <= k28p5_wr_pipe[1:0];
d16p2_wr_pipe[2:1] <= d16p2_wr_pipe[1:0];
k28p5_wr_pipe[0] <= k28p5_wr;
d16p2_wr_pipe[0] <= d16p2_wr;
end
end // gen_k_d_pipe
// Create the FIFO write enable: Idles are removed by deasserting the
// FIFO write_enable whilst an Idle is present on the data.
always @(posedge rxrecclk)
begin : gen_wr_enable
if (reset === 1'b1)
begin
remove_idle <= 1'b0;
remove_idle_reg <= 1'b0;
end
else
begin
remove_idle_reg <= remove_idle;
// Idle removal (always leave the first /I2/ Idle, then every
// alternate Idle can be removed.
if (d16p2_wr == 1'b1 && k28p5_wr_pipe[0] == 1'b1 &&
d16p2_wr_pipe[1] == 1'b1 && k28p5_wr_pipe[2] == 1'b1 &&
filling == 1'b1 && remove_idle == 1'b0)
begin
remove_idle <= 1'b1;
end
// Else write new word on every clock edge.
else
begin
remove_idle <= 1'b0;
end
end
end // gen_wr_enable
assign wr_enable = ~(remove_idle | remove_idle_reg);
// Create the FIFO write address pointer.
always @(posedge rxrecclk)
begin : gen_wr_addr
if (reset === 1'b1)
begin
next_wr_addr <= 7'b1000001;
wr_addr <= 7'b1000000;
end
else if (wr_enable == 1'b1)
begin
next_wr_addr <= next_wr_addr + 7'b1;
wr_addr <= next_wr_addr;
end
end // gen_wr_addr
// Convert write address pointer into a gray code
always @(posedge rxrecclk)
begin : wr_addrgray_bits
if (reset === 1'b1)
wr_addr_gray <= 7'b1100001;
else
begin
wr_addr_gray[6] <= next_wr_addr[6];
wr_addr_gray[5] <= next_wr_addr[6] ^ next_wr_addr[5];
wr_addr_gray[4] <= next_wr_addr[5] ^ next_wr_addr[4];
wr_addr_gray[3] <= next_wr_addr[4] ^ next_wr_addr[3];
wr_addr_gray[2] <= next_wr_addr[3] ^ next_wr_addr[2];
wr_addr_gray[1] <= next_wr_addr[2] ^ next_wr_addr[1];
wr_addr_gray[0] <= next_wr_addr[1] ^ next_wr_addr[0];
end
end // wr_addrgray_bits;
//--------------------------------------------------------------------
// Instantiate a dual port Block RAM
//--------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -