• 搜索

  • 移动端

    APP下载
  • 学习中心

Verilog语言(数字逻辑课程笔记三)
2023-11-20 16:02:52254浏览
Verilog是拿来用的,不是用来学的

​“Verilog是拿来用的,不是用来学的。”

这是我再往上看到的一句话,也是十分认同的一句话。对于工程师而言,理论基础很重要,但是实践也很重要。晦涩难懂的代码,多在工作中实际操作几遍,就会熟练上手。

之前针对于Verilog 常见的问题,以及学习的要点,之前已经更新了两篇课堂笔记。今天为大家分享《Verilog语言(数字逻辑课程笔记三)》里面有经典的案例代码,可以直接复制使用,希望能为大家带来帮助,干货满满,点赞收藏。


识别二维码添加老师

领取Verilog学习资料

《经典Verilog100多个代码案例》

《Verilog数字系统设计教程》

功能描述

结构描述

• 结构(Structural)描述是对设计电路的结构进行描述,即描述设计电路使用的元件及这些元件之间的连接关系,属于低层次的描述方法

数据流描述

• 数据(Data Flow)流描述采用持续赋值语句,抽象级别位于结构描述和行为描述之间

行为描述

• 行为(Behavioural)描述是对设计电路的逻辑功能的描述,并不用关心设计电路使用哪些元件以及这些元件之间的连接关系,属于高层次的描述方法

结构描述

◼ 基本逻辑门关键字是Verilog HDL预定义的逻辑门,包括and、or、not、
xor、nand、nor等
◼ Verilog HDL内置了26个基本元件,其中14个门级元件,12个开关级元件

调用门原语句法:

gate_keyword <instance> (output, input1,..., inputn );

module gates (input a,b,c,d,

              output o);

   //assign o=!(a&b&c&d)

   nand(o,a,b,c,d);//o is the input, a,b,c,and d are inputs

 endmodule

数据流描述

◼ 数据流描述方式要比结构化描述方式抽象级别要高一些,因为它不在需要清晰地刻画出具体的数字电路架构,而是可以比较直观地表达底层的逻辑行为

◼ 数据流描述方式又称为 RTL 级描述方式,即寄存器传输级描述

◼ 从数据的变换和传送的角度来描述设计模块,常用 assign 连续赋值语句实现,因此抽象级别没有行为描述方式高,纯数据流的描述方式只适用于小规模的电路设计

module combo (input a,b,c,d,              output o);

   assign o= ~((a&b)|c^d);

endmodule

行为描述

◼ 行为描述是对设计电路的逻辑功能的描述,并不关心设计电路使用哪些元件以及这些元件之间的连接关系

◼ 最能体现 EDA 风格的硬件描述方式,既可以描述简单的逻辑门,也可以描述复杂的数字系统乃至微处理器;既可以描述组合逻辑电路,也可以描述时序逻辑电路

◼ 属于高层次的描述方法,类似高级语言可以使用控制流和循环语句等功能

◼ 语句块将一组语句组合在一起,这些语句在语法上等效于单个语句

◼ 顺序执行的语句常包装在 begin end 关键字中,并且将以给定的顺序依次执行。出现多组 begin end 应注意其对应匹配。

◼ 并行执行的语句常包装在fork join关键字内,多用于仿真

initial begin

    #10 data =8'hfe;

    fork 

       #10 data=8'h11;

       begin

          #20 data=8'h00;

          #30 data=8'haa;

       end

     join

 end

◼ Control Flow 语句在 Verilog 中主要包括条件语句、循环语句。
◼ 其中条件语句主要为 if-else 和 case 两种关键字。

if-else语句

// if statement without else part

if(expression)

    [statement]

//if statement wirh an else part

if(expression)

    [statement]

else 

    [statement]


//if-else-if statement

if(expression)

   [statement]

else if(expression)

   [statement]

else

   [statement]

case语句

//Here 'expression' should match one of the items

case ()

   case_item1: 

   case_item2,

   case_item3: 

   case_item4: begin


                  end

   default:   

endcase


循环语句

◼ repeat 语句——连续执行一条语句 n 次

◼ while 语句——执行一条语句直到某个条件不满足。首先判断循环执行条件表达式是否为真,若为真,则执行后面的语句或语句块,直到条件表达式不为真;若不为真,则其后的语句一次也不被执行

◼ forever 语句——无限连续地执行语句,可用 disable 语句中断.多用在initial 块中,以生成时钟等周期性波形

◼ task 语句

➢ 用来由用户定义任务,任务类似高级语言中的子程序,用来单独完成某项具体任务,并可以被模块或其他任务调用

➢ 当希望能够对多个信号进行一些运算并输出多个结果(即有多个输出变量)时,宜采用任务结构

◼ function 语句

➢ 用来定义函数,函数的目的是通过返回一个用于某表达式的值,来响应输入信号,适于对不同变量采取同一运算的操作

