直方图统计模块——控制和地址生成模块1
今天初步完成了直方图统计模块之控制和地址生成模块的仿真,从仿真波形来看基本符合预先的要求。整个模块的RTL图如下:
PLL模块输入27M像素时钟,输出108M时钟供其他模块使用,另外输出一路给niosII使用。wr_gen是WREN信号产生模块,WREN信号是片内RAM的读写控制信号。counter1模块是RAM读信号,负责读出RAM中存储的像素信息。counter2模块是RAM清零模块,负责对RAM内部单元清零。两个MUX是地址选择单元,此模块地址输出可能是像素值或两个counter模块的输出。
WREN模块代码如下:
1 module wr_gen(clk,rst_n,start,cpurd,clearram,wren); 2 3 input clk,rst_n,start,cpurd,clearram; 4 output reg wren; 5 6 reg [1:0]cont; 7 always@(posedge clk/* or negedge rst_n*/) 8 begin 9 if(!start) //外部start信号,指示开始计数。必须由start控制,否则wren与外部27M像素时钟不同步。 10 cont<=0; 11 else 12 begin 13 if(cont==2'b11) 14 cont<=0; 15 else 16 cont<=cont+1; 17 end 18 end 19 always@(posedge clk /*or negedge rst_n*/) 20 begin 21 if(!rst_n) 22 wren<=0; 23 else 24 begin 25 if(cpurd==1) 26 wren<=0; 27 else if(clearram==1) 28 wren<=1; 29 else if(cont==2'b10||cont==2'b11) 30 wren<=1; 31 else 32 wren<=0; 33 end 34 end 35 endmodule
顶层模块代码如下:
1 module ctrl_addr(START,CLK27,PIXADDR,CPURD,CLRRAM,RST_N,PLL_RST, 2 oWREN,oADDR,oDONE,oCLK108 ); 3 input START; 4 input CLK27; 5 input CPURD; 6 input CLRRAM; 7 input RST_N; 8 input PLL_RST; 9 input [7:0] PIXADDR; 10 output oWREN; 11 output reg oDONE; 12 output oCLK108; 13 output [7:0] oADDR; 14 15 reg ostart; 16 wire clk0; 17 wire [7:0] q_addr1; 18 wire [7:0] q_addr2; 19 20 //address generate 21 assign oADDR=(CPURD==1)? q_addr1:(CLRRAM==1?q_addr2:PIXADDR); 22 23 //START信号必须与27MHz上升沿同步 、oDONE 24 always @ (posedge CLK27 or negedge RST_N) 25 begin 26 if(!RST_N) 27 begin 28 oDONE<=0; 29 ostart<=0; 30 end 31 else 32 begin 33 ostart<=START;//使START与27MHz时钟沿同步 34 oDONE<=!START;//完成信号,通知外部统计模块 35 end 36 end 37 pll1 pll1_inst ( 38 .areset ( PLL_RST ), 39 .inclk0 ( CLK27 ), 40 .c0 ( clk0 ), //内部108M 41 .c1 ( oCLK108 ),//输出108M接RAM 和nios 42 .locked ( ) 43 ); 44 //ram写信号产生模块 45 wr_gen u1 ( 46 .clk(clk0), 47 .rst_n( RST_N ), 48 .start(ostart), //内部计数器开始计数 49 .cpurd(CPURD), //读RAM数据 50 .clearram(CLRRAM),//读完后将RAM清零,以便统计下一帧 51 .wren(oWREN) 52 ) ; 53 //统计完成后的读地址产生 54 counter1 counter1_inst ( 55 .aclr ( !RST_N ), 56 .clock ( !clk0 ), 57 .sset ( !CPURD ), //计数器重置 58 .q ( q_addr1 ) 59 ); 60 //统计完成后ram清零模块地址产生 61 counter2 counter2_inst ( 62 .aclr ( !RST_N ), 63 .clock ( !clk0), 64 .sset ( !CLRRAM ), 65 .q ( q_addr2 ) 66 ); 67 68 endmodule
Testbench代码:
1 `timescale 1 ns/ 1 ps 2 module ctrl_addr_vlg_tst(); 3 // constants 4 reg CLK27; 5 reg CLRRAM; 6 reg CPURD; 7 reg [7:0] PIXADDR; 8 reg PLL_RST; 9 reg RST_N; 10 reg START; 11 // wires 12 wire [7:0] oADDR; 13 wire oCLK108; 14 wire oDONE; 15 wire oWREN; 16 17 // assign statements (if any) 18 ctrl_addr i1 ( 19 // port map - connection between master ports and signals/registers 20 .CLK27(CLK27), 21 .CLRRAM(CLRRAM), 22 .CPURD(CPURD), 23 .PIXADDR(PIXADDR), 24 .PLL_RST(PLL_RST), 25 .RST_N(RST_N), 26 .START(START), 27 .oADDR(oADDR), 28 .oCLK108(oCLK108), 29 .oDONE(oDONE), 30 .oWREN(oWREN) 31 ); 32 initial 33 begin 34 CLK27=0; 35 CLRRAM=0; 36 CPURD=0; 37 PLL_RST=0; 38 RST_N=0; 39 START=0; 40 PIXADDR=0; 41 #250 RST_N=1; 42 $display("Running testbench"); 43 end 44 45 initial 46 begin:test 47 integer i; 48 # 277.8 START=1; 49 for(i=0;i<256;i=i+1) 50 begin 51 #37.04 PIXADDR=PIXADDR+1;//像素值作为地址 52 end 53 end 54 55 initial 56 begin 57 # (277.8+37.04*80) START=0; //80个像素模拟一帧统计 58 # 9.26 CPURD=1; //一帧统计结束后START=0,oDONE=1,CPURD有效 59 # (9.26*256) CPURD=0;CLRRAM=1; //读取结束,RAM清零 60 # (9.26*256) CLRRAM=0; 61 # 37.04 START=1;//新的一帧 62 end 63 //27MHz 64 always #(37.04/2) CLK27=!CLK27; 65 66 endmodule
波形如下:
(1)总体图
START信号有效后,输出地址是像素值,wren信号周期性有效,开始统计并写入ram。start信号无效后,odone信号有效,通知外部模块,开始读取ram数值,cpurd模块有效表明开始读取。此时地址来自counter模块0~255递增。读取完成后cpurd信号无效,clrram信号有效,开始对ram清零。读取和清零两个阶段在下一帧开始统计之前结束。start信号开始,进行下一帧统计。
(2)前半部分放大
(3)中间部分
(4)后半部分