写自己的第二级处理器(3)——Verilog HDL行为语句

时间:2022-09-05 22:48:19

我们会继续上传新书《自己动手写处理器》(未公布),今天是第七章,我每星期试试4

2.6 Verilog HDL行为语句

2.6.1 过程语句

Verilog定义的模块一般包含有过程语句,过程语句有两种:initial、always。当中initial经常使用于仿真中的初始化。当中的语句仅仅运行一次,而always中语句则是不断反复运行的。此外,always过程语句是可综合的,initial过程语句是不可综合的。

      1、always过程语句

always过程语句的格式如图2-10所看到的。

写自己的第二级处理器(3)——Verilog HDL行为语句

always过程语句一般是带有触发条件的。触发条件写在敏感信号表达式中。敏感信号表达式又称为事件表达式或敏感信号列表,当该表达式中变量的值改变时。就会引发当中语句序列的运行。

因此。敏感信号表达式中应列出影响块内取值的全部信号。

(1)敏感信号表达式的格式

假设有两个或两个以上的敏感信号时,它们之间使用“or”连接。此处还是以32位加法器为例,2.4节是使用assign直接赋值的,事实上也能够使用always过程语句实现,例如以下。

仅仅要被加数in1、加数in2中的不论什么一个改变,都会触发always过程语句,在当中进行加法运算。这里有两个敏感信号in1、in2。使用“or”连接。

module add32(input  wire[31:0]  in1,
input wire[31:0] in2,
output reg[31:0] out); always @ (in1 or in2) //使用always过程语句实现加法
begin
out = in1 + in2;
end endmodule

敏感信号列表中的多个信号也能够使用逗号隔开,上面的32位加法器能够改动为例如以下形式。

module add32(input  wire[31:0]  in1,
input wire[31:0] in2,
output reg[31:0] out); always @ (in1, in2) //多个敏感信号使用逗号分隔
begin
out = in1 + in2;
end endmodule

敏感信号列表也能够使用通配符“*”。表示在该过程语句中的全部输入信号变量,上面的32位加法器能够改动为例如以下形式。

module add32(input  wire[31:0]  in1,
input wire[31:0] in2,
output reg[31:0] out); always @ (*) //使用通配符表示过程语句中的全部输入信号变量
begin
out = in1 + in2;
end endmodule

(2)组合电路与时序电路

敏感信号能够分为两种类型:一种为电平敏感型,一种为边沿敏感型。前一种一般相应组合电路,如上面给出的加法器的样例,后一种一般相应时序电路。对于时序电路。敏感信号一般是时钟信号,Verilog HDL提供了posedge、negedge两个keyword来描写叙述时钟信号。posedge表示以时钟信号的上升沿作为触发条件,negedge表示以时钟信号的下降沿作为触发条件。还是以32位加法器为例。能够为其加入一个时钟同步信号,例如以下。

module add32(input wire        clk,     //添加了一个时钟输入信号
input wire[31:0] in1,
input wire[31:0] in2,
output reg[31:0] out); always @ (posedge clk) //在时钟信号的上升沿会触发always中的语句
begin
out = in1 + in2;
end endmodule

在时钟信号的上升沿,才会进行加法运算,这一点与前面的加法器不同。也就是当被加数in1、加数in2变化时。并不会马上改变输出out,而是要等待时钟信号的上升沿。

      2、initial过程语句

initial过程语句的格式如图2-11所看到的。

写自己的第二级处理器(3)——Verilog HDL行为语句

initial过程语句不带触发条件,而且当中的语句序列仅仅运行一次。initial过程语句通经常使用于仿真模块中对激励向量的描写叙述。或用于给寄存器赋初值。它是面向模拟仿真的过程语句,通常不能被综合。例如以下是initial过程语句的一个样例。用于给存储器mem赋初值。

initial
begin
for(addr = 0; addr < size; addr = addr+1) // for是一种循环语句。下文会介绍
mem[addr] = 0;
end

2.6.2 赋值语句

赋值语句有两种:持续赋值语句、过程赋值语句。

      1、持续赋值语句

assign为持续赋值语句,主要用于对wire型变量的赋值。

如上文中加法器的样例。

      2、过程赋值语句

在always、initial过程中的赋值语句称为过程赋值语句。多用于对reg型变量进行赋值,分为非堵塞赋值和堵塞赋值两种方式。

(1)非堵塞赋值(Non-Blocking)

赋值符号为“<=”,比如。

b <= a

非堵塞赋值在整个过程语句结束时才会完毕赋值操作。即b的值并非立马改变的。

