📄 tx_client_fifo_8.v
字号:
end // gen_fd_addr // full duplex address counters
endgenerate
//---------------------------------------------------------------------------
generate if (FULL_DUPLEX_ONLY != 1) begin : gen_hd_addr
// 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_enable == 1'b1)
if (rd_addr_reload == 1'b1)
rd_addr <= rd_dec_addr;
else if (rd_start_addr_reload == 1'b1)
rd_addr <= rd_start_addr;
else if (rd_addr_inc == 1'b1)
rd_addr <= rd_addr + 1;
end
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
rd_start_addr <= 12'b0;
else if (rd_enable == 1'b1)
if (rd_start_addr_load == 1'b1)
rd_start_addr <= rd_addr - 4;
end
// Collision window expires after MAC has been transmitting for required slot
// time. This is 512 clock cycles at 1G. Also if the end of frame has fully
// been transmitted by the mac then a collision cannot occur.
// this collision expire signal goes high at 768 cycles from the start of the
// frame.
// inefficient for short frames, however should be enough to prevent fifo
// locking up.
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
rd_col_window_expire <= 1'b0;
else if (rd_enable == 1'b1)
if (rd_transmit_frame == 1'b1)
rd_col_window_expire <= 1'b0;
else if (rd_slot_timer[9:8] == 2'b11)
rd_col_window_expire <= 1'b1;
end
assign rd_idle_state = (rd_state == IDLE_s) ? 1'b1 : 1'b0;
always @(posedge rd_clk)
begin
if (rd_enable == 1'b1)
begin
rd_col_window_pipe[0] <= rd_col_window_expire & rd_idle_state;
if (rd_txfer_en == 1'b1)
rd_col_window_pipe[1] <= rd_col_window_pipe[0];
end
end
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1) // will not count until after first
// frame is sent.
rd_slot_timer <= 10'b0;
else if (rd_enable == 1'b1)
if (rd_transmit_frame == 1'b1) // reset counter
rd_slot_timer <= 10'b0;
// do not allow counter to role over.
// only count when frame is being transmitted.
else if (rd_slot_timer != 10'b1111111111)
rd_slot_timer <= rd_slot_timer + 1;
end
end // gen_hd_addr // half duplex address counters
endgenerate
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
rd_dec_addr <= 12'b0;
else if (rd_enable == 1'b1)
if (rd_addr_inc == 1'b1)
rd_dec_addr <= rd_addr - 1;
end
//---------------------------------------------------------------------------
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_enable == 1'b1)
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 input signals to fifo
// no reset to allow srl16 target
always @(posedge wr_clk)
begin
wr_data_pipe[0] <= wr_data;
if (wr_accept_pipe[0] == 1'b1)
wr_data_pipe[1] <= wr_data_pipe[0];
if (wr_accept_pipe[1] == 1'b1)
wr_data_bram <= wr_data_pipe[1];
end
// no reset to allow srl16 target
always @(posedge wr_clk)
begin
wr_sof_pipe[0] <= !wr_sof_n;
if (wr_accept_pipe[0] == 1'b1)
wr_sof_pipe[1] <= wr_sof_pipe[0];
end
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
begin
wr_accept_pipe[0] <= 1'b0;
wr_accept_pipe[1] <= 1'b0;
wr_accept_bram <= 1'b0;
end
else
begin
wr_accept_pipe[0] <= !wr_src_rdy_n & !wr_dst_rdy_int_n;
wr_accept_pipe[1] <= wr_accept_pipe[0];
wr_accept_bram <= wr_accept_pipe[1];
end
end
always @(posedge wr_clk)
begin
wr_eof_pipe[0] <= !wr_eof_n;
if (wr_accept_pipe[0] == 1'b1)
wr_eof_pipe[1] <= wr_eof_pipe[0];
if (wr_accept_pipe[1] == 1'b1)
wr_eof_bram[0] <= wr_eof_pipe[1];
end
// register data outputs from bram
// no reset to allow srl16 target
always @(posedge rd_clk)
begin
if (rd_enable == 1'b1)
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
// no reset to allow srl16 target
always @(posedge rd_clk)
begin
if (rd_enable == 1'b1)
if (rd_en == 1'b1)
begin
if (rd_bram_u == 1'b1)
rd_eof_pipe <= rd_eof_bram_u[0];
else
rd_eof_pipe <= rd_eof_bram_l[0];
rd_eof <= rd_eof_pipe;
rd_eof_reg <= rd_eof | rd_eof_pipe;
end
end
//---------------------------------------------------------------------------
generate if (FULL_DUPLEX_ONLY != 1) begin : gen_hd_input
// register the collision and retransmit signals
always @(posedge rd_clk)
begin
if (rd_enable == 1'b1)
rd_drop_frame <= tx_collision & !tx_retransmit;
end
always @(posedge rd_clk)
begin
if (rd_enable == 1'b1)
rd_retransmit <= tx_collision & tx_retransmit;
end
end // gen_hd_input // half duplex register input
endgenerate
//---------------------------------------------------------------------------
// Fifo full functionality
//---------------------------------------------------------------------------
// when full duplex full functionality is difference between read and write addresses.
// when in half duplex is difference between read start and write addresses.
// Cannot use gray code this time as the read address and read start addresses jump by more than 1
// generate an enable pulse for the read side every 16 read clocks. This provides for the worst case
// situation where wr clk is 20Mhz and rd clk is 125 Mhz.
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
rd_16_count <= 4'b0;
else if (rd_enable == 1'b1)
rd_16_count <= rd_16_count + 1;
end
assign rd_txfer_en = (rd_16_count == 4'b1111) ? 1'b1 : 1'b0;
// register the start address on the enable pulse
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
rd_addr_txfer <= 12'b0;
else if (rd_enable == 1'b1)
begin
if (rd_txfer_en == 1'b1)
rd_addr_txfer <= rd_start_addr;
end
end
// generate a toggle to indicate that the address has been loaded.
always @(posedge rd_clk)
begin
if (rd_sreset == 1'b1)
rd_txfer_tog <= 1'b0;
else if (rd_enable == 1'b1)
begin
if (rd_txfer_en == 1'b1)
rd_txfer_tog <= !rd_txfer_tog;
end
end
// pass the toggle to the write side
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
begin
wr_txfer_tog <= 1'b0;
wr_txfer_tog_sync <= 1'b0;
wr_txfer_tog_delay <= 1'b0;
end
else
begin
wr_txfer_tog <= rd_txfer_tog;
wr_txfer_tog_sync <= wr_txfer_tog;
wr_txfer_tog_delay <= wr_txfer_tog_sync;
end
end
// generate an enable pulse from the toggle, the address should have
// been steady on the wr clock input for at least one clock
assign wr_txfer_en = wr_txfer_tog_delay ^ wr_txfer_tog_sync;
// capture the address on the write clock when the enable pulse is high.
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
wr_rd_addr <= 12'b0;
else if (wr_txfer_en == 1'b1)
wr_rd_addr <= rd_addr_txfer;
end
// Obtain the difference between write and read pointers
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
wr_addr_diff <= 12'b0;
else
wr_addr_diff <= wr_rd_addr - wr_addr;
end
// Detect when the FIFO is full
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
wr_fifo_full <= 1'b0;
else
// The FIFO is considered to be full if the write address
// pointer is within 1 to 3 of the read address pointer.
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
// memory overflow occurs when the fifo is full and there are no frames
// available in the fifo for transmission. If the collision window has
// expired and there are no frames in the fifo and the fifo is full, then the
// fifo is in an overflow state. we must accept the rest of the incoming
// frame in overflow condition.
generate if (FULL_DUPLEX_ONLY == 1) begin : gen_fd_ovflow
// in full duplex mode, the fifo memory can only overflow if the fifo goes
// full but there is no frame available to be retranmsitted
// do not allow to go high when the frame count is being updated, ie wr_store_frame is asserted.
assign wr_fifo_overflow = (wr_fifo_full == 1'b1 && wr_frame_in_fifo == 1'b0
&& wr_eof_state == 1'b0 && wr_eof_state_reg == 1'b0) ? 1'b1 : 1'b0;
end // gen_fd_ovflow
endgenerate
generate if (FULL_DUPLEX_ONLY != 1) begin : gen_hd_ovflow
// register wr col window to give address counter sufficient time to update.
// do not allow to go high when the frame count is being updated, ie wr_store_frame is asserted.
assign wr_fifo_overflow = (wr_fifo_full == 1'b1 && wr_frame_in_fifo == 1'b0
&& wr_eof_state == 1'b0 && wr_eof_state_reg == 1'b0 && wr_col_window_expire == 1'b1) ? 1'b1 : 1'b0;
// register rd_col_window signal
// this signal is long, and will remain high until overflow functionality
// has finished, so save just to register the once.
always @(posedge wr_clk)
begin // process
if (wr_sreset == 1'b1)
begin
wr_col_window_pipe[0] <= 1'b0;
wr_col_window_pipe[1] <= 1'b0;
wr_col_window_expire <= 1'b0;
end
else
begin
if (wr_txfer_en == 1'b1)
wr_col_window_pipe[0] <= rd_col_window_pipe[1];
wr_col_window_pipe[1] <= wr_col_window_pipe[0];
wr_col_window_expire <= wr_col_window_pipe[1];
end
end
end // gen_hd_ovflow
endgenerate
//--------------------------------------------------------------------
// Create FIFO Status Signals in the Write Domain
//--------------------------------------------------------------------
// 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.
// The 4 most significant bits of the write pointer minus the 4 msb of
// the read pointer gives us our FIFO status.
always @(posedge wr_clk)
begin
if (wr_sreset == 1'b1)
wr_fifo_status <= 4'b0;
else
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
//---------------------------------------------------------------------------
// Memory
//---------------------------------------------------------------------------
assign rd_en_bram = rd_en & rd_enable_delay2;
// 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_bram),
.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_bram),
.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 + -