generate

181 阅读3分钟

generate语法

很多情况下,需要编写很多结构相同而参数不同的赋值语句或者逻辑语句,如果参数量很大的情况下,原本的列举就会显得心有余而力不足。c语言中常用for语句来解决此类问题,verilog则为我们提供了generate语句。

generate语句的最主要功能就是对module,reg,assign,always,task等语句或者模块进行复制。

generate语句有generate_for,generate_if,generate_case三种语句。

generate_for

(1)必须使用genvar申明一个正整数变量,用做for循环的判断。(genvar是generate语句中的一种变量类型,用在generate_for中声明正整数变量)

(2)需要复制的语句必须写到begin_end语句里面。就算只有一句。

(3)begin_end需要有一个类似于模块名的名字。

generate_if语句

generate_for用于复制模块,generate_if则是根据模块的参数(必须是常量)作为条件判断,来产生满足条件的电路。相当于判断语句。

generate_case语句

generate_case其实和generate_if一样,都是根据参数(都必须为常量)作为判断条件,来产生满足条件的电路,不同于使用了case语法而已。

定义genvar,作为generate种的循环变量。

generate语句中定义的for语句,必须要有begin,为后续增加标签做准备。

begin必须要有名称,也就是必须要有标签,因为标签会作为generate循环的实例名称。

generate-loop循环语句

generate-conditional条件语句

.generate-case分支语句

integer类型也是一种寄存器数据类型,integer类型的变量为有符号数,而reg类型的变量则为无符号数。

单端口RAM

设计一个单端口RAM,它有: 写接口,读接口,地址接口,时钟接口和复位;存储宽度是4位,深度128。

image.png

enb为低电平读取数据.

reg [3:0] myRAM[127:0]; 深度为128,因为地址有7位。

写法1


module RAM_1port(
    input clk,
    input rst,
    input enb,
    input [6:0]addr,
    input [3:0]w_data,
    output wire [3:0]r_data
);
//*************code***********//
    
    reg [3:0] myRAM[127:0];
    reg [3:0]r_data_r;
  //写入ram
    
    genvar i;
    generate
        for(i=0;i<128;i=i+1)
            always@(posedge clk or negedge rst) begin
                if(!rst) begin
                    myRAM[i] <= 0;
                end
                else if(enb)
                    myRAM[addr] <= w_data;
            end
    endgenerate
   
    // 当enb为低电平,读取数据
    assign r_data = (!enb) ?myRAM[addr] :'b0;
    
//*************code***********//
endmodule

写法2


module RAM_1port(
    input clk,
    input rst,
    input enb,
    input [6:0]addr,
    input [3:0]w_data,
    output wire [3:0]r_data
);
//*************code***********//
    
    reg [3:0] myRAM[127:0];
    reg [3:0]r_data_r;
  //写入ram
    
    genvar i;
    generate
        for(i=0;i<128;i=i+1)
            always@(posedge clk or negedge rst) begin
                if(!rst) begin
                    myRAM[i] <= 0;
                end
                else if(enb)
                    myRAM[addr] <= w_data;
            end
    endgenerate
    
     // 读取RAM
    always@(*) begin
        if(~rst)
            r_data_r <= 0;
        else
            r_data_r <= ~enb? myRAM[addr]: r_data_r;
    end
 
    assign r_data = r_data_r;
 
   
//*************code***********//
endmodule

双端口RAM 可以同时读写,故需要两个always语句独立

实现一个深度为8,位宽为4bit的双端口RAM,数据全部初始化为0000。具有两组端口,分别用于读数据和写数据,读写操作可以同时进行。

当读数据指示信号read_en有效时,通过读地址信号read_addr读取相应位置的数据read_data,并输出;当写数据指示信号write_en有效时,通过写地址信号write_addr 和写数据write-data,向对应位置写入相应的数据。

image.png

reg [8:0] i ; 位宽得为9位,不然会溢出。

八位地址,所以reg [3:0] myRAM [255:0];

module ram_mod(
	input clk,
	input rst_n,
	
	input write_en,
	input [7:0]write_addr,
	input [3:0]write_data,
	
	input read_en,
	input [7:0]read_addr,
	output reg [3:0]read_data
);
    
    reg [3:0] myRAM [255:0];
    reg [8:0] i ;
    
    //写数据
    always@(posedge clk or negedge rst_n)
        if(!rst_n)
            for(i=0;i<256;i=i+1)
                myRAM[i]<=0;
        else
            myRAM[write_addr] <= write_en?write_data:myRAM[write_addr];
        
    //读数据
     always@(posedge clk or negedge rst_n)
        if(!rst_n)
            read_data <= 0;
        else
            read_data <= read_en?myRAM[read_addr]:read_data;
    
    
    
    
    
	
endmodule