本文为学习Verilog记录,可以当作小白入门,想看更多verlog知识,推荐博客:Reborn Lee
变量部分
变量类型
- reg:此类型可以认为是一个寄存器,其可以保存值。
- wire:此类型仅仅可以进行assign进行赋值,其可以认为是一根导线。
- 对于模块定义中的变量,如果没有显式的说明类型,将会默认为wire类型。一般而言,对于输出变量,我们将会显式定义其为reg类型。
module Insruction_Mem(
input [31:0] addr,
input R,
input CLK,
output reg [31:0] data
);
变量定义以及使用
//定义变量格式为:类型 [最高位:最低位] 变量
wire [31:0] A;//定义一个32位的wire类型的变量
A[2:0] = 0; //将A的第0位到第2位均赋值为0
A[2:0] = 3'b000;//同A[2:0] = 0
定义变量时,需要说明变量的位,位的表示一般采用[最高位:最低位]
的形式,且位的表示位于变量前方。
如果不进行标注,将默认为1位。
使用变量时,需要选取的位也采用[最高位:最低位]
的形式,一般位于变量之后。
一维数组的定义和使用
//定义数组格式为:类型 [最高位:最低位] 变量 [最高位: 最低位]
reg [31:0] data [31:0];//定义一个有32个32位reg型变量的数组
//使用数组的格式为:类型 变量 [最高位:最低位]
data[0][1:0] = 2'b00;//将data数组的第0号元素的第0位和第1位赋值为0
定义数组时,采用以上形式,第一个位的表示说明该数组中每个变量的位,第二个位的表示说明数量。
对于数组的更多知识,请参见博客Verilog中的多维数组和存储器
模块部分
模块的构成
一个模块通常由以下几个部分构成
-
变量的定义。
-
变量的初始化。
-
触发部分,即,当特定变量改变时,对模块内reg型变量的修改。
-
赋值部分,即,对wire输出变量的赋值,此部分赋值不分先后,同时发生。
//本人写的一个很冗余的代码,可能通过调用模块可以简化,但懒~
module Registers(
input [31:0] in,
input W,
input [31:1] Write,
output [1023:0] out ,
input CLK
);
//变量的定义部分
reg [31:0] data [31:0];
reg [5:0] i;
//变量的初始化部分
initial
begin//verilog中所有的括号均使用begin,end
for(i = 0; i < 32;i = i+1)
begin
data[i] = 0;
end
end
//触发部分
always @(posedge CLK)
begin
if(W)
begin
for(i = 1; i < 32;i = i+1)
begin
if(Write[i])
begin
data[i] = in;
end
end
end
end
//赋值部分
//这里需要采用特殊的循环结构
genvar j;
generate for(j=0; j<32; j=j+1 )
begin:Reg
assign out[j*32 + 31:j*32] = data[j];
end endgenerate
endmodule
变量的初始化
initial
begin
具体变量的赋值
end
触发部分
always @(触发变量)
begin
被触发后,需要更改的变量
end
always @(posedge CLK)//时钟端上升沿触发
always @(negedge CLK)//时钟端上升沿触发
always @(*)//所有输出变量改变会触发
always @(变量1,变量2)//其中变量改变会触发
赋值部分
assign 被赋值的变量 = 赋值变量或者常量;//赋值变量必须为reg类型
特殊函数举例
case
module Alu ( f, a, b, select);
input [2:0] select;
input [3:0] a, b;
output [4:0] f;
reg [4:0] f;
always @(*)
begin
case (select)
3′b000 : f = a;
3′b001 : f = a + b;
3′b010 : f = a - b;
3′b011 : f = a / b;
3′b100 : f = a % b;
3′b10 1: f = a << 1;
3′b110 : f = a >> 1;
3′b11 1: f = a >b;
default: f = 5′b00000 ;
endcase
end
endmodule
generate for赋值循环
Generate for 的主要功能就是对assign进行复制。
genvar i; //变量定义
generate for(i=0; i<4; i=i+1 )
begin : begin_end块名称
assign赋值语句
end endgenerate
genvar j;
generate for(j=0; j<32; j=j+1 )
begin:Reg
assign out[j*32 + 31:j*32] = data[j];
end endgenerate
读取函数
$readmemh("文件名", 变量);//以16进制进行读取
$readmemb("文件名", 变量);//以2进制进行读取
module memory ();
reg [7:0] my_memory [0:255];
initial begin
$readmemh("memory.list", my_memory);
end
endmodule
// Comments are allowed (wolf点评:段注释也可以,空行空格不影响!)
CC // This is first address i.e 8'h00
AA // This is second address i.e 8'h01
@55 // Jump to new address 8'h55,@将会进行跳转
5A // This is address 8'h55
69 // This is address 8'h56
参见博客读取函数
符号位扩展
被扩展的变量 = {{(mwidth-cwidth){变量[cwidth-1]}},变量}
//变量[cwidth-1]表示需要扩展的位
//(mwidth-cwidth)需要扩展的数量
//注意大括号
module Extend16to32(
input [15:0] in,
output [31:0] out
);
assign out = {{16{in[15]}},in};
endmodule
利用变量读取变量的某些位
一般而言,是不可以在变量的位选择中使用变量的,但是采用下面的结构可以
a[BASE +:(/-:)WIDTH]
mem = in [op*32+31 : op*32];//会报错
mem = in [(op*32+31) -: 31];//不会报错
参见博客verilog通过中+:与-:解决变量内固定长度数据位的动态选取
仿真
一般而言,对于仿真文件,我们只需要修改其中的测试部分,常用的语句如下:
#100; 变量的赋值//100ms之后进行的操作
#100; CLK = 1;
#100; CLK = 0; in = 10; W = 1;
#100; CLK = 1; in = 10; W = 0;
always #10 变量的赋值//每10ms,执行一次变量的赋值
always #10 CLK = ~CLK;
always #20 Write = Write << 1;
always #100 in = in + 100;