verilog 临时存放

Verilog $random用法 随机数

$random函数调用时返回一个32位的随机数,它是一个带符号的整形数.

reg[23:0] rand;
//产生一个在 -59 — 59 范围的随机数
rand=$random%60;

// 产生 0~59 之间的随机数的例子
rand={$random} %60; //通过位拼接操作{}

// 产生一个在 min, max 之间随机数
rand = min+{$random}%(max-min+1);

verilog数组定义及其初始化

这里的内存模型指的是内存的行为模型。Verilog 中提供了两维数组来帮助我们建立内存的行为模型。具体来说,就是可以将内存宣称为一个reg类型的数组,这个数组中的任何一个单元都可以通过一个下标去访问。这样的数组的定义方式如下:

reg [wordsize : 0] array_name [0 : arraysize];

// 例如:
reg [7:0] my_memory [0:255];
// 其中 [7:0] 是内存的宽度,而[0:255]则是内存的深度(也就是有多少存储单元),其中宽度为8位,深度为256。地址0对应着数组中的0存储单元。

// 如果要存储一个值到某个单元中去,可以这样做:
my_memory [address] = data_in;

// 而如果要从某个单元读出值,可以这么做:
data_out = my_memory [address];

// 但要是只需要读一位或者多个位,就要麻烦一点,因为Verilog不允许读/写一个位。这时,就需要使用一个变量转换一下:
// 例如:
data_out = my_memory[address];
data_out_it_0 = data_out[0];
// 这里首先从一个单元里面读出数据,然后再取出读出的数据的某一位的值。

初始化内存

初始化内存有多种方式,这里介绍的是使用$readmemb 和 $readmemh系统任务来将保存在文件中的数据填充到内存单元中去。$readmemb 和 $readmemh 是类似的,只不过 $readmemb 用于内存的二进制表示,而 $readmemh 则用于内存内容的 16 进制表示。这里以 $readmemh 系统任务来介绍。

语法

$readmemh("file_name", mem_array, start_addr, stop_addr);

// 注意的是:
// file_name是包含数据的文本文件名,mem_array是要初始化的内存单元数组名,start_addr 和 stop_addr 是可选的,指示要初始化单元的起始地址和结束地址。

下面是一个简单的例子:

module  memory ();
reg [7:0] my_memory [0:255];

initial begin
$readmemh("memory.list", my_memory);
end
endmodule

// 这里使用内存文件 memory.list 来初始化 my_memory 数组。

组合逻辑for循环和generate生成块for循环

例1:给一个100位的输入向量,颠倒它的位顺序输出

只需要将in[0]赋值给out[99]、in[1]赋值给out[98]……也可以直接用for循环,其规范格式如下:

for(循环变量赋初值;循环执行条件;循环变量增值) 循环体语句块;

通过 for 循环赋值很方便:

module top_module (
    input [99:0] in,
    output reg [99:0] out
);

    always @(*) begin
        for (int i=0;i<$bits(out);i++)      // $bits() is a system function that returns the width of a signal.
            out[i] = in[$bits(out)-i-1];    // $bits(out) is 100 because out is 100 bits wide.
    end

endmodule

例2:建立一个“人口计数器”来统计一个256位输入向量中1的数量

统计1的个数可以直接将每一bit位加起来,得到的数值即为1的个数。缩减运算符只有与或非,由于加法不是一个简单地逻辑门就可以计算,所以只能一位一位的提取出来相加,因此用for语句

module top_module (
      input [254:0] in,
      output reg [7:0] out
);

      always @(*) begin       // Combinational always block
              out = 0;        // if don't assign initial value zero,simulate errors will emerge
              for (int i=0;i<255;i++)
                      out = out + in[i];
      end

endmodule

例3:通过实例化100个一位全加器制造一个100位的脉冲进位加法器

这个加法器将两个100位的输入信号和一个进位进位加起来产生一个100位的输出信号和进位信号。我们依旧用for循环语句,只是这次循环内容是另一个模块,在这里就要引入一个新的概念generate生成块。

Verilog-2001添加了generate循环,允许产生module和primitive的多个实例化,同时也可以产生多个variable,net,task,function,continous assignment,initial和always。在generate语句中可以引入if-else和case语句,根据条件不同产生不同的实例化。
用法:
1. generate语法有generate for, genreate if和generate case三种
2. generate for语句必须有genvar关键字定义for的变量
3. for 的内容必须加begin和end
4. 必须给for语段起个名字,这个名字会作为generate循环的实例名称。

标准格式:

generate
genvar i;//定义变量
for(循环变量赋初值;循环执行条件;循环变量增值) begin:gfor  //生成后的例化名,gfor[1].ui(实例化)、gfor[2].ui(实例化)......
//需要循环的实例模块
end
endgenerate

因为第一个实例的输入是cin,其他的都是上一级的cout,因此把第一个单独例化。

module top_module(
    input [99:0] a, b,
    input cin,
    output [99:0] cout,
    output [99:0] sum );
    fadd u0(.a(a[0]),
            .b(b[0]),
            .cin(cin),
            .cout(cout[0]),
            .sum(sum[0])
            );
    generate
        genvar        i;
        for(i=1;i<100;i++)begin: gfor
                fadd ui(.a(a[i]),        //this i of ui won't be replaced
                        .b(b[i]),
                        .cin(cout[i-1]),
                        .cout(cout[i]),
                        .sum(sum[i])
                        );
            end
        endgenerate
endmodule
module fadd(
    input a, b, cin,
    output cout, sum );
    assign {cout,sum} = a+b+cin;
endmodule

https://blog.csdn.net/weixin_38197667/article/details/90401400