zhliao2

风雨兼程,一路向北-------fpga (Keep a quiet heart study)
【笔记】循环操作来同步数据

参考<<Verilog那些事儿-整合篇>>

 

我们知道模块之间的沟通需要一个时钟,若要达到两个模块之间时序的同步,虽然可以用寄存器来延时输出达到时序同步的效果,如果两个模块之间的时钟相差一个时钟的话,那么我们可以定义一个寄存器来达到同步。但是想想,若是两个模块之间的时钟相差5个或者更多的话,仅仅用寄存器来同步的话,岂不累死人。所以我们需要定义一个新的同步时序的办法,这个就是下面介绍的循环操作来同步数据。

首先给出的是用寄存器来使模块之间同步的整体的RTL图:

 

其次是用循环操作来同步数据:

Verilog源代码1:

module exp7_env
(
    input CLK,
     input RSTn,
     
     input Start_Sig,
     output Done_Sig,
     
     output [7:0]ROM_Data,
     output [3:0]RAM_Addr,
     output Write_En_Sig,
     
     /***********************/
     
     output [3:0]SQ_ROM_Addr
     
     /**********************/
);

    /*****************************/
     
     wire [3:0]ROM_Addr;
     
     control_module U1
     (
         .CLK( CLK ),
          .RSTn( RSTn ),
          .Start_Sig( Start_Sig ),
          .Done_Sig( Done_Sig ),
          .ROM_Addr( ROM_Addr ),
          .Write_En_Sig( Write_En_Sig ),
          .RAM_Addr( RAM_Addr )
     );
     
     /********************************/
     
     rom_module U2
     (
         .CLK( CLK ),
          .RSTn( RSTn ),
          .ROM_Addr( ROM_Addr ),
          .ROM_Data( ROM_Data )
     );
     
     /********************************/
     
     assign SQ_ROM_Addr = ROM_Addr;
     
     /********************************/
       
endmodule

 

Verilog源代码2:

module rom_module
(
    input CLK,
     input RSTn,
     
     input [3:0]ROM_Addr,
     output [7:0]ROM_Data
);

    /***************************/
     
     reg [7:0]rData;
     
     always @ ( posedge CLK or negedge RSTn )
         if( !RSTn )
              begin 
                    rData <= 8'd0;
                end
           else
                case( ROM_Addr )
                 
                     0: rData <= 8'b0111_1110;
                      1: rData <= 8'b0100_0010;
                      2: rData <= 8'b0100_0010;
                      3: rData <= 8'b0100_0010;
                      4: rData <= 8'b0100_0010;
                      5: rData <= 8'b0100_0010;
                      6: rData <= 8'b0100_0010;
                      7: rData <= 8'b0100_0010;
                      8: rData <= 8'b0100_0010;
                      9: rData <= 8'b0100_0010;
                      10: rData <= 8'b0100_0010;
                      11: rData <= 8'b0100_0010;
                      12: rData <= 8'b0100_0010;
                      13: rData <= 8'b0100_0010;
                      14: rData <= 8'b0100_0010;
                      15: rData <= 8'b0111_1110;
                                                               
                 endcase
                 
    /***************************/
     
     assign ROM_Data = rData;
     
     /***************************/
                
endmodule

 

Verilog源代码3:

 