➢ 函数在模块内部定义,通常在本模块中调用,也能根据按模块层次分级命名的函数名从其他模块调用,而 task 只能在同一模块内定义与调用


系统函数

◼ 在仿真时将一定内容显示出来是非常常用的,$ display 和$ write 函数就主要用于显示信息和调试信息,其区别是$ display 会在字符串末尾追加一个换行符,$write则不会

module tb;

  initial begin

      $display("This ends with a new line ");

      $write("This does not,");

      $write("like this.To start new line, use newline char");

      $display("This always start on a new line!");

   end

 endmodule

◼ Verilog 还提供一个连续监视器 $monitor 函数,每当其参数列表中的变量

或表达式发生更改时,会自动打印出变量或表达式的值。

◼ Verilog 也有系统函数来处理文件相关操作,包括打开文件,将值输

出到文件,从文件中读取值和关闭文件等。

➢ 打开和关闭文件

➢ 向文件中输入信息

➢ 读取文件

➢ 读取文件数据到存储器:

$readmemb (“<数据文件名>”,<存储器名>); 

$readmemh (“<数据文件名>”,<存储器名>);

module tb;

    reg[8*45:1] str;

    integer fd;

    initial begin

       fd = $fopen("my_file.txt","r");


       //keep reading lines until EOF is found

       while(! $feof(fd)) begin

          //Gey current line of the variable

          $fgets("%0s",str);


        //Display contents of the variable

        $display("%0s",str);

      end

      $fclose(fd);

     end

endmodule

代码示例

4-bit全加器

设计源码

`timescale 1ns/1ps

module full_adder_bit(

     input wire a,b,cin,

     output wire sum,cout

     );

     assign sum=(a^b)^cin;

     assign cout=(a&b)|((a^b)&cin);

endmodule

module full_adder_4bit(

     input wire[3:0],a,b,

     output wire[3:0] sum,

     output wire cout

     );

     wire[3:0] carry;

     full_adder_1bit bit0(a[0],b[0],1'b0,sum[0],carry[0]);

     full_adder_1bit bit1(a[1],b[1],carry[0],sum[1],carry[1]);

     full_adder_1bit bit2(a[2],b[2],carry[1],sum[2],carry[2]);

     full_adder_1bit bit3(a[3],b[3],carry[2],sum[3],carry[3]);

     assign cout=carry[3];

 end module

仿真源码

`timescale 1ns/1ps

module testbench();

reg[3:0] a,b;

wire[3:0] sum;

wire cout;

initial begin

    a=4'b0011;

    b=4'b0110;

    #10;

    a=4'b1001;

    b=4'b0111;

end

full_adder_4bit adder(a,b,sum,cout);

endmodule

➢ 初始a和b分别赋值4’b0011,4’b0110,计算结果sum和
cout分别是4’b1001,1’b0
➢ 经过10ns,a和b分别赋值4’b1001,4’b0111,计算结果
sum和cout分别是4’b0000,1’b1 ,即发生溢出

可读写存储器regfile

设计源码

`timescale 1ns/1ps

module regfile(

     input wire clk,

     input wire ren,

     input wire wen,

     input wire[31:0] wdata,

     input wire[4:0] addr,

     output wire[31:0] rdata

     );

     reg[31:0] regfile[31:0];

     initial begin

        $readmemh("C:\\ram_data.txt",regfile);

     end;

     assign rdata=(ren==1'b1) ? regfile[addr]: 32'b0;

     always @(posedge clk)begin

          if(wen)

             regfile[addr]=wdata;

      end

endmodule

➢ initial 语句在仿真开始时执行,不可综合!
➢ 通过$readmemh 系统函数,将文本文件中定义的值
加载到reg变量中,文本文件内容如下:

仿真源码

`timescale 1ns/1ps

module testbench();

reg clk;

reg ren;

reg wen;

reg[4:0] addr;

reg[31:0] wdata;

wire[31:0] rdata;

regfile regfile0(clk,ren,wen,wdata,addr,rdata);

initial begin

     clk=1'b0;

     ren=1'b0;

     wen=1'b0;

     addr=5'b00011;

     wdata=32'h0;

     #12

     wen=1'b1;

     wdata=32'h0a0a0a0a;

     #5

     wen=1'b0;

     #2

     ren=1'b1;

  end

  always #5 clk=~clk;

endmodule

 本系列文章已经更新完,如果你觉得有用,还请点赞收藏哦。

来自CSDN秘密果酱博主的,已获博主许可,转载请联系博主。

公司总部

电话:199 2141 1380
地址:上海市浦东区碧波路690号张江微电子港7号楼

合肥分站

电话:199 2141 1380
地址:安徽省合肥市高新区创新大道2800号创新产业园二期E1栋

产品链接

移知官网:www.eeeknow.com
教育培训:edu.eeeknow.com
求职招聘:job.eeeknow.com

友情链接

Arm
  • 在线客服
  • 就业老师