精华内容
下载资源
问答
  • FIFO

    千次阅读 2015-11-10 17:49:23
    有名管道又称为FIFO,是进程间通信的一种方式。FIFO具有以下特点: 1.全双工的通信模式,数据先进先出; 2.可以用于任意的进程之间,通过指定相同的管道文件进行通信; 3.文件名存在文件系统中,而管道中的内容存在...

    有名管道又称为FIFO,是进程间通信的一种方式。FIFO具有以下特点:
    1.全双工的通信模式,数据先进先出;
    2.可以用于任意的进程之间,通过指定相同的管道文件进行通信;
    3.文件名存在文件系统中,而管道中的内容存在于内存中。可通过open()、read()和write()对其操作;

    使用FIFO的步骤如下:
    一、创建/打开一个FIFO
    FIFO是一种文件类型,在Linux系统中FIFO的类型用p表示。如下所示:

    $ ls -l
    total 8
    drwxr-xr-x   2 abc abc 4096 1110 17:50 ./
    drwxrwxr-x   4 abc abc 4096 1110 17:50 ../
    prw-r--r--   1 abc abc    0 1110 17:50 a_fifo|
    -rw-r--r--   1 abc abc    0 1110 17:50 a_txt
    

    可以看到,虽然FIFO文件存在于文件系统中(可供不同的进程打开),但FIFO中的内容都存放在内存中,所以文件大小始终为0。

    由于FIFO不是普通文件,所以只能用文件IO来访问。

    int mkfifo(const char *path, mode_t mode);

    函数mkfifo用于创建一个有名管道,参数path指定要创建的FIFO的路径,mode为该管道文件的访问权限,一般用八进制数表示。

    int open(const char *path, int oflag, ... );

    函数open通过指定路径打开一个文件,不同的进程可以调用open打开同一个FIFO进行通信。参考下面的代码(相关头文件省略)

    #define BUF_SIZE 51
    int main(int argc, char *argv[])
    {
        int fd;
        ssize_t n;
        char buf[BUF_SIZE];
        if ( argc <2)
        {
            fprintf(stdout, “Usage: %s n”, argv[0]);
            exit(1);
        }
        if ( mkfifo(argv[1], 0666) < 0 ) // 创建FIFO失败
        {
            if (errno != EEXIST ) // 出错原因不是因为管道已存在
            {
                fprintf(stderr, “mkfifo() failed %sn”, strerror(errno));
                exit(-1);
            }
        }
        if ( (fd = open(argv[1], O_RDWR)) < 0 ) // 打开FIFO出错
        { // 注:< 优先级要高于 =
            fprintf(stderr, “open() failed %sn”, strerror(errno));
            exit(-1);
        }
        …
        return 0;
    }
    

    二、读/写FIFO
    进程打开FIFO后,就可以根据open时指定的选项对其进行相应的读/写操作:

    #include
    ssize_t read(int fildes, void *buf, size_t nbyte);
    ssize_t write(int fildes, const void *buf, size_t nbyte);
    ……
    if ((n = read(fd, buf, BUF_SIZE)) < 0 )
    {
        fprintf(stderr, “read() failed %sn”, strerror(errno));
        exit(-1);
    }
    else if ( n = = 0 )
    {
        fprintf(stdout, “all write sides are closed…n”);
        exit(-1);
    }
    else
    {
        fprintf(stdout, “read %d bytes from FIFO : %sn”, n, buf);
    }
    ……
    

    对FIFO的写操作,大家可以仿照上面的代码。

    最后总结一下在使用FIFO时要注意的问题:

    1. 在用open打开FIFO时有可能会阻塞,原因就是当前只有读端或写端存在。换句话说,如果程序在打开FIFO时指定了只读方式/只写方式,那么该进程对于打开的FIFO来说就是一个读端/写端。如果指定的是读写方式,那么进程既是读端又是写端。
    2. 从FIFO中读数据时(用read函数),如果没有数据,默认是阻塞等待,直到有数据被写入FIFO。如果read函数返回0,说明该FIFO所有的写端都已关闭,程序要做相应的处理。向FIFO写入数据时(使用write函数),如果FIFO有足够空间,write函数会返回写入的字节数;如果空间不够,write函数会阻塞,直到写完为止。当所有的读端都关闭时,再向FIFO写数据会出错。内核会向写进程发管道断裂的信号(SIGPIPE), 从而终止该进程。处理的办法有两种:程序以读写方式打开FIFO或是在程序中捕捉SIGPIPE信号,由用户自行处理。
    展开全文
  • FIFO 管道

    2019-10-08 14:23:27
    和写对应两个文件描述符 数据写流入,读流出 操作管道的进程被销毁之后,管道自动释放 管道默认是阻塞的 管道原理 内部实现方式:队列 1. 环形队列 2. 特点:先进先出 缓冲区大小: 默认4K 大小会...

    管道的概念
    本质:内核缓冲区
    伪文件–不占用磁盘空间
    特点:

    1. 读端和写端对应两个文件描述符

    2. 数据写端流入,读端流出

    3. 操作管道的进程被销毁之后,管道自动释放

    4. 管道默认是阻塞的
      管道原理
      内部实现方式:队列
      1. 环形队列
      2. 特点:先进先出
      缓冲区大小:
      默认4K
      大小会根据实际情况进行调整;
      管道的局限性
      队列:
      数据只能读取一次,不能直接进行读取
      半双工:
      匿名管道;
      适用于血缘关系的进程
      创建匿名管道
      int pipe(int fd[2]);
      fd - 传出参数
      fd[0]—读端
      fd[1]—写端

      管道的局限性

      1 FIFO

    2 特点

    1,有名管道
    2, 在磁盘上,有这样一个文件 ls -l ->p
    3,伪文件,在磁盘上的大小永远是0
    4,在内核中,有一个对应的缓冲区
    3,半双工的通信方式

    2 使用场景

    1,没有血缘关系的进程间通信

    3 创建方式

    命令:mkfifo 管道通信
    函数:mkfifo

    4 FIFO 文件可以使用函数进行操作

    1 open/close
    2 read / write
    3 不能执行lseek操作

    5 进程间通信

    1 FIFO文件 没有FIFO
    两个不相干的进程A B
    进程A 进行——》read

    int fd =  open ("myfifo",O_RDONLY);
    read (fd,buf,sizeof(buf));
    close(fd);
    

    进程B 进行写操作

    int fd1 = open("myfifo",O_WRONLY);
    write(fd1,"hello,world",11);
    close (fd1);
    
    
    
    展开全文
  • 使用有名fifo实现进程间通信

    有名fifo默认是阻塞读,阻塞写的,如果要设置阻塞属性,可以再open()的时候进行设置

    在阻塞情况下:实现服务器端可以不断读取客户端写到管道里面的文件流

    这个里面有个重要的问题时,如果使用服务器端进行read(),读的buf的大小是多少呢?如果每一个客户端每次传过来的buf大小都不一样,那么服务器端使用read函数必然会造成数据读取不完整或者超出实际写进去的,这是因为,对于多个进程都在向fifo文件中写时,一个进程一个进程将要写的内容写进去,如果在读buf大小的数据的时候,有两个进程一前一后写入数据(在下次read()之前),那么这两个进程的写入数据就会混乱的读入读进程。

    为了解决这一问题:

    关键:统一buf的大小,也就是write read函数每次操作的buf的大小都是确定的,这样的话,每一个进程的数据就有了“原子性”,被封装在一个buf中,保证每一次读,都是一个完整的数据包

    比如:

    客户端有登录包,发送信息给其他客户端的信息包等等,将不同包的内容封装,这里就像一个协议,不同的数据包有不同的编号,比如,登录包,编号为1,信息包编号为2,这样,讲将要传递的内容拼接在一起,作为长度固定的整体,如果长度不够,填充特殊字符,就像ip数据报一样,这样,按照不同编号,服务器也对应了不同的解析buf的方法,这样就保证多个进程的数据可以完整的传递到服务器端了

    代码:

    client_0

    #include <stdio.h>
    #include <unistd.h>
    #include <error.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdlib.h>

    #define BUF_SIZE 1024

    void sys_err(char *errmes,int errno){
            perror(errmes);
            exit(errno);
    }

    int main(int argc ,char **argv){

            pid_t pid;
            int fd,i;
            char  buf[BUF_SIZE];
            if(argc<2){
                    printf("usage:./client filename");
                    exit(1);
            }
            if((fd=open(argv[1],O_WRONLY))<0){
                    sys_err("open",3);
            }
            while(1){
                    write(fd,"helloclient_0",13); //将buf的长度定为13个字节
                    sleep(1);
            }
            close(fd);
            return 0;
    }

    server.c

    int main(int argc ,char **argv){

            pid_t pid;
            int fd,n;
            int buf[BUF_SIZE];
            if(argc<2){
                    printf("usage:./server filename");
                    exit(1);
            }
            //创建一个fifo
            //先判断该文件是否存在,如果不存在再创建,存在就不创建了
            if(access(argv[1],F_OK)==-1){
                    if(mkfifo(argv[1],0777)<0){
                            sys_err("mkfifo",2);
                    }
            }
            //打开该fifo
            if((fd=open(argv[1],O_RDONLY))<0){
                    sys_err("open",3);
            }
            //注册信号
            signal(SIGCHLD,sig_child);
            //从fifo循环接收传递进来的数据
            while(1){
                    if((n=read(fd,&buf,13))){   //read函数的buf也是13个字节
                            printf("%s\n",buf);
                    }else{
                            continue;
                    }
                    sleep(1);
            }
            close(fd);
            return 0;
    }

    上面的两段代码,只是简单的表示了一下文字的代码形式,关于实际的协议定义,还需要推敲,并且buf的大小也要根据协议而定;对于不同的

    协议,有不同的拼接填充方式以及解析方式,代码中只是简单实现了

    1.使用mkfifo()函数新建一个fifo文件

    2.使用open()打开函数打开该文件(可设置阻塞属性)

    3.向文件中读写

    ps:如果只有一个读端,并且先关闭读端的话,写端将进程也将结束

          如果先没有fifo读端,无法运行fifo写端(这里还不是很清楚)

    展开全文
  • 同步FIFO和异步FIFO总结

    千次阅读 多人点赞 2020-09-17 17:06:09
    FIFO简介2. 使用场景3. 分类4. FIFO的常见参数5. FIFO设计5.1 空满标志生成5.2 异步FIFO的设计还要注意跨时钟域问题5.3 gray码如何判断空满`6. 同步FIFO实现`7. 异步FIFO实现8. 对FIFO进行约束9. 关于异步FIFO最小...

    1. FIFO简介

    FIFO是一种先进先出数据缓存器,它与普通存储器的区别是没有外部读写地址线,使用起来非常简单,缺点是只能顺序读写,而不能随机读写。

    2. 使用场景

    1. 数据缓冲:也就是数据写入过快,并且间隔时间长,也就是突发写入。那么通过设置一定深度的FIFO,可以起到数据暂存的功能,且使得后续处理流程平滑。
    2. 时钟域的隔离:主要用异步FIFO。对于不同时钟域的数据传输,可以通过FIFO进行隔离,避免跨时钟域的数据传输带来的设计和约束上的复杂度。比如FIFO的一端是AD,另一端是PCI;AD的采集速率是16位100KSPS,每秒的数据量是1.6Mbps。而PCI总线的速度是33MHz,总线宽度是32位
    3. 用于不同宽度的数据接口。例如单片机是8位,DSP是16。

    3. 分类

    同步FIFO:指读时钟和写时钟是同一个时钟
    异步FIFO:指读写时钟是不同的时钟。

    4. FIFO的常见参数

    • FIFO的宽度:即FIFO一次读写操作的数据位;
    • FIFO的深度:指的是FIFO可以存储多少个N位的数据(如果宽度为N)。
    • 满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。
    • 空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。
    • 读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
    • 写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。

    5. FIFO设计

    5.1 空满标志生成

    1. FIFO设计的关键是产生可靠的FIFO读写指针和生成FIFO空/满状态标志。
      当读写指针相等时,表明FIFO为空,这种情况发生在复位操作时;或者当读指针读出FIFO中最后一个字后,追赶上了写指针时,这时FIFO处于满的状态。
      为了区分到底是满状态还是空状态,可以采用以下方法:
      方法1:在指针中添加一个额外的位(extra bit),当写指针增加并越过最后一个FIFO地址时,就将写指针这个未用的MSB加1,其它位回零。对读指针也进行同样的操作。此时,对于深度为2^n的FIFO,需要的读/写指针位宽为(n+1)位,如对于深度为8的FIFO,需要采用4bit的计数器,0000~1000、1001~1111,MSB作为折回标志位,而低3位作为地址指针。
    • 如果两个指针的MSB不同,说明写指针比读指针多折回了一次;如r_addr=0000,而w_addr = 1000,为满。
    • 如果两个指针的MSB相同,则说明两个指针折回的次数相等。其余位相等,说明FIFO为空;

    5.2 异步FIFO的设计还要注意跨时钟域问题

    将一个二进制的计数值从一个时钟域同步到另一个时钟域的时候很容易出现问题,因为采用二进制计数器时所有位都可能同时变化,在同一个时钟沿同步多个信号的变化会产生亚稳态问题。而使用格雷码只有一位变化,因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到gray码的转换电路,将地址值转换为相应的gray码,然后将该gray码同步到另一个时钟域进行对比,作为空满状态的检测

    5.3 gray码如何判断空满

    对于“空”的判断:依然依据二者完全相等(包括MSB);
    对于“满”的判断:如下图,由于gray码除了MSB外,具有镜像对称的特点,当读指针指向7,写指针指向8时,除了MSB,其余位皆相同,不能说它为满。因此不能单纯的只检测最高位了,在gray码上判断为满必须同时满足以下3条:

    • wptr和同步过来的rptr的MSB不相等,因为wptr必须比rptr多折回一次。
    • wptr与rptr的次高位不相等,如上图位置7和位置15,转化为二进制对应的是0111和1111,MSB不同说明多折回一次,111相同代表同一位置。
    • 剩下的其余位完全相等

    6. 同步FIFO实现

    image.png
    参考链接:https://blog.csdn.net/HengZo/article/details/49683707

    代码的核心部分主要是data_count,并且full 信号是当data_count == DATA_DEPTH时拉高,除了data_count之外,还可以同过判断r_ptr和w_ptr两个指针是否相等来判断空,满信号
    ssign empty = (w_ptr == r_ptr) ? 1 : 0;
    assign full = (w_ptr[2:0] == r_ptr[2:0] && (w_ptr[3] == ~r_ptr[3])) ? 1 : 0;

    • 这里还有一个注意的点,也就是w_ptr++会越界,同步FIFO就算用data_cnt来判断空满条件,在存数据和写数据时还是应该用w_ptr来表示,如果直接用data_cnt来表示,那么设计的就是一个栈而不是FIFO了。
    module syn_fifo(
    	clk,
    	rst_n,
    	data_in,
    	w_en,
    	full,
    	data_out,
    	r_en,
    	empty);
    
    parameter DATA_WIDTH = 8;
    parameter DATA_DEPTH = 16;
    parameter ADDR_WIDTH = 4;
    
    input wire clk, rst_n;
    input wire [DATA_WIDTH-1:0] data_in;
    input wire w_en, r_en;
    
    output wire empty, full;
    output reg [DATA_WIDTH-1:0] data_out;
    
    reg [ADDR_WIDTH   : 0] data_count;
    reg [ADDR_WIDTH-1 : 0] w_ptr, r_ptr;
    reg [DATA_WIDTH-1 : 0] mem[0 : DATA_DEPTH-1];
    
    assign empty = (data_count == 'd0) ? 1 : 0;
    assign full = (data_count == DATA_DEPTH) ? 1 : 0; //data_count == DATA_DEPTH
    
    always @ (posedge clk or negedge rst_n) begin
    	if (!rst_n)
    		data_count <= 'd0;
    	else if (w_en && r_en)
    		data_count <= data_count;
    	else if (!full && w_en)
    		data_count <= data_count + 1'b1;
    	else if (!empty && r_en)
    		data_count <= data_count - 1'b1;
    	else
    		data_count <= data_count;
    end
    
    always @ (posedge clk  or negedge rst_n) begin
    	if (!rst_n)
    		mem[w_ptr] <= 'd0;
    	else if (!full && w_en)
    		mem[w_ptr] <= data_in;
    end
    
    always @ (posedge clk or negedge rst_n) begin
    	if (!rst_n)
    		w_ptr <= 'd0;
    	else if (w_en && !full)
    		w_ptr <= w_ptr + 1'b1;
    	else
    		w_ptr <= w_ptr;
    end
    
    always @ (posedge clk or negedge rst_n) begin
    	if (!rst_n)
    		r_ptr <= 'd0;
    	else if (r_en && !empty)
    		r_ptr <= r_ptr + 1'b1;
    	else
    		r_ptr <= r_ptr;
    end
    
    always @ (posedge clk  or negedge rst_n) begin
    	if (!rst_n)
    		data_out <= 'd0;
    	else if (!empty && r_en)
    		data_out <= mem[r_ptr];
    end
    
    endmodule
    

    7. 异步FIFO实现

    设计难点:

    1. 跨时钟域数据比较,需要用到同步器,减少亚稳态的传递
    2. 用到gray码,进一步减少亚稳态的产生
    3. gray码相等信号的比较 空:两个gray码相等 满:高两位相反,其余位相同。
    4. 指针计数需要比ADDR的位宽多一位,这一点和同步FIFO的设计是一样的。
      image.png

    https://www.cnblogs.com/BitArt/archive/2013/04/10/3010073.html

    module asyn_fifo(
    	clk_w,
    	clk_r,
    	rst_n,
    	r_en,
    	w_en,
    	data_in,
    	data_out,
    	full,
    	empty
    	);
    
    input wire clk_r, clk_w, rst_n;
    
    input wire r_en, w_en;
    
    input wire [7:0] data_in;
    
    output wire full, empty;
    output reg [7:0] data_out;
    
    parameter DATA_DEPTH = 8;
    parameter DATA_WIDTH = 8;
    
    parameter ADDR_WIDTH = 3;
    
    reg [3:0] w_ptr, r_ptr;
    
    reg [7:0] mem[DATA_DEPTH-1 : 0];
    
    
    always @ (posedge clk_w or negedge rst_n) begin
    	if (~rst_n)
    		w_ptr <= 'd0;
    	else if (w_en && !full)
    		w_ptr <= w_ptr + 1'b1;
    	else
    		w_ptr <= w_ptr;
    end
    wire [3:0] w_ptr_gray, r_ptr_gray;
    
    assign w_ptr_gray = w_ptr ^ (w_ptr >> 1);
    assign r_ptr_gray = r_ptr ^ (r_ptr >> 1);
    
    //
    reg [ADDR_WIDTH:0] rd1_wp, rd2_wp;
    always @ (posedge clk_r or negedge rst_n) begin
    	if (!rst_n) begin
    		rd1_wp <= 'd0;
    		rd2_wp <= 'd0;
    	end else begin
    		rd1_wp <= w_ptr_gray;
    		rd2_wp <= rd1_wp;
    	end
    end
    
    assign empty = (rd2_wp == r_ptr_gray) ? 1 : 0;
    
    
    always @ (posedge clk_r or negedge rst_n) begin
    	if (~rst_n)
    		r_ptr <= 'd0;
    	else if (r_en && !empty)
    		r_ptr <= r_ptr + 1'b1;
    	else
    		r_ptr <= r_ptr;
    end
    //wire [ADDR_WIDTH:0] r_ptr_gray;
    
    assign r_ptr_gray = r_ptr ^ (r_ptr >> 1);
    
    reg [ADDR_WIDTH:0] wd1_rp, wd2_rp;
    always @ (posedge clk_w or negedge rst_n) begin
    	if (~rst_n) begin
    		wd1_rp <= 'd0;
    		wd2_rp <= 'd0;
    	end
    	else begin
    		wd1_rp <= r_ptr_gray;
    		wd2_rp <= wd1_rp;
    	end
    end
    
    assign full = ({(~wd2_rp[ADDR_WIDTH:ADDR_WIDTH-1]),wd2_rp[ADDR_WIDTH-2:0]} == w_ptr_gray) ? 1:0;
    
    always @ (posedge clk_w or negedge rst_n) begin
    	if (~rst_n)
    		mem[w_ptr] <= 'd0;
    	else if (!empty && rd_en)
    		mem[w_ptr] <= data_in;
    end
    
    always @ (posedge clk_r or negedge rst_n) begin
    	if (~rst_n)
    		data_out <= 'd0;
    	else if (!full && w_en)
    		data_out <= mem[r_ptr];
    end
    endmodule
    

    8. 对FIFO进行约束

    set_false_path
    在设计中,不需要满足setup/hold时序的数据路径需要设置成false path
    set_disable_timing:可以使库单元的时间弧(timing arc)无效
    总的来说,set_false_path 只对data path起作用, EDA 工具还会分析计算这条时序路径, 只是不报出来是否有时序违例。
    set_disable_timing 对timing arc起作用,完全不去分析这条timing arc

    9. 关于异步FIFO最小深度的计算

    FIFO仅在数据突发时才有效,不使用与连续的数据输出和输入。如果存在连续的数据流,那么所需要的FIFO大小因该是无限的。因此需要知道突发速率,突发大小,频率等,才能确定FIFO的深度。
    最小深度的计算流程

    1. 确定读时钟fr和写时钟的频率fw, 一般情况fw>fr的
    2. 根据fr和fw计算读写一次数据的周期Tr 和Tw,根据T= 1/f
    3. 根据突发写长度的大小,计算这么多数据需要写多少时间 tw = Tw*len
    4. 根据写的时间tw计算读了多少数据 n = tw/Tr
    5. FIFO的最小深度等于 len-n

    9.1 写时钟快于读时钟,写和读的过程中没有空闲周期

    image.png
    分析过程:
    写时钟周期Tw = 1000/80 ns = 12.5ns;同理读时钟周期为20ns;
    突发写长度为120个数据,写120个数据耗时120 * 12.5 = 1500ns;
    1500ns时间内读出数据1500/20ns = 75个;
    故最小FIFO深度为120 - 75 = 45;

    9.2 写时钟频率大于读时钟频率,但在读写的过程中存在空闲周期

    image.png
    分析:
    写时钟周期T_A = 12.5ns,读时钟周期为T_B = 20ns;
    两个写时钟写一个数据,也就是写一个数据需要时间2*T_A = 25ns,那么由于突发写数据个数为120个,写这么多数据需要时间120 * 25ns = 3000ns;
    4个读时钟周期读一个数据,因此读一个数据需要时间80ns,3000ns读了3000/80 = 37.5个数据(0.5不算一个数据,没读完整),约等于37个数据。
    所以,FIFO的最小深度为120 - 37 = 83;

    9.3 写时钟慢于读时钟,且读写过程中没有空闲周期

    image.png
    分析:
    这种情况下永远也不会发生数据丢失的情况;
    fifo的深度为1

    9.4 写时钟频率小于读时钟频率,但读写过程中存在空闲周期

    image.png
    分析:
    写时钟周期1000/30 ns = 100/3 ns;读时钟周期 20ns;
    写一个数据需要2个时钟,也就是200/3 ns;读一个数据需要4个时钟,也就是80 ns;
    写120个数据需要时间8000ns,这段时间内读出数据8000/80 = 100个;
    因此,FIFO的最小深度为120 - 100 = 20;

    9.5 读写时钟速率相同,且无空闲时钟

    image.png
    分析:
    如果读写时钟之间没有相位差,则不需要FIFO就可以进行读写;
    如果二者存在相位差,只需要FIFO的深度为1即可。

    9.6 读写时钟频率一致,但在读写过程中存在空闲周期

    image.png
    分析:
    两个时钟写一个数据,需要时间40ns;
    4个时钟读一个数据,需要80ns;
    由于突发长度为120,需要120*40 = 4800ns写完;这段时间读出数据个数:4800/80 = 60;
    所以,FIFO最小深度为120 - 60 = 60;

    9.7 特定条件下,最坏情况分析FIFO最小深度

    image.png
    首先,从条件可知,写频率等于读频率;
    其次,读写可以在如下限制下的任意时刻发生:
    image.png
    image.png
    为了获得更安全的FIFO深度,我们需要考虑最坏的情况,以防数据丢失;
    对于最坏的情况,写入和读取之间的数据速率之间的差异应该是最大的。 因此,对于写操作,应考虑最大数据速率,对于读操作,应考虑最小数据速率。从上表可以看出,最快的写数据速率应该为第4种情况,写操作在最小的时间内完成;
    由于突发写长度为160,所以160个时钟写160个数据;
    由于读速度为10个时钟读8个数据,因此一个数据需要10/8个时钟;
    所以160个时钟读了160*8/10 = 128个数据;
    所以FIFO的最小深度为160-128=32.

    9.8 条件拐弯抹角的给出,需要自己提取关键信息

    image.png
    假如clkA = 25MHz,则CLKB = 100MHz;

    TA= 40ns, TB = 10ns;
    en_B = 100*40 = 4000ns;占空比为1/4;
    我们认为B为写时钟,写使能时间为4000/4 = 1000ns,则突发写长度为1000/10 = 100个数据;
    在1000ns内读出数据为1000/40 = 25个数据,所以FIFO最小深度为100 - 25 = 75

    9.9 其它情况

    输入时钟频率炜250MHz,输入数据率8Gbps,输出的时钟频率200MHz,输出的数据率为5Gbps,单位时间内输入的数据总量为4Gb,在保证数据不丢失的情况下,最少需要多大的缓冲空间,并给出分析步骤。
    解析:解答1,不考虑两个包之间的背靠背的情况
    4Gb/8Gbps * 5Gbps = 2.5Gb,因此缓冲空间=4Gb-2.5Gb = 1.5Gb;
    解答2:考虑背靠背的情况
    突发长度=8G, 写应该是0440的情况,读用最慢的情况,2.5, 2.5,0.5, 2.5,因此FIFO= 8-3 = 5G

    9. Vivado FIFO IP核使用

    1. 在IP Catalog中搜索FIFO,会出现各种各样的FIFO,一般选择FIFO generator。
      image.png
    2. 点击IP之后,会出现FIFO配置的一些选项,包括Basic Native ports, flag等
      image.png
    3. 在Basic中我们可以控制FIFO的接口形式和FIFO的类型
    • FIFO 的接口分为两类,一类是 Native 接口,这类接口使用比较简单,另一类是 AXI 协议接口,这类协议口线比较多,操作相对复杂。
    • FIFO 的类型主要区别:1.读写是否使用一个时钟 2.使用何种硬件资源
      其中区别1主要是通过common clk和 independent clk来确定,也就是同步FIFO和异步FIFO
      区别2硬件资源:分为3种。BRAM:即块RAM资源,这是FPGA内嵌的一种重要的专用RAM资源,可以在读写两端使用不同的数据宽度,可以使用 ECC (一种数据校验特性),支持 First-World Fall Through ,以及支持动态错误注入。;分布式RAM:Distributed RAM,即将FPGA中的LUT用作RAM,仅支持 First-World Fall Through 功能;专用FIFO,专用FIFO会提供很小的延迟。BRAM 是一种比较重要的资源,如果设计的 FIFO 对延时不敏感,可以使用分布式的 RAM 以节约 BRAM 资源。
    1. Stand FIFO 和 First Word Fall Through的区别
    • standard FIFO 读取数据时会延迟一个周期,也即会在使能信号拉高后延迟一个周期才有数据输出,而First word fall through会和使能信号同时输出。造成这种区别的原因在于FWFT模式下,第一个写入的数据将从RAM中提前读出到数据线。
    • FIFO 的复位使用的高电平复位,如果设计中系统复位信号是低电平有效的,那么不要忘记要将系统复位电平取反后再接入 FIFO 复位电平。一般我们在同步系统设计中使用异步复位。
      image.png
    1. status flag
    • 包括 almost Full/Empty 信号,这两个信号,顾名思义,就是在 FIFO 几乎要满或者几乎要空的情况下置起,所谓的“几乎“就是指还差一个数据满或者空
    • 这个页面上还提供握手选项,但一般我们在初级设计中不会需要 FIFO 具有这种“交互”特性,实质上 AXI 协议接口也会提供握手特性。
    • 第四个页面 Data Count,顾名思义就是提供一个信号来表示当前 FIFO 中的数据总数
      image.png
    1. 在顶层文件实例化IP
    • 在IP Source中打开Instation Template目录下的veo文件,里面就有实例化的例子
      image.png
    1. 异步FIFO IP的使用
      image.png
      注意同步化synchronization stages
      image.png
      这个值用于表示FIFOempty拉低的时间长度,同时要注意FIFO的读一定要有empty控制,并且发现empty并不是一写入数据就拉低的。

    10. FIFO IP使用注意事项

    1. 如果读写位宽不一样的情况,比如写位宽8, 读位宽32,那么当写入三次是, empty信号仍然为高电平,也就意味着是读不出数据的。
    2. FIFO的复位信号是高电平有效
    3. standard FIFO 和FWFT的区别就是读的时候需要延时一个周期和不需要延时
    4. output register:嵌入式输出寄存器可用于增加性能并向宏添加流水线寄存器,主要用于改善时序情况,但是只对Standard FIFO模式有用,添加output register, 读延时会增加1个周期
    5. Valid: This signal indicates that valid data is available on the output bus (dout).因此在FWFT模式下,只要FIFO有数据,valid信号就会拉高;而在Standard FIFO模式下,只有在读信号使能之后,valid信号才会拉高
      FWTF

    Standard FIFO

    参考链接:
    https://blog.csdn.net/Reborn_Lee/article/details/100127937
    [https://hardwaregeeksblog.files.wordpress.com/2016/12/fifodepthcalculationmadeeasy2.pdf]
    https://zhuanlan.zhihu.com/p/47847664

    展开全文
  • 也谈大小端

    2013-03-17 15:50:53
    大小端问题是一个很简单的概念,但在实际使用中却是一个所必须考虑的非常重要的细节。虽然简单却也曾经困扰过我很多次,今天正好有空整理出来做个笔记。  字节序的大小端通常指的是在一个字内(32位或者64位)各...
  • FIFO(四):异步FIFO的最小深度计算

    万次阅读 多人点赞 2019-05-31 18:10:55
    1. 异步FIFO最小深度计算 1.1异步FIFO最小深度计算原理 1.2 异步FIFO最小深度常用计算公式 1. 2.1假如读写FIFO是同时进行的 1.2.2 读写FIFO不是同时进行的情况 2. 异步FIFO最小深度计算实例 2.1 用于SDRAM中的...
  • FIFO深度

    2021-03-11 11:24:04
    如何确定合理的FIFO深度,以保证数据不会丢失。 1、数据 速率表示一段时间内有效数据的快慢。 如一个16位宽FIFO,写时钟100MHz,读时钟801MHz,假设每4个写时钟有一个写使能,每2个读时钟就有一个读使能。 则: ...
  • 管道和FIFO

    2018-06-06 15:57:06
    两部分:读,写,对应两个文件描述符 数据写流入, 读流出 操作管道的进程被销毁之后,管道自动被释放了 管道默认是阻塞的,读写两都是 2.管道的原理 内部实现方式:环形队列 特点:先进先出 缓冲区...
  • FIFO最小深度计算

    2021-07-23 15:11:07
    FIFO最小深度计算 文章目录1、FIFO最小深度2、示例分析 ...在上游水流速度最大,下游水流速度最小的情况下,中间缓冲区不能溢出的大小就是我们关系的问题。   同理,读写速率差距过大,FIFO深度太小,就
  • 同步fifo与异步fifo

    2019-05-29 18:29:00
     FIFO的分类根据FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。 同步FIFO是指读时钟和写时钟为同一个时钟。在时钟沿来临时同时发生读写操作。异步FIFO是指读写时钟不一致,读写时钟是互相独立的。  FIFO...
  • 父进程创建管道(拥有读写两),父进程fork子进程,父进程要将原本输出到屏幕上的内容输出到管道中,用dup实现,然后execlp去进行ls操作;子进程同理,将原本从标准输入的内容变从管道去读取,用dup实现,再用...
  • zircon fifo实现分析

    千次阅读 2020-01-04 11:00:40
    其读写性能比socket或者channel都更加有效率,但是其在elements和buffers的大小上有严格的限制! //TODO:限制的本质原因 系统调用banjo文件位置:zircon\system\public\zircon\syscalls.banjo fifo的创建:zx_...
  • FIFO的使用

    2012-06-20 01:19:00
    1. 如何根据需要设计FIFO的规格和参数:  如何计算FIFO的深度 介绍 面试中最常被问到的问题之一,就是如何计算FIFO的深度。常识告诉我们,当读速率慢于写...因此为了保证FIFO大小,我们需要考虑FIFO传输的最坏...
  • 异步FIFO的硬件实现

    2020-07-11 17:51:25
    异步FIFO的硬件实现 FIFO原理 FIFO(First Input First Out)顾名思义,先入先出,在新型大规模集成电路中,为了增加数据传输率,处理大量数据流,解决异步时钟域数据传输的问题,FIFO被广泛应用.FIFO是一个双口缓冲器,即第...
  • Linux管道FIFO

    2018-02-27 21:12:07
    管道FIFO2.1 管道基本概念​ 管道是针对于本地计算机的两个进程之间的通信而设计的通信方法,管道建立后,实际上是获得两个文件描述符:一个用与读取而另一个用于写入。任何从管道写入写入的数据,可以从管道读取...
  • 有名管道FIFO

    2019-09-24 21:16:37
    管道和FIFO的特征之一是它们的数据是一个字节流。这是UNIX的原生I/O模型。进程往其中写入的是字节流,系统不对它作解释。 FIFO不存数据,只是通过它找到内核文件。 一.建立有名管道 1.命令mknod : mknod name p...
  • 还是如上的数据再这边的地址数据显示是这样的: 地址: 0x100 0x101 0x102 0x103 |———|—78—|—56—|—34—|—12—|——| 从左到右:低地址到高地址 从左到右:低位到高位 记忆方法:低低高高(对于大小端的...
  • 进程间通信之FIFO

    2020-08-04 11:34:18
    FIFO俗名叫 命名管道(有名管道),是进程间通信的一种方法。其实,所谓的管道,就是内核里面的一块缓存。从管道的一段写入的数据,实际上是缓存在内核中的,另一端读取,也就是从内核中读取这段数据。另外,管道传输...
  • 异步FIFO最小深度计算

    2015-12-27 16:34:00
    因此FIFO大小基本上暗示了所需缓存数据的容量,该容量取决于读写数据的速率。据统计,系统的数据速率取决于系统的负载能力。因此为了保证FIFO大小,我们需要考虑FIFO传输的最坏情况下。所谓最坏的情况就是使得写...
  • 异步fifo的设计

    千次阅读 2019-07-18 23:39:21
    FIFOFirst In First Out是一种先进先出的数据缓存器,与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据, 其数据地址由内部读写指针自动加1完成,不能像...
  • liux 命名管道fifo

    2018-10-06 13:09:34
    无名管道pipe 和 命名管道fifo 区别: pipe用于父子进程间通信;fifo用于系统中任何两个进程间通信 *int mkfifo( const char pathname, mode_t mode) 用于创建管道。 命名管道其本质是 文件 pathname : fifo...
  • 基于Verilog的fifo的设计研究

    千次阅读 2018-05-29 14:46:03
    仿真工具:ISE14.4一、FIFO简单讲解FIFO的本质是RAM,先进先出重要参数:fifo深度(简单来说就是需要存多少个数据) fifo位宽(每个数据的位宽)FIFO有同步和异步两种,同步即读写时钟相同,异步即读写时钟不相同...
  • FIFO(命名管道)

    千次阅读 2019-03-30 20:58:51
    FIFO常被称为命名管道,以区分管道(pipe)。管道(pipe)只能用于“有血缘关系”的进程间。但通过FIFO,不相关的进程也能交换数据。FIFO是Linux基础文件类型中的一种(p,...另外,使用统一fifo文件,可以有多个读和...
  • 在通讯场景下,两的数据处理能力不同,或者受传输单次数据传输量的的限制,很多时候我们都需要将数据进行缓存,然后在进行处理,fifo就是一种很好的数据缓存模型,下面我写了一个实例,可直接移植使用 typedef ...
  • 本文更新了过去对异步FIFO的设计!
  • FIFO:有名管道 原型:int mkfifo(const char *pathname,mode_t mode);头文件:sys/types.h和sys/stat.h 参数:创建的管道名字和操作权限 说明:可以在任意两个进程中通信 返回值:成功则返回0,否则返回-1,错误原因存...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 22,433
精华内容 8,973
热门标签
关键字:

fifo的大小端