Документ взят из кэша поисковой машины. Адрес оригинального документа : http://www.naic.edu/~phil/hardware/pdev/fpga/gx/plinth/src/pi_fifo.v
Дата изменения: Thu Jun 26 04:26:02 2008
Дата индексирования: Sat Sep 6 20:09:43 2008
Кодировка:

Поисковые слова: п п п п п п п п п

// Jeff Mock
// 2030 Gough St.
// San Francisco, CA 94109
// jeff@mock.com
//
// Copyright 2005,2006
//
// $URL: https://www.mock.com/svn/pdev/trunk/gx/plinth/src/pi_fifo.v $
// $Id: pi_fifo.v 227 2006-06-25 05:01:23Z jeff $

// Small 32-entry 32-bit fifo using onchip memory.
// This is an async fifo with independent read and write
// clocks and is used for crossing the clock boundary from
// the ADC clock of the signal processor to the powerpc
// bus clock.
//
// This fifo uses the gray code technique for crossing the async
// boundary. Read and write pointers are kept in both binary
// and gray code. To calculate flow control (nearly full and
// empty) math needs to be done on the read and write pointers
// from differeing clock domains. The gray code version of
// the write pointer is moved across the clock boundary,
// converted back to binary and compared with the pointer
// in the current clock domain. I think Peter Alfke at Xilinx
// came up with this idea, but I'm not sure. It's a really
// clever way to implement async fifos that let you sleep at
// night.
//
// This fifo maintains two write pointers. An "early" write
// pointer is used for calculating full. Data is actually
// written using the regular write point and is used for
// calculating empty. This reduces the size of the skip
// needed by quite a lot so the fifo can be small.
//
// The low water mark (preg_pfifo_lwm) is the minimum number
// of entries in the FIFO before rd_okay is set. This is for
// the burst powerpc interface. The 440gx is setup for some
// burst size while doing DMA. rd_okay is used for the DMA
// request so the lwm should be set to the burst size used
// in the 440gx dma.
//
// The high water mark (preg_pfifo_hwm) should be set to
// 32-latency where latency is the read latency of of the
// pack_fifo. This is the skid necessary to stop the pack_fifo
// from putting stuff into pi_fifo. hwm is probably set to
// something like 24-26.

module pi_fifo (
wr_ck,
wr_reset,
wr,
wr_early,
wr_di,
wr_dip,
wr_okay,
wr_over,
wr_under,

preg_pfifo_lwm,
preg_pfifo_hwm,
preg_dma_bl,

rd_ck,
rd_reset,
rd,
rd_early,
rd_do,
rd_dop,
rd_okay,
rd_cnt,
rd_over,
rd_under
);

input wr_ck;
input wr_reset;
input wr;
input wr_early;
input [31:0] wr_di;
input [3:0] wr_dip;
output wr_okay;
output wr_over;
output wr_under;

// These register are all on rd_ck
input [4:0] preg_pfifo_lwm;
input [4:0] preg_pfifo_hwm;
input [3:0] preg_dma_bl;

input rd_ck;
input rd_reset;
input rd;
input [1:0] rd_early;
output [31:0] rd_do;
output [3:0] rd_dop;
output rd_okay;
output [4:0] rd_cnt;
output rd_over;
output rd_under;


//
// wr_ck domain
//


// Write pointer in write clock domain
wire [4:0] wrptr;
wire [4:0] wrptr_g;
pi_ptr pi_ptr_wr (
.ck ( wr_ck ),
.reset ( wr_reset ),
.inc ( wr ),
.ptr ( wrptr ),
.ptr_g ( wrptr_g )
);

// For long latency of write, maintain and early for purposes
// if computing wr_okay flag.
wire [4:0] wrptr_early;
wire [4:0] wrptr_g_early_nc;
pi_ptr pi_ptr_wre (
.ck ( wr_ck ),
.reset ( wr_reset ),
.inc ( wr_early ),
.ptr ( wrptr_early ),
.ptr_g ( wrptr_g_early_nc )
);

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// Move rdptr from rd_ck domain to wr_ck domain in gray code
// to compute wr_okay
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//
reg [4:0] rdptr_g_wrck;
wire [4:0] rdptr_wrck;
wire [4:0] rdptr_g;
always @(posedge wr_ck)
rdptr_g_wrck <= rdptr_g;
g2b_5 g2b_wrck (
.i ( rdptr_g_wrck ),
.o ( rdptr_wrck )
);

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// Move preg_pfifo_hwm to wr_ck domain to compute wr_okay
// This is a DC control register signal so it's not a cause
// for worry.
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//
reg [4:0] preg_pfifo_hwm_wrck;
always @(posedge wr_ck)
preg_pfifo_hwm_wrck <= preg_pfifo_hwm;

