关于Verilog HDL的一些技巧、易错、易忘点(不定期更新)

  本文记录一些关于Verilog HDL的一些技巧、易错、易忘点等(主要是语法上),一方面是方便自己忘记语法时进行查阅翻看,另一方面是分享给大家,如果有错的话,希望大家能够评论指出。

关键词:

  ·技巧篇:

      组合逻辑输出类型选择;

      语法上的变量交换;

  ·易忘篇:

      case/casex/casez语句;

      循环语句;

      数制和操作符;

      数据类型;

  ·易错:

技巧篇:

  1、组合逻辑输出:描述一个纯组合逻辑电路时,尽量不要把输出定义成输出类型,例如描述下面的电路:

 1 module mux #(parameter N=2)(
 2
 3 input [N-1:0] a, // sel=00时,选择该输入
 4
 5 input [N-1:0] b, // sel=01时,选择该输入
 6
 7 input [N-1:0] c, // sel=10时,选择该输入
 8
 9 input [N-1:0] d, // sel=11时,选择该输入
10
11 input [1:0] sel, //选择器
12
13 output[N-1:0] mux_out);// 选择器结果输出
14
15 reg [N-1:0] mux_temp; // 临时变量,用于防止其他调用者误认为输出锁存
16
17 assign mux_out=mux_temp;
18
19 //always_comb //该语句在systemverilog中可以替换下面的语句并检查
20
21 always @ (a or b or c or d or sel)
22
23   case (sel)
24
25     0 : mux_temp = a;
26
27     1 : mux_temp = b;
28
29     2 : mux_temp = c;
30
31     3 : mux_temp = d;
32   
33     default : $display("Error with sel signal");
34
35   endcase
36
37 endmodule

  2、语法上的变量交换:在always 语句块内部,任何一个语句块(以begin 开始,end 结束)都是串行执行的,只是存在赋值立刻生效还是事后生效的差异,即后面将要重点论述的阻塞赋值和非阻塞赋值两种区别(这两种赋值语句综合的区别请看我的另一篇博文,链接为:

        http://www.cnblogs.com/IClearner/p/7188875.html)。

对于下面的代码,从纯语法上讲:

1 always@(*)begin
2
3     temp=b;
4
5     b=a;
6
7     a=temp;
8
9 end

上面的例子,就是一个串行执行的例子,能够完成 a 与 b 的数值交换,如果不是串行执行,上述代码将很难完成类似各类程序控制。

易忘篇/陌生篇:

  1、case语句的各种注意情况及对应综合电路

  (留坑,以后填)

  2、循环语句:循环语句,主要包含 for、while、forever、repeat 四类语句,但只有 for 语句才有可能具备可综合性,其余均为测试验证所准备。

循环语句 for 的语法为:

    for(表达式 1;表达式 2;表达式 3) 语句

其实可以将 for 语句理解为:

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

·for 循环的例子如下(截取关键部分,非完整代码),这是最原始的一个8bit 乘法器实现,其中<<表示左移,等效于乘以2 的移位次方:

 1 parameter size = 8;
 2
 3 reg[size-1:0] opa, opb;
 4
 5 reg[2*size-1:0] result;
 6
 7 integer bindex;
 8
 9 always @(*)begin
10
11     result =  opb[0]?opa:0;
12
13     for( bindex=0; bindex<=size-1; bindex=bindex+1 )begin//根据乘法特性,判断后是否进行移位
14
15         if(opb[bindex]) result = result + (opa<<(bindex));
16
17      end
18
19     mult_out = result;
20
21 end    

(上述例子也可以当做技巧看,也就是使用位移实现乘法运算)

  3、数制与操作符

  这里数制和操作符...其实我已经基本是滚瓜烂熟了,放在这里是给初学者查询的...


用例


说明


‘hAE


8 位十六进制数


10‘b10


左边添 0 占位,实际为 10‘b0000000010


10‘bx1x0


左边添 x 占位,实际为 10‘bxxxxxxx1x0


3‘b1001_0011


3‘b011 相等


运算类别


符号


运算符含义


算术运算符


+


加法(二元运算符)


-


减法(二元运算符)


*


乘法(二元运算符)


/


除法(二元运算符)


%


取模(二元运算符)


关系运算符


>


大于


<


小于


>=


不小于


<=


不大于


==


逻辑相等


!=


逻辑不等


逻辑运算符


&&


逻辑与


||


逻辑或



逻辑非


按位逻辑运算符


~


一元非,相当于非门运算


&


二元与,相当于与门运算


|


二元或,相当于或门运算


^


二元异或,相当于异或门运算


~^,^~


二元异或非即同或,相当于同或门运算


移位运算符


>>


右移


<<


左移


赋值运算符


=


阻塞赋值,等效于立即生效


<=


非阻塞赋值,等效于当前模块结束后赋值,或者下个时钟

周期赋值生效


缩减运算符


&


一元与,相当于数据 bit 逐个进行与操作


|


一元或,相当于数据 bit 逐个进行或操作


^


一元异或,相当于数据 bit 逐个进行异或操作


~^


一元同或,相当于数据 bit 逐个进行同或操作

      单元运算符:可以带一个操作数,操作数放在运算符的右边。

      二元运算符:可以带二个操作数,操作数放在运算符的两边。

      三元运算符:可以带三个操作数,这三个数用三目运算符分隔开。

  缩减运算符是对单个操作数进行或与非递推运算,最后的运算结果是一位的二进制数。缩减运算符目前支持或与非三种操作。具体运算过程如下:第一步先将操作数的第一位与第二位进行或与非运算,第二步将运算结果与第三位进行或与非运算,依次类推,直至最后一位。

  拼接运算符则与缩减运算符相反,主要目的是将两个或多个信号的某些位拼接起来进行运算操作。拼接运算不消耗任何逻辑资源,只是一个单纯的连线逻辑。其使用方法如下:

    {信号1的某几位,信号2的某几位,..,..,信号n的某几位}

即把某些信号的某些位详细地列出来,中间用逗号分开,最后用大括号括起来表示一个整体信号。例如:

    {a,b[3:0],c,3‘b101}

也可以写成如下形式:

    {a,b[3],b[2],b[1],b[0],c,1‘b1,1‘b0,1‘b1}

在位拼接表达式中不允许存在没有指明位数的信号。这是因为在计算拼接信号的位宽的大小时必需知道其中每个信号的位宽。位拼接还可以用重复法来简化表达式,例如:

    {6{a}}//这等同于{a,a,a,a,a,a,a},a可为任意比特位宽

位拼接还可以用嵌套的方式来表达,例如:

    {c,{3{a,b}}}//这等同于{c,a,b,a,b,a,b}

用于表示重复的表达式如上例中的6 和3,必须是常数表达式或者参数

  4、数据类型:

  ·当一个wire 类型的信号没有被驱动时,缺省值为Z(高阻)。

  ·有一种专门针对存储器模型(RAM)的定义方法,例如:

    (* ramstyle ="MLAB"*)reg[31:0] RegFile1[15:0];

    (* ramstyle ="MLAB"*)reg[31:0] RegFile2[15:0];

  在ASIC 设计中,这种描述方式只会被识别为一系列的寄存器堆,并不会被识别为RAM;ASIC 中应当利用RAM 单元库(IP)例化的方法描述RAM。而在FPGA 中,综合器首先将这种描述识别为RAM 的声明,并通过识别对象的行为确认描述对象是RAM 还是寄存器堆。如果后续的描述行为满足RAM 的特征,就自动替换为FPGA 内部内置的RAM 单元库,否则将识别为寄存器堆。上例的RegFile1RegFile2 对象在Altera FPGA 中,将被识别为16 个32bit 位宽的RAM,而且指定为MLAB 类型。

 易错篇

(留坑,以后有萝卜再填)

时间: 2024-10-26 03:44:58

关于Verilog HDL的一些技巧、易错、易忘点(不定期更新)的相关文章

C++笔试易错题集(持续更新)

1.如下代码输出结果是什么? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include<stdio.h> char *myString() {     char buffer[6] = {0};     char *s = "Hello World!";     for (int i = 0; i < sizeof(buffer) - 1; i++)     {         buffer[i] = *(s + i);     

自己动手写处理器之第二阶段(2)——Verilog HDL简介

将陆续上传本人写的新书<自己动手写处理器>(尚未出版),今天是第六篇,我尽量每周四篇 2.3 Verilog HDL简介 本书实现的OpenMIPS处理器是使用Verilog HDL编写的,所以本章接下来的几节将介绍Verilog HDL的一些基本知识,包括语法.结构等.因为本书并不是一本讲授Verilog HDL的专门书籍,所以此处介绍的内容并不是Verilog HDL的全部,只是一些基础知识,以及在OpenMIPS处理器实现过程中会使用到的知识.读者如果对Verilog HDL有进一步了解

Verilog HDL的程序结构及其描述

这篇博文是写给要入门Verilog HDL及其初学者的,也算是我对Verilog  HDL学习的一个总结,主要是Verilog HDL的程序结构及其描述,如果有错,欢迎评论指出. 一.Verilog HDL的程序结构 首先我们不开始讲Verilog HDL的语法,我们从Verilog HDL的程序结构出发.相信大家都看过芯片吧,它有个名字,有个外壳,外壳向外伸出有引脚(BGA封装的那种请不要乱搅和...),然后芯片它可以实现一定的功能. Ok,知道这些之后,我们就来看看Verilog HDL的描

&lt;转&gt;Verilog HDL宏定义define

宏定义 `define 用一个指定的标识符(即名字)来代表一个字符串,它的一般形式为: `define 标识符(宏名) 字符串(宏内容) 如:`define signal string 它的作用是指定用标识符signal来代替string这个字符串,在编译预处理时,把程序中在该命令以后所有的signal都替换成string.这种方法使用户能以一个简单的名字代替一个长的字符串,也可以用一个有含义的名字来代替没有含义的数字和符号,因此把这个标识符(名字)称为“宏名”,在编译预处理时将宏名替换成字符串

Sublime Text 2 和 Verilog HDL

Sublime Text 2 和 Verilog HDL Date  Fri 04 July 2014 Tags Sublime Text / Vivado Sublime Text 代码编辑器之于程序员,就如同剑之于战士.程序员关于代码编辑器的争论从来就没有停止过,每个程序员都有自己熟悉的编辑器,他们热爱自己的 "武器",甚至可以形成 "宗教",比如 Vim 和 Emac 的战争. 如今,这个无休止的争论中要加入一个新成员了,她就是 Sublime Text .其

浅谈Verilog HDL代码编写风格

消失了好久,没有写文章,也没有做笔记,因为最近再赶一个比赛,时间很紧,昨天周六终于结束了,所以趁着周末这会儿有时间,写点东西,记录下来.首先我学习FPGA才一年多,我知道自己没有资格谈论一些比较深层次的问题,对于这个行业来说可能我才是一直脚踩在门外面.所以这篇文章是写给一些刚开始学习FPGA.Verilog HDL的同学,我看过一些大神写的代码,然后尽量模仿大神写法,经过好几个大神的影响和自己的习惯摸索,最终算是总结出了一套自己的代码书写风格,当然我的代码风格还是一直在进化中.现在将自己的一些经

流水线cpu —Verilog HDL

一.准备工作 先看看书(<计算机原理与设计 Verilog HDL版>),搞懂一点原理.然后照着书上的代码写一写(用8.4的就可以了,不用8.6的). 注意mux2x32,mux4,cla32等可以用单周期的mux,alu. (cla32就是个加法器,) 然后dffe32在书上前几章也有. pipeimem即为im指令存储器,可以套用单周期的IM. pipemem是数据存储器,可以套用单周期的dm regfile 可以套用单周期的RF. alu可以完全套用单周期的alu.pipecu中的alu

Javascript易错知识点

? JS易错知识点总结: == 和 === 的区别: ==:判断两个变量的值是否相等. ===:判断两个变量的类型和值是否都相等,两个条件同时满足时,表达式为True. switch中break的作用: 如果一个case后面的语句,没有写break,那么程序会向下执行,而不会退出: 例如:当满足条件的case 2下面没有break时,case 3也会执行 1 var num = 2; 2 switch(num){ 3 case 1: 4 alert('case 1'); 5 break; 6 c

3_8译码器Verilog HDL语言的简单实现

最近在学Verilog HDL语言,觉得learn in doing是比较好的学习方式,所以我们来直接分析分析代码好了. 先来一波代码: 1 module q_decode_38(data_in,data_out); 2 3 input[2:0] data_in; //端口声明 4 output[7:0] data_out; 5 reg[7:0] data_out; 6 7 always@(data_in) 8 begin 9 case(data_in) 10 3'd0:data_out = 8