(2)堵塞赋值(Blocking)

赋值符号为“=”,比如。

b = a

堵塞赋值在该语句结束时就马上完毕赋值操作,即b的值在这条语句结束后立马改变。假设在一个块语句中,有多条堵塞赋值语句,那么在前面的赋值语句没有完毕之前。后面的语句就不能被运行,仿佛被堵塞了一样,因此称为堵塞赋值方式。

在always过程块中,堵塞赋值能够理解为赋值语句是顺序运行的,而非堵塞赋值能够理解为赋值语句是并发运行的。如图2-12所看到的。

在一个过程块中,堵塞式赋值与非堵塞式赋值仅仅能使用当中一种。

写自己的第二级处理器(3)——Verilog HDL行为语句

2.6.3 条件语句

条件语句有if-else、case两种。应放在always块内。

分别介绍例如以下。

      1、if-else语句

if-else语句的格式有例如以下三种。

(1) if(表达式)                语句序列1;              // 非完整性IF语句

(2) if(表达式)                语句序列1;              // 二重选择的IF语句
else 语句序列2; (3) if(表达式1) 语句序列1; // 多重选择的IF语句
else if(表达式2) 语句序列2;
else if(表达式3) 语句序列3;
......
else if(表达式n) 语句序列n;
else 语句序列n+1;

上述格式中的“表达式”一般为逻辑表达式或关系表达式,也可能是1位的变量。系统对表达式的值进行推断。假设为0、X、Z。则按“假”处理,假设为1。则按“真”处理。

语句序列能够是单句。也能够是多句。多句时需使用begin-end块语句括起来。

还是以32位加法器为例。为其加入一个复位信号rst,假设rst为高电平,那么复位信号有效。输出out为0,反之,复位信号无效,输出out为两个输入信号之和。

module add32(input wire        rst,    // 添加了一个复位信号
input wire[31:0] in1,
input wire[31:0] in2,
output reg[31:0] out); always @ (*)
begin
if(rst == 1'b1)
out <= 32'h0; // 假设复位信号有效。那么输出out为0
else
out <= in1 + in2; // 反之,输出out为两个输入信号之和
end endmodule

      2、case语句

相对于if-else语句仅仅有两个分支而言,case语句是一种多分支语句,所以case语句多用于多条件译码电路,如译码器、数据选择器、状态机及微处理器的指令译码等。其格式例如以下。

case(敏感表达式)
值1: 语句序列1;
值2: 语句序列2;
......
值n: 语句序列n;
default: 语句序列n+1;
endcase

当敏感表达式的值等于“值1”时,运行语句序列1;当等于“值2”时,运行语句序列2。依次类推。假设敏感表达式的值与上面列出的值都不符,那么运行default后面的语句序列。例如以下代码是一个简单的运算单元,可运行加法或减法运算,假设输入变量type的值为1。那么运行加法运算,假设type的值为0。那么运行减法运算。

module add_sub32(input  wire        type,   // type决定运算类型
input wire[31:0] in1,
input wire[31:0] in2,
output reg[31:0] out); always @ (*)
begin
case(type)
1'b1 : out <= in1 + in2; // type为1。运行加法运算
1'b0 : out <= in1 - in2; // type为0。运行减法运算
default : out <= 32'h0;
endcase
end endmodule

case语句中。敏感表达式与值1-n之间的比較是一种全等比較,必须保证两者的相应位全等。casez、casex语句是case语句的两种扩展。

  • 在casez语句中,假设比較的两方某些位的值为高阻Z,那么对这些位的比較结果就不予考虑,仅仅需考虑其他位的比較结果。
  • 在casex语句中。假设比較的两方某些位的值为Z或X。那么对这些位的比較结果就不予考虑,仅仅需考虑其他位的比較结果。

此外。另一种表示X或Z的方式,即用表示无关值的符号“?”来表示,比如。

case(a)
2'b1x : out <= 1; //仅仅有a等于2'b1x时,out才等于1 casez(a)
2'b1x : out <= 1; //a等于2'b1x、2'b1z时,out等于1 casex(a)
2'b1x : out <= 1; //a等于2'b10、2'b11、2'b1x、2'b1z时。out等于1 case(a)
2'b1? : out <= 1; //a等于2'b10、2'b11、2'b1x、2'b1z时,out等于1

2.6.4 循环语句

Verilog HDL中存在四种类型的循环语句:for、forever、repeat、while,用来控制语句的运行次数。分别介绍例如以下。

      1、for语句

for语句的格式例如以下。这与C语言是相似的。

for(循环变量赋初值; 循环结束条件; 改动循环变量)
运行语句序列;

一个使用for语句实现7人表决器的样例例如以下。

通过for循环统计赞成的人数,若超过4人(含4人)赞成则通过。当中vote[7:1]表示7个人的投票情况。vote[i]为1。表示第i个人投的是赞成票。反之是反对票,pass是输出,超过4个人赞成。pass为1,反之为0。

module vote7(vote, pass);

input  wire[7:1] vote;
output reg pass;
reg[2:0] sum;
integer i; always @ (vote)
begin
sum = 0;
for(i=1; i<7; i=i+1)
if(vote[i])
sum = sum+1; //假设vote[i]为1,那么sum加1,注意此处使用堵塞赋值
if(sum[2] == 1'b1) //假设sum大于等于4。那么输出pass为1
pass = 1;
else
pass = 0;
end endmodule

      2、forever语句

forever语句的格式例如以下。

forever begin

语句序列

end

forever循环语句连续不断的运行当中的语句序列。经常使用来产生周期性的波形。

在2.8节编写仿真用的Test Bench文件时,会给出forever语句的样例。

      3、repeat语句

repeat语句的格式例如以下。

repeat(循环次数表达式) begin

语句序列

end

      4、while语句

while语句的格式例如以下。

while(循环运行条件表达式) begin

语句序列

end

while语句在运行时,首先推断循环运行条件表达式是否为真,若为真,则运行当中的语句序列,然后再次推断循环运行条件表达式是否为真,若为真。则再次运行当中的语句序列,如此重复,直到循环运行条件表达式不为真。

2.6.5 编译指示语句

Verilog HDL和C语言一样提供了编译指示功能,同意在程序中使用编译指示(Compiler Directives)语句,在编译时,通常先对这些指示语句进行预处理,然后再将预处理的 结果和源程序一起进行编译。

编译指示语句以“`”開始,以差别其他语句。

经常使用的编译指示语句有:`define、`include、`ifdef、`else、`endif。分别介绍例如以下。

      1、宏替换`define

`define能够用一个简单的名字或有意义的标识(也称为宏名)取代一个复杂的名字或变量。其格式例如以下。

`define 宏名 变量或名字

比如:一般在时序电路中会有一个复位信号,当该复位信号为高电平时表示复位信号有效,当该复位信号为低电平时,表示复位信号无效。分别运行不同的代码,例如以下。

always @ (clk)
begin
if(rst == 1'b1)
//复位有效
else
//复位无效
end

一种更为友好的书写方式,是使用宏定义,例如以下。

// 定义宏RstEnable表示复位信号有效,这个名字对读者而言更有意义
`define RstEnable 1'b1 ...... always @ (clk)
begin
if(rst == `RstEnable) // 在编译的时候会自己主动将`RstEnable替换成1'b1
//复位有效
else
//复位无效
end

      2、`include语句

`include是文件包括语句,它可将一个文件所有包括到还有一个文件里,使用格式例如以下。

`include "文件名称"

在OpenMIPS处理器的实现过程中。我们定义了非常多宏。这些宏都集中在文件defines.v中,假设某一程序须要使用当中的宏定义,就能够在程序文件的開始使用`include语句将defines.v文件包括进来就可以。例如以下。

`include "defines.v"

      3、条件编译语句`ifdef、`else、`endif

条件编译语句`ifdef、`else、`endif能够指定仅对程序中的部分内容进行编译。有两种使用形式。

第一种使用形式例如以下。

当指定的宏在程序中已定义。那么当中的语句序列參与源文件的编译,否则,当中的语句序列不參与源文件的编译。

`ifdef 宏名

   语句序列

 `endif

另外一种使用形式例如以下。

当指定的宏在程序中已定义,那么当中的语句序列1參与源文件的编译,否则。当中的语句序列2參与源文件的编译。

`ifdef 宏名

   语句序列1

`else

   语句序列2

`endif

2.6.6 行为语句的可综合性

前面几小节介绍了Verilog HDL中的多种行为语句。包含过程语句、赋值语句、条件语句、循环语句、编译指示语句。全部的语句都能在仿真中使用,可是有些语句是不可综合的。也就是说综合器无法将这些语句转变为相应的硬件电路。

Verilog HDL行为语句可综合性的情况如表2-4所看到的。

写自己的第二级处理器(3)——Verilog HDL行为语句

版权声明:本文博客原创文章,博客,未经同意,不得转载。

写自己的第二级处理器(3)——Verilog HDL行为语句的更多相关文章

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

    将陆续上传本人写的新书<自己动手写处理器>(尚未出版),今天是第六篇.我尽量每周四篇 2.3 Verilog HDL简单介绍 本书实现的OpenMIPS处理器是使用Verilog HDL编 ...

  2. Verilog HDL基础语法讲解之模块代码基本结构

    Verilog HDL基础语法讲解之模块代码基本结构   本章主要讲解Verilog基础语法的内容,文章以一个最简单的例子"二选一多路器"来引入一个最简单的Verilog设计文件的 ...

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

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

  4. 基于Verilog HDL整数乘法器设计与仿真验证

    基于Verilog HDL整数乘法器设计与仿真验证 1.预备知识 整数分为短整数,中整数,长整数,本文只涉及到短整数.短整数:占用一个字节空间,8位,其中最高位为符号位(最高位为1表示为负数,最高位为 ...

  5. FPGA Verilog HDL 系列实例--------步进电机驱动控制

    [连载] FPGA Verilog HDL 系列实例 Verilog HDL 之 步进电机驱动控制 步进电机的用途还是非常广泛的,目前打印机,绘图仪,机器人等等设备都以步进电机为动力核心.那么,下面我 ...

  6. Verilog HDL模块的结构

    一个设计是由一个个模块(module)构成的.一个模块的设计如下: 1.模块内容是嵌在module 和endmodule两个语句之间.每个模块实现特定的功能,模块可进行层次的嵌套,因此可以将大型的数字 ...

  7. 基于Verilog HDL 的数字电压表设计

    本次实验是在“基于Verilog HDL的ADC0809CCN数据采样”实验上进一步改进,利用ADC0809采集到的8位数据,进行BCD编码,以供查表方式相加进行显示,本次实验用三位数码管. ADC0 ...

  8. Verilog HDL的程序结构及其描述

    这篇博文是写给要入门Verilog HDL及其初学者的,也算是我对Verilog  HDL学习的一个总结,主要是Verilog HDL的程序结构及其描述,如果有错,欢迎评论指出. 一.Verilog ...

  9. 浅谈Verilog HDL代码编写风格

    消失了好久,没有写文章,也没有做笔记,因为最近再赶一个比赛,时间很紧,昨天周六终于结束了,所以趁着周末这会儿有时间,写点东西,记录下来.首先我学习FPGA才一年多,我知道自己没有资格谈论一些比较深层次 ...

随机推荐

  1. Greenplum查询计划分析

    这里对查询计划的学习主要是对TPC-H中Query2的分析. 1.Query的查询语句 select s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_a ...

  2. DNS-2

    ipconfig 用法: ipconfig [/allcompartments] [/? | /all | /renew [adapter] | /release [adapter] | /renew ...

  3. ZOJ 3209 Treasure Map &lpar;Dancing Links&rpar;

    Treasure Map Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu Submit S ...

  4. svn简介与使用

    本文简单介绍windows下svn服务器与客户端软件的简单应用. 其中,svn服务器用于储存和管理代码,相当与文本服务器的作用(多版本控制等功能),同时分配用户代码的访问与使用权限. 客户端软件 用于 ...

  5. 开启SQL Server执行占用时间显示和逻辑读取次数显示

    两条命令 1:set statistics time on 这条命令会显示你编译这条语句和执行这条语句花多长时间 2.set statistics io on 这条命令会显示你逻辑读取了多少次数据库和 ...

  6. Spring NoSuchBeanDefinitionException原因分析

    摘要:摘要:本文译自EugenParaschiv文章SpringNoSuchBeanDefinitionException原文链接:/2014th7cj/d/file/p/20161012/dv5o0 ...

  7. linux命令-crontab

    一.安装 yum install crontabs 二.基本使用 1.crontab -e:创建任务,进入编辑 格式: 基本格式 : ——————————————————— * * * * * com ...

  8. 前端实现实时通讯-----ajax长连接

    因为web运行模式为请求-响应,服务端无法主动发起通讯,所以通讯实时性存在各种问题,ajax轮询可以模拟及时通讯,但连接太频繁将给服务端带来很大压力,不频繁则实时性很差. 下面介绍在web上真正实现实 ...

  9. New Year and Old Subsequence CodeForces - 750E &lpar;dp矩阵优化&rpar;

    大意: 给定字符串, 每次询问区间[l,r]有子序列2017, 无子序列2016所需要删除的最小字符数 转移用矩阵优化一下, 要注意$(\mathbb{Z},min,+)$的幺元主对角线全0, 其余全 ...

  10. concurrent&period;future

    concurrent.future module provides a high-level interface for asynchronously executing callables. Bas ...