tag 标签: ip设计

相关博文
  • 热度 13
    2015-11-9 22:25
    2656 次阅读|
    1 个评论
      平行宇宙的追逐--异步FIFO控制器的设计。    在逻辑设计中,通常会用到异步FIFO, 异步FIFO控制器是经典的异步信号传输的范例,通过FIFO控制器与异步双端口RAM的组合实现数据的从一个时钟域到另一个时钟域的传输。在IC设计/FPGA设计中, 可以通过designware或其他IP生成器可以例化相关设计,但是如何设计一个适合系统的异步fifo控制器,不依赖其他IP,是本文所讨论的重点。         上图所示:FIFO由fifo控制器生成,FIFO控制器为逻辑生成,而RAM可使用memory complier生成。对于异步FIFO控制器,最重要控制的两个信号就是满与空,其他信号都产生机理都可以此类推,  如何产生这两个信号?下面就引出了平行宇宙的追逐故事。          平行宇宙的追逐故事,假设存在存在两个平行宇宙(PUSH和POP),平行宇宙上有两个人(W和R),这两个人都沿着平行宇宙的圈在追逐,但是有一个规则:      (1)R不能超过W。      (2)W不能超过R的对角线。     如上图所示,W和R就可以一直沿着所制定的规则进行追逐游戏,总是W先跑,R在后面追,W超不过R半圈,R不能超过W。     但是存在一个问题,W和R在两个平行宇宙中,W不知道R现在的位置,R也不知道W现在的位置,因此W和R需要知道彼此的位置,才能按照预设的规则运行。      因此W位置和R的位置需要通过一种机制传输到对面的宇宙上。这个位置分别就是W_b 和R_b; 因此,上述规则变成了,R不能超过W_b和W不能超过R_b的对角线。如果W跑到了R_b的对角线,则这种事件叫做满(FULL),而如果R跑到W_b的位置,则这种事件叫做空(empty)。W和R分别叫做读指针和写指针。因此,异步FIFO的机制就类似上述的平行宇宙的追逐关系。         上图所示:若W跑到R_b的对面,则为full,此时RAM中存储N的深度;若R赶上W_b,则RAM中存储深度为0.则为empty。      那如何在平行宇宙PUSH和POP之间传递W和R当前位置的信号? 答案如下:      需要将先讲W转换成格雷码W_gray=(W^(W1)),然后将将W_gray码寄存两拍,然后将寄存两拍后数据W-_gray_d2转换成二进制的(W_b)(具体装换方式见代码实现),通过上述操作,则我们得到的W_b,  此时能够保证 W_b ≤W ,同样以此类推得到R_b;此时能够保证在跨时钟域操作中,因为格雷码每次只变化1bit,因此跨时钟域采样时要么变化1bit,要么不变化。因此保证W在变化时(例如W+1),要么W_b的状态保持不变(为W),要么为(W+1),而不会是其他状态。      综上:我们就可以设计一个FIFO控制器,通过比较读指针和写指针以及读指针和写指针异步同步信号(W_b,R_b),可以产生空满状态,以及其他控制状态,从而实现异步时钟域的数据的传输。      另外:如果需要数据在还没有POP读出时,就首先在dout端口上(frist word full through ),即在非空状态下,输出最早写入的值,读信号有效是,读信号与读数据同一拍。则需要RAM的读数据提前读出值来,即在非空标示的前一拍,为空时,就提前将数据读出,并且在非空时,要将读地址+1;详细见代码所示;       如果写数据位宽与读数据位宽不匹配,假如为整数关系,则也可以用上述模型来实现,只不过W和R的平行宇宙的大小按比例缩小或放大即可,其相位关系不变。    附录:fifo控制器源码: //================================================================= //MODULE  NAME :async_fifo_ctrl //FUNCTION     : fifo fucntion //             : 1,transmit data cross asynchronouc clock domain //             : 2,generate control signal, empty/full and so on; //             : 3,support first word down through. // AUTHOR      : lihui_140601 @163.com // modify info : v1.0 build this module,10/30/15 //================================================================= module async_fifo_ctrl(            push_clk,            push_rst_n,            pop_clk,            pop_rst_n,            push,            push_din,            pop,            pop_dout,            push_full,            pop_empty,            push_almost_full,            pop_almost_empty,            push_progfull,             pop_progempty,            push_cnt,            pop_cnt,            ram_din,            ram_we,            ram_we_addr,            ram_dout,            ram_rd,            ram_rd_addr        ); parameter    fifo_depth = 8; parameter    wr_data_w  = 32; parameter    rd_data_w  = 32; parameter    wr_depth_add =  (wr_data_w/rd_data_w == 32)? 5:                              (wr_data_w/rd_data_w == 16)? 4:                              (wr_data_w/rd_data_w == 8)? 3:                              (wr_data_w/rd_data_w == 4)? 2:                              (wr_data_w/rd_data_w == 2)? 1:0; parameter    rd_depth_add =  (rd_data_w/wr_data_w == 32)? 5:                              (rd_data_w/wr_data_w == 16)? 4:                              (rd_data_w/wr_data_w == 8)? 3:                              (rd_data_w/wr_data_w == 4)? 2:                              (rd_data_w/wr_data_w == 2)? 1:0; parameter    wr_depth    = fifo_depth + wr_depth_add; parameter    rd_depth    = fifo_depth + rd_depth_add; parameter    fwdt        = 1;  //first word down through   input                      push_clk; input                      push_rst_n; input                      pop_clk; input                      pop_rst_n; input                      push; input     push_din; input                      pop; output    pop_dout; output                     push_full; output                     pop_empty; output                     push_almost_full; output                     pop_almost_empty; output                     push_progfull;  output                     pop_progempty; output     push_cnt; output     pop_cnt; output    ram_din; output                     ram_we; output     ram_we_addr; input     ram_dout; output                     ram_rd; output     ram_rd_addr; //internal signal define reg                        push_full; reg                        pop_empty; reg                        push_almost_full; reg                        pop_almost_empty;   reg   push_wr_cnt; wire  push_wr_cnt_tmp; wire  push_wr_cnt_gray; reg   push_wr_cnt_gray_d1; reg   push_wr_cnt_gray_d2; wire  push_wr_cnt_sync; reg   pop_rd_cnt; wire  pop_rd_cnt_tmp; wire  pop_rd_cnt_gray; reg   pop_rd_cnt_gray_d1; reg   pop_rd_cnt_gray_d2; wire  pop_rd_cnt_sync; wire  push_wr_cnt_tmp_cmp; wire  push_wr_cnt_sync_cmp; wire  pop_rd_cnt_tmp_cmp; wire  pop_rd_cnt_sync_cmp; wire      push_cnt_tmp; wire      pop_cnt_tmp; //----------------------------------------------------------------------------- //push clk  space //write to ram //----------------------------------------------------------------------------- assign push_wr_cnt_tmp = (push  !push_full) ? push_wr_cnt + 1'b1 : push_wr_cnt; always@(posedge push_clk or negedge push_rst_n)   if(!push_rst_n)     push_wr_cnt = 0;   else     push_wr_cnt = push_wr_cnt_tmp;     assign push_wr_cnt_gray = push_wr_cnt ^ (push_wr_cnt 1)  ;//     //----------------------------------------------------------------------------- //pop clk  space // read from ram //----------------------------------------------------------------------------- assign pop_rd_cnt_tmp =  (pop  !pop_empty)? pop_rd_cnt + 1 : pop_rd_cnt;   always@(posedge pop_clk or negedge pop_rst_n)   if(!push_rst_n)     pop_rd_cnt = 0;   else     pop_rd_cnt = pop_rd_cnt_tmp;   assign  pop_rd_cnt_gray = pop_rd_cnt ^ (pop_rd_cnt1) ;//   //----------------------------------------------------------------------------- //binay to gray code , //----------------------------------------------------------------------------- always@(posedge push_clk or negedge push_rst_n)   if(!push_rst_n) begin     pop_rd_cnt_gray_d1 = 0;     pop_rd_cnt_gray_d2 = 0;   end   else begin     pop_rd_cnt_gray_d1 = pop_rd_cnt_gray;     pop_rd_cnt_gray_d2 = pop_rd_cnt_gray_d1;   end   generate   genvar i;     assign pop_rd_cnt_sync =   pop_rd_cnt_gray_d2 ;//    for(i=fifo_depth-1;i=0 ;i=i-1) begin: pop_gray_binay      assign pop_rd_cnt_sync   = pop_rd_cnt_sync ^ pop_rd_cnt_gray_d2 ;//    end endgenerate   always@(posedge pop_clk or negedge pop_rst_n)   if(!pop_rst_n) begin     push_wr_cnt_gray_d1 = 0;     push_wr_cnt_gray_d2 = 0;   end   else begin     push_wr_cnt_gray_d1 = push_wr_cnt_gray;     push_wr_cnt_gray_d2 = push_wr_cnt_gray_d1;   end   generate   genvar j;    assign  push_wr_cnt_sync   =  push_wr_cnt_gray_d2 ;//    for(j=fifo_depth-1;j=0 ;j=j-1) begin: push_gray2binay      assign  push_wr_cnt_sync   =  push_wr_cnt_sync ^ push_wr_cnt_gray_d2 ;//    end endgenerate   //genrate fifo empty always@(posedge pop_clk or negedge pop_rst_n)   if(!pop_rst_n)     pop_empty = 1'b0;   else if({pop_rd_cnt_tmp,{rd_depth_add{1'b0}}}  == {push_wr_cnt_sync,{wr_depth_add{1'b0}}})//pop read count and push write count       pop_empty = 1'b1;   else     pop_empty = 1'b0;   //generate push fifo full; always@(posedge push_clk or negedge push_rst_n)   if(!push_rst_n)     push_full = 1'b0;   else if({push_wr_cnt_tmp,{wr_depth_add{1'b0}} } ==  {!pop_rd_cnt_sync ,  pop_rd_cnt_sync ,{rd_depth_add{1'b0}}})     push_full = 1'b1;   else     push_full = 1'b0;   //genrate fifo  almost empty always@(posedge pop_clk or negedge pop_rst_n)   if(!pop_rst_n)     pop_almost_empty = 1'b0;   else if({(pop_rd_cnt_tmp + 1),{rd_depth_add{1'b0}}} == {push_wr_cnt_sync,{wr_depth_add{1'b0}}})     pop_almost_empty = 1'b1;   else     pop_almost_empty = 1'b0;   //generate push almost full; always@(posedge push_clk or negedge push_rst_n)   if(!push_rst_n)     push_almost_full = 1'b0;   else if({(push_wr_cnt_tmp + 1),{wr_depth_add{1'b0}}}  ==  {!pop_rd_cnt_sync ,  pop_rd_cnt_sync ,{rd_depth_add{1'b0}}})     push_almost_full = 1'b1;   else     push_almost_full = 1'b0;     //generate  push count for push clk and pop count for pop clk, used for generating progfull and other signal assign  pop_rd_cnt_tmp_cmp    =  {pop_rd_cnt_tmp,{rd_depth_add{1'b0}}};// assign  push_wr_cnt_sync_cmp  =  {push_wr_cnt_sync,{wr_depth_add{1'b0}}};// assign  push_wr_cnt_tmp_cmp   =  {push_wr_cnt_tmp,{wr_depth_add{1'b0}}};// assign  pop_rd_cnt_sync_cmp   =  {pop_rd_cnt_sync,{rd_depth_add{1'b0}}};// assign  push_cnt_tmp  = (push_wr_cnt_tmp_cmp  pop_rd_cnt_sync_cmp) ?                          push_wr_cnt_tmp_cmp - pop_rd_cnt_sync_cmp :                          {1'b1,push_wr_cnt_tmp_cmp} - pop_rd_cnt_sync_cmp; assign  pop_cnt_tmp   = (push_wr_cnt_sync_cmp pop_rd_cnt_tmp_cmp)  ?                          push_wr_cnt_sync_cmp - pop_rd_cnt_tmp_cmp :                         {1'b1,push_wr_cnt_sync_cmp} - pop_rd_cnt_tmp_cmp ; assign  push_cnt =  push_cnt_tmp ;    assign  pop_cnt  =  pop_cnt_tmp ;        //----------------------------------------------------------------------------- //ram interface //----------------------------------------------------------------------------- assign ram_we_addr = push_wr_cnt ;// assign ram_we      = push !push_full ;// assign ram_din     = push_din; assign pop_dout    = ram_dout;   generate if(fwdt == 1) begin assign ram_rd_addr = pop_rd_cnt + !pop_empty ;// assign ram_rd      = pop !pop_empty  | pop_empty;// end else begin assign ram_rd_addr = pop_rd_cnt ;// assign ram_rd      = pop !pop_empty ;// end endgenerate endmodule  //以下为双端口RAM的仿真模型,将控制器与模型连接在一起,即可仿真。 module  dual_ram(          we_clk,          rd_clk,          we,          rd,          we_data,          rd_data,          we_addr ,          rd_addr          );   parameter    ram_depth = 8; parameter    wr_data_w  = 32; parameter    rd_data_w  = 32; parameter    wr_depth_add =  (wr_data_w/rd_data_w == 32)? 5:                              (wr_data_w/rd_data_w == 16)? 4:                              (wr_data_w/rd_data_w == 8)? 3:                              (wr_data_w/rd_data_w == 4)? 2:                              (wr_data_w/rd_data_w == 2)? 1:0; parameter    rd_depth_add =  (rd_data_w/wr_data_w == 32)? 5:                              (rd_data_w/wr_data_w == 16)? 4:                              (rd_data_w/wr_data_w == 8)? 3:                              (rd_data_w/wr_data_w == 4)? 2:                              (rd_data_w/wr_data_w == 2)? 1:0; parameter    wr_depth    = ram_depth + wr_depth_add; parameter    rd_depth    = ram_depth + rd_depth_add;     input                     we_clk; input                     rd_clk; input                     we; input                     rd; input    we_data; input     we_addr ;// input     rd_addr ;//   output    rd_data;   reg       rd_data; reg   ram_reg ;   always@(posedge we_clk)   if(we)        ram_reg = we_data; always@(posedge rd_clk)   if(rd)        rd_data = ram_reg ; endmodule
相关资源
  • 所需E币: 4
    时间: 2020-1-4 12:27
    大小: 404.82KB
    上传者: 978461154_qq
    转载SOPC_NIOSII的七段数码管ip设计七段数码管动态显示IP的研究及设计张亚峰编2009年10月11日Seg7_ControllerIP的研究及设计目录1.IP说明..........................................................................................................................................................31.1.功能..................................................................................................................................................31.2.寄存器..............................................................................................................................................31.2.1.address[3:0]...............................……