verilog

本文为学习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;
原文地址:https://www.cnblogs.com/zqybegin/p/13951803.html