📄 rx_elastic_buffer.v
字号:
RAMB16_S18_S18 dual_port_block_ram0
(
.ADDRA ({3'b0, wr_addr}),
.DIA (wr_data_reg_reg[15:0]),
.DIPA (2'b00),
.DOA (),
.DOPA (),
.WEA (wr_enable),
.ENA (1'b1),
.SSRA (1'b0),
.CLKA (rxrecclk),
.ADDRB ({3'b0, rd_addr}),
.DIB (16'b0),
.DIPB (2'b00),
.DOB (rd_data[15:0]),
.DOPB (),
.WEB (1'b0),
.ENB (1'b1),
.SSRB (rxreset),
.CLKB (rxusrclk2)
);
//--------------------------------------------------------------------
// FIFO read logic (Idles are insterted as necessary).
//--------------------------------------------------------------------
// Register the BRAM data.
always @(posedge rxusrclk2)
begin : reg_rd_data
if (rxreset == 1'b1)
rd_data_reg <= 16'b0;
else if (rd_enable_reg == 1'b1)
rd_data_reg <= rd_data;
end // reg_rd_data
//--------------------------------------------------------------------
// FIFO read logic (Idles are insterted as necessary).
//--------------------------------------------------------------------
// Detect /K28.5/ character in upper half of the word read from FIFO
assign k28p5_rd = (rd_data_reg[7:0] == 8'b10111100 &&
rd_data_reg[11] == 1'b1) ? 1'b1 : 1'b0;
// Detect /D16.2/ character in lower half of the word read from FIFO
assign d16p2_rd = (rd_data[7:0] == 8'b01010000 &&
rd_data[11] == 1'b0) ? 1'b1 : 1'b0;
// Create the FIFO read enable: Idles are inserted by pausing the
// FIFO read_enable whilst an Idle is present on the data.
always @(posedge rxusrclk2)
begin : gen_rd_enable
if (rxreset == 1'b1)
begin
even <= 1'b1;
insert_idle <= 1'b0;
insert_idle_reg <= 1'b0;
rd_enable_reg <= 1'b1;
end
else
begin
insert_idle_reg <= insert_idle;
rd_enable_reg <= rd_enable;
// Repeat as many /I2/ code groups as required if nearly
// empty by pausing rd_enable.
if ((k28p5_rd == 1'b1 && d16p2_rd == 1'b1) && emptying == 1'b1 && insert_idle == 1'b0)
begin
insert_idle <= 1'b1;
even <= 1'b0;
end
// Else read out a new word on every alternative clock edge.
else
begin
insert_idle <= 1'b0;
even <= ~(even);
end
end
end // gen_rd_enable
assign rd_enable = ~(insert_idle | insert_idle_reg);
// Create the FIFO read address pointer.
always @(posedge rxusrclk2)
begin : gen_rd_addr
if (rxreset == 1'b1)
begin
next_rd_addr <= 7'b0000001;
rd_addr <= 7'b0000000;
end
else if (rd_enable == 1'b1)
begin
next_rd_addr <= next_rd_addr + 7'b1;
rd_addr <= next_rd_addr;
end
end // gen_rd_addr
// Convert read address pointer into a gray code
always @(posedge rxusrclk2)
begin : rd_addrgray_bits
if (rxreset == 1'b1)
rd_addr_gray <= 7'b0;
else if (rd_enable == 1'b1)
begin
rd_addr_gray[6] <= next_rd_addr[6];
rd_addr_gray[5] <= next_rd_addr[6] ^ next_rd_addr[5];
rd_addr_gray[4] <= next_rd_addr[5] ^ next_rd_addr[4];
rd_addr_gray[3] <= next_rd_addr[4] ^ next_rd_addr[3];
rd_addr_gray[2] <= next_rd_addr[3] ^ next_rd_addr[2];
rd_addr_gray[1] <= next_rd_addr[2] ^ next_rd_addr[1];
rd_addr_gray[0] <= next_rd_addr[1] ^ next_rd_addr[0];
end
end // rd_addrgray_bits
// Create the output data signals.
always @(posedge rxusrclk2)
begin : gen_mux
if (rxreset == 1'b1)
begin
rxchariscomma_usr <= 1'b0;
rxcharisk_usr <= 1'b0;
rxdisperr_usr <= 1'b0;
rxnotintable_usr <= 1'b0;
rxrundisp_usr <= 1'b0;
rxdata_usr <= 8'b0;
end
else
begin
if (rd_enable_reg == 1'b0 && even == 1'b0)
begin
rxchariscomma_usr <= 1'b0;
rxcharisk_usr <= 1'b0;
rxdisperr_usr <= 1'b0;
rxnotintable_usr <= 1'b0;
rxrundisp_usr <= rd_data_reg[8];
rxdata_usr <= 8'b01010000;
end
else if (rd_enable_reg == 1'b0 && even == 1'b1)
begin
rxchariscomma_usr <= 1'b1;
rxcharisk_usr <= 1'b1;
rxdisperr_usr <= 1'b0;
rxnotintable_usr <= 1'b0;
rxrundisp_usr <= rd_data[8];
rxdata_usr <= 8'b10111100;
end
else
begin
rxchariscomma_usr <= rd_data_reg[12];
rxcharisk_usr <= rd_data_reg[11];
rxdisperr_usr <= rd_data_reg[10];
rxnotintable_usr <= rd_data_reg[9];
rxrundisp_usr <= rd_data_reg[8];
rxdata_usr <= rd_data_reg[7:0];
end
end
end // gen_mux
// Create RocketIO style clock correction status when inserting /
// removing Idles.
always @(posedge rxusrclk2)
begin : gen_rxclkcorcnt
if (rxreset == 1'b1)
rxclkcorcnt <= 3'b0;
else
begin
if (rd_data_reg[13] == 1'b1 && rxclkcorcnt[0] == 1'b0)
rxclkcorcnt <= 3'b001;
else if (insert_idle_reg == 1'b1 && rxclkcorcnt != 3'b111)
rxclkcorcnt <= 3'b111;
else
rxclkcorcnt <= 3'b000;
end
end // gen_rxclkcorcnt
assign rxclkcorcnt_usr = rxclkcorcnt;
//--------------------------------------------------------------------
// Create emptying/full thresholds in read clock domain.
//--------------------------------------------------------------------
// Reclock the write address pointer (gray code) onto the read domain.
// By reclocking the gray code, the worst case senario is that
// the reclocked value is only in error by -1, since only 1 bit at a
// time changes between gray code increments.
always @(posedge rxusrclk2)
begin : reclock_wr_addrgray
if (rxreset === 1'b1)
rd_wr_addr_gray <= 7'b1100001;
else
rd_wr_addr_gray <= wr_addr_gray;
end // reclock_wr_addrgray
// Convert the resync'd Write Address Pointer grey code back to binary
assign rd_wr_addr[6] = rd_wr_addr_gray[6];
assign rd_wr_addr[5] = rd_wr_addr_gray[6] ^ rd_wr_addr_gray[5];
assign rd_wr_addr[4] = rd_wr_addr_gray[6] ^ rd_wr_addr_gray[5]
^ rd_wr_addr_gray[4];
assign rd_wr_addr[3] = rd_wr_addr_gray[6] ^ rd_wr_addr_gray[5]
^ rd_wr_addr_gray[4] ^ rd_wr_addr_gray[3];
assign rd_wr_addr[2] = rd_wr_addr_gray[6] ^ rd_wr_addr_gray[5]
^ rd_wr_addr_gray[4] ^ rd_wr_addr_gray[3]
^ rd_wr_addr_gray[2];
assign rd_wr_addr[1] = rd_wr_addr_gray[6] ^ rd_wr_addr_gray[5]
^ rd_wr_addr_gray[4] ^ rd_wr_addr_gray[3]
^ rd_wr_addr_gray[2] ^ rd_wr_addr_gray[1];
assign rd_wr_addr[0] = rd_wr_addr_gray[6] ^ rd_wr_addr_gray[5]
^ rd_wr_addr_gray[4] ^ rd_wr_addr_gray[3]
^ rd_wr_addr_gray[2] ^ rd_wr_addr_gray[1]
^ rd_wr_addr_gray[0];
// Determine the occupancy of the FIFO as observed in the read domain.
always @(posedge rxusrclk2)
begin : gen_rd_occupancy
if (rxreset === 1'b1)
rd_occupancy <= 7'b1000000;
else
rd_occupancy <= rd_wr_addr - rd_addr;
end // gen_rd_occupancy
// Set emptying flag if FIFO occupancy is less than LOWER_THRESHOLD.
assign emptying = (rd_occupancy < lower_threshold) ? 1'b1 : 1'b0;
// Set underflow if FIFO occupancy is less than UNDERFLOW_THRESHOLD.
assign underflow = (rd_occupancy < underflow_threshold) ? 1'b1 : 1'b0;
// Set overflow if FIFO occupancy is less than OVERFLOW_THRESHOLD.
assign overflow = (rd_occupancy > overflow_threshold) ? 1'b1 : 1'b0;
// If either an underflow or overflow, assert the buffer error signal.
// Like the RocketIO, this will persist until a reset is issued.
always @(posedge rxusrclk2)
begin : gen_buffer_error
if (rxreset === 1'b1)
rxbuferr <= 1'b0;
else if (overflow == 1'b1 || underflow == 1'b1)
rxbuferr <= 1'b1;
end // gen_buffer_error
//--------------------------------------------------------------------
// Create emptying/full thresholds in write clock domain.
//--------------------------------------------------------------------
// Reclock the read address pointer (gray code) onto the write domain.
// By reclocking the gray code, the worst case senario is that
// the reclocked value is only in error by -1, since only 1 bit at a
// time changes between gray code increments.
always @(posedge rxrecclk)
begin : reclock_rd_addrgray
if (reset === 1'b1)
wr_rd_addr_gray <= 7'b0;
else
wr_rd_addr_gray <= rd_addr_gray;
end // reclock_rd_addrgray
// Convert the resync'd Read Address Pointer grey code back to binary
assign wr_rd_addr[6] = wr_rd_addr_gray[6];
assign wr_rd_addr[5] = wr_rd_addr_gray[6] ^ wr_rd_addr_gray[5];
assign wr_rd_addr[4] = wr_rd_addr_gray[6] ^ wr_rd_addr_gray[5]
^ wr_rd_addr_gray[4];
assign wr_rd_addr[3] = wr_rd_addr_gray[6] ^ wr_rd_addr_gray[5]
^ wr_rd_addr_gray[4] ^ wr_rd_addr_gray[3];
assign wr_rd_addr[2] = wr_rd_addr_gray[6] ^ wr_rd_addr_gray[5]
^ wr_rd_addr_gray[4] ^ wr_rd_addr_gray[3]
^ wr_rd_addr_gray[2];
assign wr_rd_addr[1] = wr_rd_addr_gray[6] ^ wr_rd_addr_gray[5]
^ wr_rd_addr_gray[4] ^ wr_rd_addr_gray[3]
^ wr_rd_addr_gray[2] ^ wr_rd_addr_gray[1];
assign wr_rd_addr[0] = wr_rd_addr_gray[6] ^ wr_rd_addr_gray[5]
^ wr_rd_addr_gray[4] ^ wr_rd_addr_gray[3]
^ wr_rd_addr_gray[2] ^ wr_rd_addr_gray[1]
^ wr_rd_addr_gray[0];
// Determine the occupancy of the FIFO as observed in the write domain.
always @(posedge rxrecclk)
begin : gen_wr_occupancy
if (reset === 1'b1)
wr_occupancy <= 7'b1000000;
else
wr_occupancy <= wr_addr[6:0] - wr_rd_addr[6:0];
end // gen_wr_occupancy
// Set filling flag if FIFO occupancy is greated than UPPER_THRESHOLD.
assign filling = (wr_occupancy > upper_threshold) ? 1'b1 : 1'b0;
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -