Verilog 学习之路二——基础学习总结(摘取自菜鸟教程)

目录

      • 1 Verilog 设计方法
      • 2. 基础语法
        • 2.1 格式
        • 2.2 数值表示
          • 数值种类
          • 表示方法
        • 2.3 数据类型
        • 2.4 表达式
      • 3. 编译指令
      • 4. 连续赋值
      • 5. 过程结构
      • 6 过程赋值
      • 7 时序控制
      • 8 语句块
      • 9 循环
      • 10 函数
        • 例子-数码管译码

1 Verilog 设计方法

Verilog 的设计多采用自上而下的设计方法(top-down)。即先定义顶层模块功能,进而分析要构成顶层模块的必要子模块;然后进一步对各个模块进行分解、设计,直到到达无法进一步分解的底层功能块。这样,可以把一个较大的系统,细化成多个小系统,从时间、工作量上分配给更多的人员去设计,从而提高了设计速度,缩短了开发周期。

在这里插入图片描述

2. 基础语法

2.1 格式

Verilog 是区分大小写的。

格式自由,可以在一行内编写,也可跨多行编写。

每个语句必须以分号为结束符。空白符(换行、制表、空格)都没有实际的意义,在编译阶段可忽略。例如下面两中编程方式都是等效的。

2.2 数值表示

数值种类

0 1 x z

表示方法

合法的基数格式:4'b1011,32'h3022_c0de,'d100,'O332
负数——-6d15,-15
实数——20.123,1.2e4【12000】

  • 字符串表示方法
    字符串是由双引号包起来的字符队列。字符串不能多行书写,即字符串中不能包含回车符。Verilog 将字符串当做一系列的单字节 ASCII 字符队列。例如,为存储字符串 “www.runoob.com”, 需要 14*8bit 的存储单元。例如:

reg [0: 14*8-1] str ;
initial begin
str = “www.runoob.com”;
end

2.3 数据类型

wire 类型表示硬件单元之间的物理连线,由其连接的器件输出端连续驱动。如果没有驱动元件连接到 wire 型变量,缺省值一般为 “Z”。
寄存器(reg)用来表示存储单元,它会保持数据原有的值,直到被改写。
整数,实数,时间寄存器变量等数据类型实际也属于寄存器类型。

  1. 整数类型用关键字 integer 来声明。声明时不用指明位宽,位宽和编译器有关,一般为32 bit。reg 型变量为无符号数,而 integer 型变量为有符号数。
  2. 实数用关键字 real 来声明,可用十进制或科学计数法来表示。实数声明不能带有范围,默认值为 0。如果将一个实数赋值给一个整数,则只有实数的整数部分会赋值给整数。
  3. Verilog 使用特殊的时间寄存器 time 型变量,对仿真时间进行保存。其宽度一般为 64 bit,通过调用系统函数 $time 获取当前仿真时间。
  • 数组
    在 Verilog 中允许声明 reg, wire, integer, time, real 及其向量类型的数组。
integer          flag [7:0] ; //8个整数组成的数组
reg  [3:0]       counter [3:0] ; //由4个4bit计数器组成的数组
wire [7:0]       addr_bus [3:0] ; //由4个8bit wire型变量组成的数组
wire             data_bit[7:0][5:0] ; //声明1bit wire型变量的二维数组
reg [31:0]       data_4d[11:0][3:0][3:0][255:0] ; //声明4维的32bit数据变量数组

存储器变量就是一种寄存器数组,可用来描述 RAM 或 ROM 的行为。
参数用来表示常量,用关键字 parameter 声明,只能赋值一次。

  • 字符串
    字符串保存在 reg 类型的变量中,每个字符占用一个字节(8bit)。因此寄存器变量的宽度应该足够大,以保证不会溢出。
    字符串不能多行书写,即字符串中不能包含回车符。如果寄存器变量的宽度大于字符串的大小,则使用 0 来填充左边的空余位;如果寄存器变量的宽度小于字符串大小,则会截去字符串左边多余的数据。
    有一些特殊字符在显示字符串中有特殊意义,例如换行符,制表符等。如果需要在字符串中显示这些特殊的字符,则需要在前面加前缀转义字符 \ 。
    在这里插入图片描述

2.4 表达式

操作符——

3. 编译指令

以反引号 ` 开始的某些标识符是 Verilog 系统编译指令。

编译指令含义
`define宏定义,替换文本
`undef取消宏定义
`ifdef, `ifndef, `elsif, `else, `endif条件编译指令
`ifdef       MCU51
    parameter DATA_DW = 8   ;
`elsif       WINDOW
    parameter DATA_DW = 64  ;
`else
    parameter DATA_DW = 32  ;
`endif

例子中,如果定义了 MCU51,则使用第一种参数说明;如果没有定义 MCU、定义了 WINDOW,则使用第二种参数说明;如果 2 个都没有定义,则使用第三种参数说明。

编译指令含义
`include使用 `include 可以在编译时将一个 Verilog 文件内嵌到另一个 Verilog 文件中,作用类似于 C 语言中的 #include 结构。该指令通常用于将全局或公用的头文件包含在设计文件里。文件路径既可以使用相对路径,也可以使用绝对路径。
`timescale在 Verilog 模型中,时延有具体的单位时间表述,并用 `timescale 编译指令将时间单位与实际时间相关联。`timescale 的时间精度设置是会影响仿真时间的。时间精度越小,仿真时占用内存越多,实际使用的仿真时间就越长。所以如果没有必要,应尽量将时间精度设置的大一些。
  • `timescale
    该指令用于定义时延、仿真的单位和精度,格式为:

`timescale time_unit / time_precision
time_unit 表示时间单位,time_precision 表示时间精度,它们均是由数字以及单位 s(秒),ms(毫秒),us(微妙),ns(纳秒),ps(皮秒)和 fs(飞秒)组成。时间精度可以和时间单位一样,但是时间精度大小不能超过时间单位大小,例如下面例子中,输出端 Z 会延迟 5.21ns 输出 A&B 的结果。

在编译过程中,`timescale 指令会影响后面所有模块中的时延值,直至遇到另一个 `timescale 指令或 `resetall 指令。

编译指令含义
`default_nettype该指令用于为隐式的线网变量指定为线网类型,即将没有被声明的连线定义为线网类型。
`resetall该编译器指令将所有的编译指令重新设置为缺省值。`resetall 可以使得缺省连线类型为线网类型。当 `resetall 加到模块最后时,可以将当前的 `timescale 取消防止进一步传递,只保证当前的 `timescale 在局部有效,避免 `timescale 的错误继承。
`celldefine, `endcelldefine这两个程序指令用于将模块标记为单元模块,他们包含模块的定义。例如一些与、或、非门,一些 PLL 单元,PAD 模型,以及一些 Analog IP 等。
`unconnected_drive, `nounconnected_drive在模块实例化中,出现在这两个编译指令间的任何未连接的输入端口,为正偏电路状态或者为反偏电路状态。
`celldefine
module (
    input      clk,
    input      rst,
    output     clk_pll,
    output     flag);
        ……
endmodule
`endcelldefine

4. 连续赋值

assign     LHS_target = RHS_expression  ;

  • LHS_target 必须是一个标量或者线型向量,而不能是寄存器类型。
  • RHS_expression 的类型没有要求,可以是标量或线型或存器向量,也可以是函数调用。
  • 只要 RHS_expression 表达式的操作数有事件发生(值的变化)时,RHS_expression 就会立刻重新计算,同时赋值给 LHS_target。
wire      A, B ;
wire      Cout = A & B ;

5. 过程结构

一个模块中可以包含多个 initial 和 always 语句,但 2 种语句不能嵌套使用
这些语句在模块间并行执行,与其在模块的前后顺序没有关系。
但是 initial 语句或 always 语句内部可以理解为是顺序执行的(非阻塞赋值除外)。
每个 initial 语句或 always 语句都会产生一个独立的控制流,执行时间都是从 0 时刻开始。

  • initial

initial 语句从 0 时刻开始执行,只执行一次,多个 initial 块之间是相互独立的。
initial 理论上来讲是不可综合的,多用于初始化、信号检测等。

  • always

与 initial 语句相反,always 语句是重复执行的。always 语句块从 0 时刻开始执行其中的行为语句;当执行完最后一条语句后,便再次执行语句块中的第一条语句,如此循环反复。
由于循环执行的特点,always 语句多用于仿真时钟的产生,信号行为的检测等。

6 过程赋值

  • 阻塞赋值
    阻塞赋值属于顺序执行,即下一条语句执行前,当前语句一定会执行完毕。
    阻塞赋值语句使用等号 = 作为赋值符。
    前面的仿真中,initial 里面的赋值语句都是用的阻塞赋值。
  • 非阻塞赋值
    非阻塞赋值属于并行执行语句,即下一条语句的执行和当前语句的执行是同时进行的,它不会阻塞位于同一个语句块中后面语句的执行。
    非阻塞赋值语句使用小于等于号 <= 作为赋值符。

7 时序控制

基于时延的时序控制出现在表达式中,它指定了语句从开始执行到执行完毕之间的时间间隔。

时延类型解释
常规时延遇到常规延时时,该语句需要等待一定时间,然后将计算结果赋值给目标信号。
内嵌时延遇到内嵌延时时,该语句先将计算结果保存,然后等待一定的时间后赋值给目标信号。

当延时语句的赋值符号右端是常量时,2 种时延控制都能达到相同的延时赋值效果。
当延时语句的赋值符号右端是变量时,2 种时延控制可能会产生不同的延时赋值效果。
一般时延赋值方式:遇到延迟语句后先延迟一定的时间,然后将当前操作数赋值给目标信号,并没有"惯性延迟"的特点,不会漏掉相对较窄的脉冲。
内嵌时延赋值方式:遇到延迟语句后,先计算出表达式右端的结果,然后再延迟一定的时间,赋值给目标信号。

8 语句块

类型内容
顺序块顺序块用关键字 begin 和 end 来表示。顺序块中的语句是一条条执行的。当然,非阻塞赋值除外。顺序块中每条语句的时延总是与其前面语句执行的时间相关。
并行块并行块有关键字 fork 和 join 来表示。并行块中的语句是并行执行的,即便是阻塞形式的赋值。并行块中每条语句的时延都是与块语句开始执行的时间相关。
嵌套块顺序块和并行块还可以嵌套使用。
命名块我们可以给块语句结构命名。命名的块中可以声明局部变量,通过层次名引用的方法对变量进行访问。

9 循环

  • while 循环
while (condition) begin
    …
end
  • for 循环
for(initial_assignment; condition ; step_assignment)  begin
    …
end
  • repeat 循环
repeat (loop_times) begin
    …
end

repeat 的功能是执行固定次数的循环,它不能像 while 循环那样用一个逻辑表达式来确定循环是否继续执行。repeat 循环的次数必须是一个常量、变量或信号。如果循环次数是变量信号,则循环次数是开始执行 repeat 循环时变量信号的值。即便执行期间,循环次数代表的变量信号值发生了变化,repeat 执行次数也不会改变。

  • forever 循环
forever begin
    …
end

forever 语句表示永久循环,不包含任何条件表达式,一旦执行便无限的执行下去,系统函数 $finish 可退出 forever。

forever 相当于 while(1) 。

通常,forever 循环是和时序控制结构配合使用的。

// 产生一个时钟
reg          clk ;
initial begin
    clk       = 0 ;
    forever begin
        clk = ~clk ;
        #5 ;
    end
end

10 函数

函数只能在模块中定义,位置任意,并在模块的任何地方引用,作用范围也局限于此模块。函数主要有以下几个特点:
1)不含有任何延迟、时序或时序控制逻辑
2)至少有一个输入变量
3)只有一个返回值,且没有输出
4)不含有非阻塞赋值语句
5)函数可以调用其他函数,但是不能调用任务

  • 声明格式

function [range-1:0] function_id ;
input_declaration ;
other_declaration ;
procedural_statement ;
endfunction

函数在声明时,会隐式的声明一个宽度为 range、 名字为 function_id 的寄存器变量,函数的返回值通过这个变量进行传递。当该寄存器变量没有指定位宽时,默认位宽为 1。

函数通过指明函数名与输入变量进行调用。函数结束时,返回值被传递到调用处。

  • 函数调用格式如下:
function_id(input1, input2, …);

下面用函数实现一个数据大小端转换的功能。

module endian_rvs
    #(parameter N = 4)
        (
            input             en,     //enable control
            input [N-1:0]     a ,
            output [N-1:0]    b
    );
         
        reg [N-1:0]          b_temp ;
        always @(*) begin
        if (en) begin
                b_temp =  data_rvs(a);
            end
            else begin
                b_temp = 0 ;
            end
    end
        assign b = b_temp ;
         
    //function entity
        function [N-1:0]     data_rvs ;
            input     [N-1:0] data_in ;
            parameter         MASK = 32'h3 ; 
            integer           k ;
            begin
                for(k=0; k<N; k=k+1) begin
                    data_rvs[N-k-1]  = data_in[k] ;  
                end
            end
    endfunction
         
endmodule
  • 常数函数

常数函数是指在仿真开始之前,在编译期间就计算出结果为常数的函数。常数函数不允许访问全局变量或者调用系统函数,但是可以调用另一个常数函数。
这种函数能够用来引用复杂的值,因此可用来代替常量。

  • automatic 函数

在 Verilog 中,一般函数的局部变量是静态的,即函数的每次调用,函数的局部变量都会使用同一个存储空间。若某个函数在两个不同的地方同时并发的调用,那么两个函数调用行为同时对同一块地址进行操作,会导致不确定的函数结果。
Verilog 用关键字 automatic 来对函数进行说明,此类函数在调用时是可以自动分配新的内存空间的,也可以理解为是可递归的。因此,automatic 函数中声明的局部变量不能通过层次命名进行访问,但是 automatic 函数本身可以通过层次名进行调用。

例子-数码管译码

在这里插入图片描述

module digital_tube
     (
      input             clk ,
      input             rstn ,
      input             en ,
 
      input [3:0]       single_digit ,
      input [3:0]       ten_digit ,
      input [3:0]       hundred_digit ,
      input [3:0]       kilo_digit ,
 
      output reg [3:0]  csn , //chip select, low-available
      output reg [6:0]  abcdefg        //light control
      );
 
    reg [1:0]            scan_r ;  //scan_ctrl
    always @ (posedge clk or negedge rstn) begin
        if(!rstn)begin
            csn            <= 4'b1111;
            abcdefg        <= 'd0;
            scan_r         <= 3'd0;
        end
        else if (en) begin
            case(scan_r)
            2'd0:begin
                scan_r    <= 3'd1;
                csn       <= 4'b0111;     //select single digit
                abcdefg   <= dt_translate(single_digit);
            end
            2'd1:begin
                scan_r    <= 3'd2;
                csn       <= 4'b1011;     //select ten digit
                abcdefg   <= dt_translate(ten_digit);
            end
            2'd2:begin
                scan_r    <= 3'd3;
                csn       <= 4'b1101;     //select hundred digit
                abcdefg   <= dt_translate(hundred_digit);
            end
            2'd3:begin
                scan_r    <= 3'd0;
                csn       <= 4'b1110;     //select kilo digit
                abcdefg   <= dt_translate(kilo_digit);
            end
            endcase
        end
    end
 
    /*------------ translate function -------*/
    function [6:0] dt_translate;
        input [3:0]   data;
        begin
        case(data)
            4'd0: dt_translate = 7'b1111110;     //number 0 -> 0x7e
            4'd1: dt_translate = 7'b0110000;     //number 1 -> 0x30
            4'd2: dt_translate = 7'b1101101;     //number 2 -> 0x6d
            4'd3: dt_translate = 7'b1111001;     //number 3 -> 0x79
            4'd4: dt_translate = 7'b0110011;     //number 4 -> 0x33
            4'd5: dt_translate = 7'b1011011;     //number 5 -> 0x5b
            4'd6: dt_translate = 7'b1011111;     //number 6 -> 0x5f
            4'd7: dt_translate = 7'b1110000;     //number 7 -> 0x70
            4'd8: dt_translate = 7'b1111111;     //number 8 -> 0x7f
            4'd9: dt_translate = 7'b1111011;     //number 9 -> 0x7b
        endcase
        end
    endfunction
 
endmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/44435.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

平台化的测试工具推荐|一站式测试平台RunnerGo

互联网行业的发展到今天越来越多的公司更加注重工作效率和团队协作&#xff0c;越来越多的产品也趋于平台化&#xff0c;平台化也更有利于提高团队效率&#xff0c;代码管理、持续构建、持续部署这些工具的发展都是非常超前的&#xff0c;它们对于团队协作的支持和工作效率的提…

vue中如何通过webpack-bundle-analyzer打包分析工具进行配置优化

vue中随着项目的不断功能迭代和开发&#xff0c;项目文件越来越多&#xff0c;项目的打包文件也越来越大。如何对打包文件进行分析优化&#xff0c;减小打包文件大小呢&#xff1f;可以通过webpack-bundle-analyzer 这个打包分析工具进行解决。 1、webpack-bundle-analyzer的安…

接口漏洞-WebService-wsdl+SOAP-Swagger+HTTP-WebPack

什么是接口&#xff1f; 接口就是位于复杂系统之上并且能简化你的任务&#xff0c;它就像一个中间人让你不需要了解详细的所有细节。像谷歌搜索系统&#xff0c;它提供了搜索接口&#xff0c;简化了你的搜索任务。再像用户登录页面&#xff0c;我们只需要调用我们的登录接口&am…

【go语言学习笔记】02 Go语言高效并发

文章目录 一、并发基础1. 协程&#xff08;Goroutine&#xff09;2. Channel2.1 声明2.2 无缓冲 channel2.3 有缓冲 channel2.4 关闭 channel2.5 单向 channel2.6 selectchannel 示例 二、同步原语1. 资源竞争2. 同步原语2.1 sync.Mutex2.2 sync.RWMutex2.3 sync.WaitGroup2.4 …

TypeError: can‘t convert np.ndarray of type numpy.object_.

在处理数据集的时候出现报错&#xff1a; TypeError: can’t convert np.ndarray of type numpy.object_. The only supported types are: float64, float32, float16, complex64, complex128, int64, int32, int16, int8, uint8, and bool. train_labels torch.tensor(train…

ES6基础知识七:你是怎么理解ES6中 Generator的?使用场景?

一、介绍 Generator 函数是 ES6 提供的一种异步编程解决方案&#xff0c;语法行为与传统函数完全不同 回顾下上文提到的解决异步的手段&#xff1a; 回调函数promise 那么&#xff0c;上文我们提到promsie已经是一种比较流行的解决异步方案&#xff0c;那么为什么还出现Gen…

Docker安装Nexus并配置Maven私服

1 准备工作 1 服务器已安装docker, docker各命令无报错 2 通过dockerhub查看nexus的版本信息&#xff0c;此次使用的镜像为&#xff1a;sonatype/nexus3&#xff0c;可以看到latest版本更前的的是3.58.0&#xff0c;我们这次就使用这个版本的nexus3. 2 开始安装 # 下载镜像 do…

Java中的队列

队列的理解 队列&#xff08;Queue&#xff09;是一种特殊的线性表&#xff0c;它只允许在表的前端进行删除操作&#xff0c;而在表的后端进行插入操作。 LinkedList类实现了Queue接口&#xff0c;因此我们可以把LinkedList当成Queue来用。 常用方法 实例 import java.util…

Go基础快速入门

目录 一、变量相关基础语法 1、变量的定义以及赋值 2、变量的交换 3、匿名变量 4、变量的作用域 二、常量 三、基本数据类型 1、常见数据类型 2、数据类型的转换 四、运算符 五、函数 函数高级用法 函数也是一个类型 函数也是一个变量&#xff0c;也可以赋值 高…

Jmeter接口自动化生成测试报告html格式

jmeter自带执行结果查看的插件&#xff0c;但是需要在jmeter工具中才能查看&#xff0c;如果要向领导提交测试结果&#xff0c;不够方便直观。 笔者刚做了这方面的尝试&#xff0c;总结出来分享给大家。 这里需要用到ant来执行测试用例并生成HTML格式测试报告。 一、ant下载安…

Opencv 细节补充

1.分辨率的解释 •像素&#xff1a;像素是分辨率的单位。像素是构成位图图像最基本的单元&#xff0c;每个像素都有自己的颜色。 •分辨率&#xff08;解析度&#xff09;&#xff1a; a) 图像分辨率就是单位英寸内的像素点数。单位为PPI(Pixels Per Inch) b) PPI表示的是每英…

【stm32L152】段码屏驱动注解、MX_LCD_Init()初始化失败的解决方法

文章目录 断码屏驱动补充MX_LCD_Init()驱动初始化失败 断码屏驱动补充 已经有大神写过较详细的教程&#xff1a;https://blog.csdn.net/CSDN_Gao_16/article/details/115463499&#xff0c;但这篇博文仍然比较抽象&#xff0c;我看了好多遍才看明白-_-||&#xff0c;为了节省和…

选择最佳安全文件传输方法的重要性

在数字化时代&#xff0c;文件的传输是商务、教育、科研、医学等领域不可或缺的工作流程。为了保障数据安全&#xff0c;选择最佳安全文件传输方法非常关键。在本文中&#xff0c;我们将探讨选择最佳安全文件传输方法的重要性。 第一、最佳安全文件传输方法可以保证文件内容不被…

Jmeter常见问题之URI异常

这篇文章介绍一下"http://"重复导致的URI异常问题&#xff0c;通常从浏览器地址栏复制url&#xff0c;直接粘贴到Jmeter的http请求的服务器地址中会默认带上“http://”&#xff0c;要将http://删除&#xff0c;只写IP地址&#xff0c;如下图&#xff1a; 否则&…

ESP-C3入门20. CentOS开发环境及Jenkins流水线

一、准备环境 CentOS8已经正常安装Jenkins 二、升级 cmake cmake 升到 3.16以上。 cmake --version # 安装 g sudo yum install gcc-c export CXXg# 安装 CMake 的依赖项 sudo yum install -y openssl-devel# 下载 CMake 源码并进行编译安装 wget https://github.com/Kitwa…

[ 容器 ] Harbor 私有仓库的部署与管理

目录 一、什么是Harbor二、Harbor的特性三、Harbor的构成四、Harbor 部署五、关于 Harbor.cfg 配置文件中有两类参数&#xff1a;所需参数和可选参数六、维护管理Harbor 一、什么是Harbor Harbor 是 VMware 公司开源的企业级 Docker Registry 项目&#xff0c;其目标是帮助用户…

微服务笔记---Nacos集群搭建

微服务笔记---Nacos集群搭建 Nacos集群搭建1.集群结构图2.搭建集群2.1.初始化数据库2.2.下载nacos2.3.配置Nacos2.4.启动2.5.nginx反向代理2.6.优化 Nacos集群搭建 1.集群结构图 官方给出的Nacos集群图&#xff1a; 其中包含3个nacos节点&#xff0c;然后一个负载均衡器代理…

具身智能,是机器人的“冷饭热炒”吗?

大模型正如火如荼&#xff0c;下一个AI风口就来了。 如果你关注2023世界人工智能大会等行业峰会&#xff0c;以及英伟达、微软、谷歌、特斯拉和国內科技大厂的最新发布会&#xff0c;除了“大模型”&#xff0c;应该会听到另一个高频词——具身智能。 所谓具身智能Embodied AI …

实用的设计模式08——适配器模式

适配器的单词是Adapter&#xff0c;我们在开发时经常碰到叫做XxxAdapter的类&#xff0c;此时一般就是使用了适配器模式&#xff0c;适配器模式是非常常用&#xff0c;本文就对适配器模式做一个简单的介绍 文章目录 1、真实开发场景的问题引入2、适配器模式讲解2.1 核心类及类图…

前端:运用html+css+js模仿百度热搜电影榜鼠标移入特效

前端:运用htmlcssjs模仿百度热搜电影榜鼠标移入特效 1. 实现原理2. 界面布局3. js实现对鼠标移入和移出的监听4. 参考代码如下&#xff1a; 1. 实现原理 百度热搜上电影榜鼠标移入特效如上图所示。个人觉得上述特效实现原理为使用相对定位、绝对定位实现的(鼠标移入和没有移入…