// Flow control for write side. Use early wrptr and rdptr
// re-clocked to wrck to calculate fifo count and indicate that
// it's okay to write if count is less than threshold.
//
reg wr_okay;
always @(posedge wr_ck)
wr_okay <= (wrptr_early - rdptr_wrck) < preg_pfifo_hwm_wrck;

// Keep track of FIFO pointers and barf if fifo overflows
//
reg [4:0] wr_cnt;
reg [4:0] wr_cnt_d1;
reg wr_over;
reg wr_under;
always @(posedge wr_ck) begin
if (wr_reset) begin
wr_cnt <= 5'd0;
wr_cnt_d1 <= 5'd0;
wr_under <= 1'b0;
wr_over <= 1'b0;
end else begin
wr_cnt <= wrptr - rdptr_wrck;
wr_cnt_d1 <= wr_cnt;
wr_under <= wr_under | (wr_cnt_d1<5'd4 && wr_cnt>5'd28);
wr_over <= wr_over | (wr_cnt<5'd4 && wr_cnt_d1>5'd28);
end
end


//
// rd_ck domain
//


// read pointer in rd_ck domain
//
wire [4:0] rdptr;
pi_ptr pi_ptr_rd (
.ck ( rd_ck ),
.reset ( rd_reset ),
.inc ( rd ),
.ptr ( rdptr ),
.ptr_g ( rdptr_g )
);

// To deassert dmareq to powerpc as soon as possible after a
// read request an early read pointer is maintained that increments
// by burst size at the beginning of the read. This is used
// to calculate rd_ready and deasserted as soon as possible
// when in turn will deassert the dma request.
//
wire [4:0] rdptr_early;
wire [4:0] rdptr_g_early_nc;
pi_ptr_e pi_ptr_rd_e (
.ck ( rd_ck ),
.reset ( rd_reset ),
.preg_dma_bl ( preg_dma_bl ),
.inc ( rd_early ),
.ptr ( rdptr_early ),
.ptr_g ( rdptr_g_early_nc )
);

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// Move wrptr (not early) to rd_ck domain in gray code
// to compute rd_okay
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//
reg [4:0] wrptr_g_rdck;
wire [4:0] wrptr_rdck;
always @(posedge rd_ck)
wrptr_g_rdck <= wrptr_g;
g2b_5 g2b_rdck (
.i ( wrptr_g_rdck ),
.o ( wrptr_rdck )
);

// Flow control for read side. Compare rdptr again wrptr
// re-clocked to rdck to calculate fifo count in indicate
// that it's okay to read if there is at least one burst
// of data in the fifo.
//
reg rd_okay;
always @(posedge rd_ck)
rd_okay <= (wrptr_rdck - rdptr_early) >= preg_pfifo_lwm;

// Keep track of FIFO pointers and barf if fifo overflows
//
reg [4:0] rd_cnt;
reg [4:0] rd_cnt_d1;
reg rd_over;
reg rd_under;
always @(posedge rd_ck) begin
if (rd_reset) begin
rd_cnt <= 5'd0;
rd_cnt_d1 <= 5'd0;
rd_under <= 1'b0;
rd_over <= 1'b0;
end else begin
rd_cnt <= wrptr_rdck - rdptr;
rd_cnt_d1 <= rd_cnt;
rd_under <= rd_under | (rd_cnt_d1<5'd4 && rd_cnt>5'd28);
rd_over <= rd_over | (rd_cnt<5'd4 && rd_cnt_d1>5'd28);
end
end


//
// The memory, write on wr_ck, read is combinatorial on
// rd_ck rdptr.
//


reg [35:0] mem [0:31];
always @(posedge wr_ck)
if (wr)
mem[wrptr] <= {wr_dip, wr_di};

wire [31:0] rd_do;
wire [3:0] rd_dop;
assign {rd_dop, rd_do} = mem[rdptr];
endmodule