📄 rx_client_fifo_8.v
字号:
rd_en <= 1'b1;
default :
rd_en <= !rd_dst_rdy_n;
endcase
end
// rd_addr_inc is used to enable the BRAM read address to increment
assign rd_addr_inc = rd_en;
// When the current frame is output, if there is no frame in the fifo, then
// the fifo must wait until a new frame is written in. This requires the read
// address to be moved back to where the new frame will be written. The pipe
// is then reloaded using the QUEUE states
assign rd_addr_reload = (rd_state == EOF_s && rd_nxt_state == WAIT_s) ? 1'b1 : 1'b0;
// Data is available if there is at leat one frame stored in the FIFO.
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
frame_in_fifo <= 1'b0;
else
if (rd_frames != 9'b0)
frame_in_fifo <= 1'b1;
else
frame_in_fifo <= 1'b0;
end
// when a frame has been stored need to convert to rd clock domain for frame
// count store.
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
begin
rd_store_frame_tog <= 1'b0;
rd_store_frame_sync <= 1'b0;
rd_store_frame_delay <= 1'b0;
rd_store_frame <= 1'b0;
end
else
begin
rd_store_frame_tog <= wr_store_frame_tog;
rd_store_frame_sync <= rd_store_frame_tog;
rd_store_frame_delay <= rd_store_frame_sync;
// edge detector
if ((rd_store_frame_delay ^ rd_store_frame_sync) == 1'b1)
rd_store_frame <= 1'b1;
else
rd_store_frame <= 1'b0;
end
end
assign rd_pull_frame = (rd_state == SOF_s && rd_nxt_state != SOF_s) ? 1'b1 :
(rd_state == QUEUE_SOF_s && rd_nxt_state != QUEUE_SOF_s) ? 1'b1 : 1'b0;
// Up/Down counter to monitor the number of frames stored within the
// the FIFO. Note:
// * decrements at the beginning of a frame read cycle
// * increments at the end of a frame write cycle
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
rd_frames <= 9'b0;
else
// A frame is written to the fifo in this cycle, and no frame is being
// read out on the same cycle
if (rd_store_frame == 1'b1 && rd_pull_frame == 1'b0)
rd_frames <= rd_frames + 1;
// A frame is being read out on this cycle and no frame is being
// written on the same cycle
else if (rd_store_frame == 1'b0 && rd_pull_frame == 1'b1)
rd_frames <= rd_frames - 1;
end
//---------------------------------------------------------------------------
// Write State machines and control
//---------------------------------------------------------------------------
// write state machine
// states are IDLE, FRAME, EOF, GF, BF, OVFLOW
// clock state to next state
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
wr_state <= IDLE_s;
else if (wr_enable == 1'b1)
wr_state <= wr_nxt_state;
end
// decode next state, combinatorial
always @(wr_state or wr_dv_pipe[1] or wr_gf_pipe[1] or wr_bf_pipe[1] or wr_eof_bram[0] or wr_fifo_full)
begin
case (wr_state)
IDLE_s : begin
// there is data in the incoming pipeline when dv_pipe(1) goes high
if (wr_dv_pipe[1] == 1'b1)
wr_nxt_state <= FRAME_s;
else
wr_nxt_state <= IDLE_s;
end
FRAME_s : begin
// if fifo is full then go to overflow state.
// if the good or bad flag is detected the end
// of the frame has been reached!
// this transistion occurs when the gb flag
// is on the clock edge immediately following
// the end of the frame.
// if the eof_bram signal is detected then data valid has
// fallen low and the end of frame has been detected.
if (wr_fifo_full == 1'b1)
wr_nxt_state <= OVFLOW_s;
else if (wr_gf_pipe[1] == 1'b1)
wr_nxt_state <= GF_s;
else if (wr_bf_pipe[1] == 1'b1)
wr_nxt_state <= BF_s;
else if (wr_eof_bram[0] == 1'b1)
wr_nxt_state <= END_s;
else
wr_nxt_state <= FRAME_s;
end
END_s : begin
// if frame is full then go to overflow state
// else wait until the good or bad flag has been received.
if (wr_gf_pipe[1] == 1'b1)
wr_nxt_state <= GF_s;
else if (wr_bf_pipe[1] == 1'b1)
wr_nxt_state <= BF_s;
else
wr_nxt_state <= END_s;
end
GF_s : begin
// wait for next frame
wr_nxt_state <= IDLE_s;
end
BF_s : begin
// wait for next frame
wr_nxt_state <= IDLE_s;
end
OVFLOW_s : begin
// wait until the good or bad flag received.
if (wr_gf_pipe[1] == 1'b1 || wr_bf_pipe[1] == 1'b1)
wr_nxt_state <= IDLE_s;
else
wr_nxt_state <= OVFLOW_s;
end
default : begin
wr_nxt_state <= IDLE_s;
end
endcase
end
// decode control signals
// wr_en is used to enable the BRAM write and loading of the input pipeline
assign wr_en = (wr_state == FRAME_s) ? 1'b1 : 1'b0;
// the upper and lower signals are used to distinguish between the upper and
// lower BRAM
assign wr_en_l = wr_en & !wr_addr[11];
assign wr_en_u = wr_en & wr_addr[11];
// increment the write address when we are receiving a frame
assign wr_addr_inc = (wr_state == FRAME_s) ? 1'b1 : 1'b0;
// if the fifo overflows or a frame is to be dropped, we need to move the
// write address back to the start of the frame. This allows the data to be
// overwritten.
assign wr_addr_reload = (wr_state == BF_s || wr_state == OVFLOW_s) ? 1'b1 : 1'b0;
// the start address is saved when in the WAIT state
assign wr_start_addr_load = (wr_state == IDLE_s) ? 1'b1 : 1'b0;
// we need to know when a frame is stored, in order to increment the count of
// frames stored in the fifo.
always @(posedge wr_clk)
begin // process
if (wr_sreset == 1'b1)
wr_store_frame_tog <= 1'b0;
else if (wr_enable == 1'b1)
if (wr_state == GF_s)
wr_store_frame_tog <= ! wr_store_frame_tog;
end
//---------------------------------------------------------------------------
// Address counters
//---------------------------------------------------------------------------
// write address is incremented when write enable signal has been asserted
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
wr_addr <= 12'b0;
else if (wr_enable == 1'b1)
if (wr_addr_reload == 1'b1)
wr_addr <= wr_start_addr;
else if (wr_addr_inc == 1'b1)
wr_addr <= wr_addr + 1;
end
// store the start address
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
wr_start_addr <= 12'b0;
else if (wr_enable == 1'b1)
if (wr_start_addr_load == 1'b1)
wr_start_addr <= wr_addr;
end
// read address is incremented when read enable signal has been asserted
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
rd_addr <= 12'b0;
else
if (rd_addr_reload == 1'b1)
rd_addr <= rd_addr - 2;
else if (rd_addr_inc == 1'b1)
rd_addr <= rd_addr + 1;
end
// which BRAM is read from is dependant on the upper bit of the address
// space. this needs to be registered to give the correct timing.
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
begin
rd_bram_u <= 1'b0;
rd_bram_u_reg <= 1'b0;
end
else if (rd_addr_inc == 1'b1)
begin
rd_bram_u <= rd_addr[11];
rd_bram_u_reg <= rd_bram_u;
end
end
//---------------------------------------------------------------------------
// Data Pipelines
//---------------------------------------------------------------------------
// register data inputs to bram
// no reset to allow srl16 target
always @(posedge wr_clk)
begin
if (wr_enable == 1'b1)
begin
wr_data_pipe[0] <= rx_data;
wr_data_pipe[1] <= wr_data_pipe[0];
wr_data_bram <= wr_data_pipe[1];
end
end
// no reset to allow srl16 target
always @(posedge wr_clk)
begin
if (wr_enable == 1'b1)
begin
wr_dv_pipe[0] <= rx_data_valid;
wr_dv_pipe[1] <= wr_dv_pipe[0];
wr_eof_bram[0] <= wr_dv_pipe[1] & !wr_dv_pipe[0];
end
end
// no reset to allow srl16 target
always @(posedge wr_clk)
begin
if (wr_enable == 1'b1)
begin
wr_gf_pipe[0] <= rx_good_frame;
wr_gf_pipe[1] <= wr_gf_pipe[0];
wr_bf_pipe[0] <= rx_bad_frame;
wr_bf_pipe[1] <= wr_bf_pipe[0];
end
end
// register data outputs from bram
// no reset to allow srl16 target
always @(posedge rd_clk)
begin
if (rd_en == 1'b1)
begin
rd_data_pipe_u <= rd_data_bram_u;
rd_data_pipe_l <= rd_data_bram_l;
if (rd_bram_u_reg == 1'b1)
rd_data_pipe <= rd_data_pipe_u;
else
rd_data_pipe <= rd_data_pipe_l;
end
end
// register data outputs from bram
always @(posedge rd_clk)
begin
if (rd_en == 1'b1)
if (rd_bram_u == 1'b1)
rd_eof <= rd_eof_bram_u[0];
else
rd_eof <= rd_eof_bram_l[0];
end
//---------------------------------------------------------------------------
// Overflow functionality
//---------------------------------------------------------------------------
// Take the Read Address Pointer and convert it into a grey code
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
rd_addr_gray <= 12'b0;
else
rd_addr_gray <= bin_to_gray(rd_addr);
end
// Resync the Read Address Pointer grey code onto the write clock
// NOTE: rd_addr_gray signal crosses clock domains
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
begin
wr_rd_addr_gray_sync <= 12'b0;
wr_rd_addr_gray <= 12'b0;
end
else if (wr_enable == 1'b1)
begin
wr_rd_addr_gray_sync <= rd_addr_gray;
wr_rd_addr_gray <= wr_rd_addr_gray_sync;
end
end
// Convert the resync'd Read Address Pointer grey code back to binary
assign wr_rd_addr = gray_to_bin(wr_rd_addr_gray);
// Obtain the difference between write and read pointers
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
wr_addr_diff <= 12'b0;
else if (wr_enable == 1'b1)
wr_addr_diff <= wr_rd_addr - wr_addr;
end
// Detect when the FIFO is full
// The FIFO is considered to be full if the write address
// pointer is within 0 to 3 of the read address pointer.
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
wr_fifo_full <= 1'b0;
else if (wr_enable == 1'b1)
if (wr_addr_diff[11:4] == 8'b0 && wr_addr_diff[3:2] != 2'b0)
wr_fifo_full <= 1'b1;
else
wr_fifo_full <= 1'b0;
end
assign overflow = (wr_state == OVFLOW_s) ? 1'b1 : 1'b0;
//--------------------------------------------------------------------
// FIFO Status Signals
//--------------------------------------------------------------------
// The FIFO status signal is four bits which represents the occupancy
// of the FIFO in 16'ths. To generate this signal we therefore only
// need to compare the 4 most significant bits of the write address
// pointer with the 4 most significant bits of the read address
// pointer.
// already have fifo status on write side through wr_addr_diff.
// calculate fifo status here and output on the wr clock domain.
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
wr_fifo_status <= 4'b0;
else if (wr_enable == 1'b1)
if (wr_addr_diff == 12'b0)
wr_fifo_status <= 4'b0;
else
begin
wr_fifo_status[3] <= !wr_addr_diff[11];
wr_fifo_status[2] <= !wr_addr_diff[10];
wr_fifo_status[1] <= !wr_addr_diff[9];
wr_fifo_status[0] <= !wr_addr_diff[8];
end
end
assign rx_fifo_status = wr_fifo_status;
//---------------------------------------------------------------------------
// Memory
//---------------------------------------------------------------------------
// Block Ram for lower address space (rx_addr(11) = 1'b0)
defparam ramgen_l.WRITE_MODE_A = "READ_FIRST";
defparam ramgen_l.WRITE_MODE_B = "READ_FIRST";
RAMB16_S9_S9 ramgen_l (
.WEA (wr_en_l),
.ENA (VCC),
.SSRA (wr_sreset),
.CLKA (wr_clk),
.ADDRA (wr_addr[10:0]),
.DIA (wr_data_bram),
.DIPA (wr_eof_bram),
.WEB (GND),
.ENB (rd_en),
.SSRB (rd_sreset),
.CLKB (rd_clk),
.ADDRB (rd_addr[10:0]),
.DIB (GND_BUS[7:0]),
.DIPB (GND_BUS[0:0]),
.DOA (),
.DOPA (),
.DOB (rd_data_bram_l),
.DOPB (rd_eof_bram_l));
// Block Ram for lower address space (rx_addr(11) = 1'b0)
defparam ramgen_u.WRITE_MODE_A = "READ_FIRST";
defparam ramgen_u.WRITE_MODE_B = "READ_FIRST";
RAMB16_S9_S9 ramgen_u (
.WEA (wr_en_u),
.ENA (VCC),
.SSRA (wr_sreset),
.CLKA (wr_clk),
.ADDRA (wr_addr[10:0]),
.DIA (wr_data_bram),
.DIPA (wr_eof_bram),
.WEB (GND),
.ENB (rd_en),
.SSRB (rd_sreset),
.CLKB (rd_clk),
.ADDRB (rd_addr[10:0]),
.DIB (GND_BUS[7:0]),
.DIPB (GND_BUS[0:0]),
.DOA (),
.DOPA (),
.DOB (rd_data_bram_u),
.DOPB (rd_eof_bram_u));
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -