How to get data from FIFO?

Questions and discussions about the Xillybus IP core and drivers

How to get data from FIFO?

Postby Cristian8 »

Hi,
I was trying to do a simple test of continuously and asynchronously storing data in a FIFO. Then serialize that data onto a pin. (Later I will need to take the data off the FIFO, do some processing on it, and then output it onto a pin). Right now I'm just trying to take the data off the FIFO and put it onto a pin. I tried to just make a simple asynchronous FIFO and combine it with the logic from the example in xillycapture along with my custom IP Core which just has a read and write 32. However, I can't seem to get the data from the FIFO to serialize it onto a pin. I'm using a Zybo board. How do I get the data from the FIFO and put it onto a pin? I've included

// Clock and quiesce
wire bus_clk;
wire quiesce;

// Wires related to /dev/xillybus_read_32
wire user_r_read_32_rden;
wire user_r_read_32_empty;
wire [31:0] user_r_read_32_data;
wire user_r_read_32_eof;
wire user_r_read_32_open;

// Wires related to /dev/xillybus_write_32
wire user_w_write_32_wren;
wire user_w_write_32_full;
wire [31:0] user_w_write_32_data;
wire user_w_write_32_open;

// Wires related to Xillybus Lite
wire user_clk;
wire user_wren;
wire user_rden;
wire [3:0] user_wstrb;
wire [31:0] user_addr;
wire [31:0] user_rd_data;
wire [31:0] user_wr_data;
wire user_irq;

xillybus xillybus_ins (

// Ports related to /dev/xillybus_read_32
// FPGA to CPU signals:
.user_r_read_32_rden(user_r_read_32_rden),
.user_r_read_32_empty(user_r_read_32_empty),
.user_r_read_32_data(user_r_read_32_data),
.user_r_read_32_eof(user_r_read_32_eof),
.user_r_read_32_open(user_r_read_32_open),

// Ports related to /dev/xillybus_write_32
// CPU to FPGA signals:
.user_w_write_32_wren(user_w_write_32_wren),
.user_w_write_32_full(user_w_write_32_full),
.user_w_write_32_data(user_w_write_32_data),
.user_w_write_32_open(user_w_write_32_open),

// Ports related to Xillybus Lite
.user_clk(user_clk),
.user_wren(user_wren),
.user_rden(user_rden),
.user_wstrb(user_wstrb),
.user_addr(user_addr),
.user_rd_data(user_rd_data),
.user_wr_data(user_wr_data),
.user_irq(user_irq),

// General signals
.PS_CLK(PS_CLK),
.PS_PORB(PS_PORB),
.PS_SRSTB(PS_SRSTB),
.clk_100(clk_100),
.otg_oc(otg_oc),
.DDR_Addr(DDR_Addr),
.DDR_BankAddr(DDR_BankAddr),
.DDR_CAS_n(DDR_CAS_n),
.DDR_CKE(DDR_CKE),
.DDR_CS_n(DDR_CS_n),
.DDR_Clk(DDR_Clk),
.DDR_Clk_n(DDR_Clk_n),
.DDR_DM(DDR_DM),
.DDR_DQ(DDR_DQ),
.DDR_DQS(DDR_DQS),
.DDR_DQS_n(DDR_DQS_n),
.DDR_DRSTB(DDR_DRSTB),
.DDR_ODT(DDR_ODT),
.DDR_RAS_n(DDR_RAS_n),
.DDR_VRN(DDR_VRN),
.DDR_VRP(DDR_VRP),
.MIO(MIO),
.PS_GPIO(PS_GPIO),
.DDR_WEB(DDR_WEB),
.GPIO_LED(GPIO_LED),
.bus_clk(bus_clk),
.hdmi_clk_n(hdmi_clk_n),
.hdmi_clk_p(hdmi_clk_p),
.hdmi_d_n(hdmi_d_n),
.hdmi_d_p(hdmi_d_p),
.hdmi_out_en(hdmi_out_en),
.quiesce(quiesce),
.vga4_blue(vga4_blue),
.vga4_green(vga4_green),
.vga4_red(vga4_red),
.vga_hsync(vga_hsync),
.vga_vsync(vga_vsync)
);

// Wires and registers related to data capturing
wire capture_clk;
reg [31:0] capture_data;
wire capture_en;
reg [4:0] slowdown;
wire capture_full;

reg capture_open;
reg capture_open_cross;
reg capture_has_been_full;
reg capture_has_been_nonfull;
reg has_been_full_cross;
reg has_been_full;

// Data capture section
// ====================

always @(posedge capture_clk)
begin
if (capture_en)
capture_data <= user_w_write_32_data; //Take data written to this file

// capture_has_been_full remembers that the FIFO has been full
// until the file is closed. capture_has_been_nonfull prevents
// capture_has_been_full to respond to the initial full condition
// every FIFO displays on reset.

if (!capture_full)
capture_has_been_nonfull <= 1;
else if (!capture_open)
capture_has_been_nonfull <= 0;

if (capture_full && capture_has_been_nonfull)
capture_has_been_full <= 1;
else if (!capture_open)
capture_has_been_full <= 0;
end

// The dependency on slowdown is only for bogus data
assign capture_en = capture_open && !capture_full &&
!capture_has_been_full;

// Clock crossing logic: bus_clk -> capture_clk
always @(posedge capture_clk)
begin
capture_open_cross <= user_r_read_32_open;
capture_open <= capture_open_cross;
end

// Clock crossing logic: capture_clk -> bus_clk
always @(posedge bus_clk)
begin
has_been_full_cross <= capture_has_been_full;
has_been_full <= has_been_full_cross;
end

// The user_r_read_32_eof signal is required to go from '0' to '1' only on
// a clock cycle following an asserted read enable, according to Xillybus'
// core API. This is assured, since it's a logical AND between
// user_r_read_32_empty and has_been_full. has_been_full goes high when the
// FIFO is full, so it's guaranteed that user_r_read_32_empty is low when
// that happens. On the other hand, user_r_read_32_empty is a FIFO's empty
// signal, which naturally meets the requirement.

assign user_r_read_32_eof = user_r_read_32_empty && has_been_full;
assign user_w_write_32_full = 0;

// The data capture clock here is bus_clk for simplicity, but clock domain
// crossing is done properly, so capture_clk can be an independent clock
// without any other changes.

assign capture_clk = bus_clk;

async_fifo_32x512 fifo_32 //FIFO created using Xilinx FIFO Generator Wizard
(
.rst(!user_r_read_32_open),
.wr_clk(capture_clk),
.rd_clk(bus_clk),
.din(capture_data),
.wr_en(capture_en),
.rd_en(user_r_read_32_rden),
.dout(user_r_read_32_data),
.full(capture_full),
.empty(user_r_read_32_empty)
);

//Signals for use in later programming after the test works
reg Q_en = 1'b0; //starting value is 0 because first 32bit is I
reg [31:0] data_outI = 32'd0;
reg [31:0] data_outQ = 32'd0;
reg I = 1'b0;
reg Q = 1'b0;
reg [5:0] counter_32_shift = 6'b000000;
reg temp = 1'b0;

reg serialization = 1'b0;
reg [31:0] fifo_data;

always @(posedge bus_clk) begin //serialization of bits onto pins I and Q
if (serialization == 1'b0 && counter_32_shift == 6'b000000) begin
fifo_data <= user_r_read_32_data; //read in fifo data to register to begin serializing
serialization <= 1'b1; //begin serializing
end else if (serialization == 1'b1) begin
if (counter_32_shift == 6'b100000) begin //counter_32_shift == 32
I <= fifo_data[0];
fifo_data <= (fifo_data >> 1);
Q <= fifo_data[0];
fifo_data <= (fifo_data >> 1);
counter_32_shift <= 6'b000000;
serialization <= 1'b0;
temp <= ~temp; //testing to make counter resets
end else begin
I <= fifo_data[0];
fifo_data <= (fifo_data >> 1);
Q <= fifo_data[0];
fifo_data <= (fifo_data >> 1);
counter_32_shift <= counter_32_shift + 6'b000001;
end
end // serialization check
end //end always

assign PS_GPIO_ONE_I = I; //Assign Pin I
assign PS_GPIO_TWO_Q = Q; //Assign Pin Q
assign PS_GPIO_FOUR_FULL = temp; //Assign testing pins

assign user_w_write_32_full = 0;
assign user_irq = 0; // No interrupts for now

Thank you!
Cristian8
 
Posts: 5
Joined:

Re: How to get data from FIFO?

Postby support »

Hello,

The xillycapture example shows how to capture data on the FPGA and transport it to the host. You seem to want to go in the opposite direction, so the example is unfortunately completely irrelevant.

Please take a look on Xilinx' FIFO IP core guide, or any other documentation regarding the meaning of the FIFO's signals and how it works.

Anyhow, what you should do, is to put a FIFO between the user_w_write_32_* signals and your own logic. What your logic should do, is maintaining a shift register, and load the data from the FIFO once every 32 clocks. If you don't care what happens when there's no data in the FIFO, it could go something like this:

Code: Select all
reg [31:0] shreg;
reg out;
reg [4:0] counter;

always @(posedge some_clk)
  begin
    counter <= counter + 1;
    if (counter == 0)
      shreg <= fifo_data_out;
    else
      shreg <= shreg >> 1;
    out <= shreg[0];
    fifo_rd_en <= (counter == 0);
  end


This is a very crude implementation, and I haven't tested it, but it will most likely work.

some_clk should be the same clock used to clock the FIFO's fifo_data_out and fifo_rd_en signals.

Ah, and if you want to be really lazy, create an asymmetric FIFO with Coregen: One with a 32-bit width on one side, and 1 bit on the other. Connect the 32-bit side to Xillybus' signals, and the 1-bit side to your serialized output. Just make sure to keep this FIFO's rd_en high all the time, and the 1-bit data will flow out continuously when there is data in the FIFO. When there's no data in the FIFO, the rd_en is ignored by the FIFO, so it's harmless to tie it to high.

Let the FIFO do the serializing for you.

Regards,
Eli
support
 
Posts: 802
Joined:

Re: How to get data from FIFO?

Postby alejandro »

I have a similar question. You said that code is if you don't care what happens when there's no data in the FIFO. However for me, it is important to know when there is data in the FIFO because I am storing data in the FIFO in a specific sequence. For example, I have a 32bit "A" stored followed by a stored 32bit "B" value in the FIFO. Afterwards, the FIFO saves in this alternating pattern of "A" and "B". I read in the FPGA programming guide that for the empty and full signals of the FIFO that "These two signals can go low at any moment, of course" which leads me to believe that I can't just start reading from the FIFO when something is stored in it. How do I make sure that I only start reading from the FIFO when there is something stored in the FIFO (That way the data read, which will be processed, will always correspond to its respective A or B value) ?

If the order for A and B get switched at all, then my outputs will be completely wrong. I tried to make a simple diagram of what I am trying to do below:

Code: Select all
host file                                    FPGA   

32bit A                                output A onto pin A
32bit B    ---->[FIFO]------->         output B onto pin B
32bit A                                output A onto pin A
32bit B                                output B onto pin B
...                                       ...
alejandro
 
Posts: 2
Joined:

Re: How to get data from FIFO?

Postby support »

Hi,

The general rule that applies to all FIFO access is that if you assert the rd_en input on a clock cycle for which its "empty" output is asserted, the rd_en is ignored. Likewise, if you assert the "wr_en" input when the "full" output is asserted, it's ignored as well.

In other words, no smoke will come out of the FPGA if these empty/full signals aren't respected, but the FIFO will not read a new element if it's empty, and not add one if it's full. In some applications, like in the serializer mentioned above, there's no problems with these overruns and underruns: If the FIFO is empty, we have junk in the serial output anyhow.

When the data ordering is significant, like in the A/B case, the logic should make sure that it knows when new data comes out from the FIFO.

For example, if you choose to keep rd_en tied high, let your logic monitor the "empty" output. If it was high, it should behave as if the clock edge never took place. Something like

Code: Select all
always @(posedge rd_clk)
  if (reset)
    data_state <= 0;
  else if (!empty)
   begin
     data_state <= !data_state;
     { ... handle data ... }
   end


It's also common to be extra careful with the rd_en signal:
Code: Select all
assign rd_en = !empty && i_want_some_data;

and then make the logic handling data enable on rd_en.

I hope this clarified this issue.

Regards,
Eli
support
 
Posts: 802
Joined:


Return to Xillybus

cron