module control_module
(
    input CLK,
     input RSTn,
     
     input Start_Sig,
     output Done_Sig,
     
     output [3:0]ROM_Addr,
     output Write_En_Sig,
     output [3:0]RAM_Addr
);

    /*****************************/
     
     reg [1:0]i;
     reg [4:0]x;
     reg [4:0]y;
     reg [3:0]rROM, rRAM;
     reg isWrite;
     reg [4:0]C1;
     reg isDone;
     
     always @ ( posedge CLK or negedge RSTn )
         if( !RSTn )
              begin
                    i <= 2'd0;
                     x <= 5'd0;
                     y <= 5'd0;
                     rROM <= 4'd0;
                     rRAM <= 4'd0;
                     isWrite <= 1'b0;
                     C1 <= 5'd0;
                     isDone <= 1'b0;
                end
          else if( Start_Sig )
              case( i )
                     //important    
                     //步骤0需要17个时钟,这17个时钟时16个循环操作+ROM模块的沟通延迟一个时钟
                     //if( x +1 == C1 )表示延时一个时钟
                     0:
                     begin
                          if( y == C1 ) begin y <= y + 1'b1; rROM <= y[3:0] ; end
                         if( x +1 == C1 ) begin x <= x + 1'b1; isWrite <= 1'b1; rRAM <= x[3:0]; end
                         
                          if( C1 == 17 -1 ) begin C1 <= 5'd0; x <= 5'd0; y <= 5'd0; i <= i + 1'b1; end 
                          else C1 <= C1 + 1'b1;
                     end
                     
                     1:
                     begin isWrite <= 1'b0; i <= i + 1'b1; end
                     
                     2:
                     begin isDone <= 1'b1; i <= i + 1'b1; end
                     
                     3:
                     begin isDone <= 1'b0; i <= 2'd0; end
                
                endcase
                
    /*****************************/
     
     assign ROM_Addr = rROM;
     assign RAM_Addr = rRAM;
     assign Write_En_Sig = isWrite;
     assign Done_Sig = isDone;
     
     /******************************/
                

endmodule


仿真源代码:

`timescale 1 ps/ 1 ps
module exp7_env_simulation();

    reg CLK;
    reg RSTn;

    reg Start_Sig;                               
    wire Done_Sig;

    wire [3:0]SQ_ROM_Addr;
    wire [7:0]ROM_Data;
    
    wire Write_En_Sig;
    wire [3:0]RAM_Addr;

    /*******************************/
                         
    exp7_env U1 
    (
        .CLK(CLK),
        .RSTn(RSTn),
        .Start_Sig(Start_Sig),
        .Done_Sig(Done_Sig),
        .RAM_Addr(RAM_Addr),
        .ROM_Data(ROM_Data),
        .Write_En_Sig(Write_En_Sig),
        .SQ_ROM_Addr(SQ_ROM_Addr)
    );
    
    /*******************************/
    
    initial                                                
    begin                                                  
       RSTn = 0; #1000 RSTn = 1;
       CLK = 0; forever #25 CLK = ~CLK;
    end                                 

   /*******************************/
   
    reg [3:0]i;
    
   always @ ( posedge CLK or negedge RSTn )
        if( !RSTn )
             begin
                  i <= 4'd0;
                  Start_Sig <= 1'b0;
              end
         else
             case( i )
              
                  0:
                    if( Done_Sig ) begin Start_Sig <= 1'b0; i <= i + 1'b1; end
                    else Start_Sig <= 1'b1;
                    
                    1:
                    i <= i;
              
              endcase
              
    /*******************************/
            
endmodule

仿真图

这里主要看步骤0的最后的一个时钟

 光标1是指向步骤0的T0,在T0的时候if(y==C1) 成立然后,y递增,rROM被赋予y
的过去值,亦即0。在T0的未来y的未来值为1,rROM的未来值为0。y的循环操作执行
直到光标3指向的T15。
在光标4指向的T16,rROM理应被赋予y的过去值,亦即16,但是为什么在T16的未来,
rROM的过去值会是0而不是16?答案很简单rROM被赋予y[3:0],16的二进制是5'b10000,
所以是4'b000。同样在T16的瞬间,由于if(C1==17-1) 成立y<=5'd0;的优先级大于y<=
y+1'b1;所以在T16的未来y的未来值是0而不是17。
光标2是指向步骤0的T1,在T1的时候if(x+1==C1) 成立,rRAM被赋予x的过去值,
同时间isWrite 也被拉高。所以在T1的未来x的未来值为1,rRAM的未来值为0。x的循

环操作执行直到光标4指向的T16。很凑巧的是在T16的时候if(C1==17-1) 也成立,与其
y<=y+1'b1被执行但是优先级的关系,所以y<=5'd0被优先执行。
不过有一点不一样的是if(C1==17-1)的成立不包括拉低isWrite,isWrite更像是循环保留
的操作。isWrite 在步骤0的T1被拉高(光标2),由于它需要和rRAM同步,所以isWrite
也必须拉高16个时钟的时间,亦即T1~16(光标2~4)。直到步骤1(光标5)的时候它才被
拉低。

posted on 2012-12-24 15:31  zhliao  阅读(353)  评论(0编辑  收藏  举报