4.3 Verilog练习(2)
发布日期:2022-04-04 06:36:32 浏览次数:12 分类:博客文章

本文共 6442 字,大约阅读时间需要 21 分钟。

目录


练习五. 用always块实现较复杂的组合逻辑电路

目的: 1.掌握用always实现组合逻辑电路的方法;2.了解assign与always两种组合逻辑电路实现方法之间的区别。

仅使用assign结构来实现组合逻辑电路,在设计中会发现很多地方会显得冗长且效率低下。而适当地采用always来设计组合逻辑,往往会更具实效。已进行的范例和练习中,我们仅在实现时序逻辑电路时使用always块。从现在开始,我们对它的看法要稍稍改变。

下面是一个简单的指令译码电路的设计示例。该电路通过对指令的判断,对输入数据执行相应的操作,包括加、减、与、或和求反,并且无论是指令作用的数据还是指令本身发生变化,结果都要作出及时的反应。显然,这是一个较为复杂的组合逻辑电路,如果采用assign语句,表达起来非常复杂。示例中使用了电平敏感的always块,所谓电平敏感的触发条件是指在@后的括号内电平列表中的任何一个电平发生变化,(与时序逻辑不同,它在@后的括号内没有沿敏感关键词,如posedge 或negedge)就能触发always块的动作,并且运用了case结构来进行分支判断,不但设计思想得到直观的体现,而且代码看起来非常整齐、便于理解

//  ALU.v`timescale 1ns / 1ps`define  add    3'd0`define  sub    3'd1`define  and    3'd2`define  or     3'd3`define  turn   3'd4module ALU(    input [2:0] opcode,    input [7:0] a,b,    output [7:0] out    );    reg [7:0] out;        always@(a or b or opcode)    begin        case(opcode)            `add  : out = a + b;            `sub  : out = a - b;            `and  : out = a & b;            `or   : out = a | b;            `turn : out = ~a;            default: out = 8'h0;         endcase     endendmodule
// Module Name: ALU_simu`timescale 1ns / 1psmodule ALU_simu;    wire [7:0]  out;    reg  [7:0]  a,b;    reg  [2:0]  opcode;    parameter  times = 5;        initial     begin        a = {$random} % 256;        b = {$random} % 256;        opcode = 3'h0;        repeat(times)            begin            #100  a = {$random} % 256;                  b = {$random} % 256;                  opcode = opcode + 1;            end            #100 $stop;      end            ALU ALU1(opcode,a,b,out);        endmodule

 

练习六. 在Verilog HDL中使用函数

目的:掌握函数在模块设计中的使用。知识点 

与一般的程序设计语言一样,Veirlog HDL也可使用函数以适应对不同变量采取同一运算的操作。Veirlog HDL函数在综合时被理解成具有独立运算功能的电路,每调用一次函数相当于改变这部分电路的输入以得到相应的计算结果。
下例是函数调用的一个简单示范,采用同步时钟触发运算的执行,每个clk时钟周期都会执行一次运算。并且在测试模块中,通过调用系统任务$display在时钟的下降沿显示每次计算的结果。

// Module Name: tryfunction.vmodule tryfunction(    input [3:0] n,    input clk,    input reset,    output [31:0] result    );        reg [31:0] result;    always @(posedge clk)        begin            if(!reset)                result = 0;            else                result =  factorial(n);        end        function [31:0] factorial;    input [3:0] operand;    reg  [3:0]  index;    begin        factorial = operand ? 1:0;        for(index = 2; index <= operand; index = index + 1)            factorial = index * factorial;    endendfunction endmodule

上例中函数factorial(n)实际上就是阶乘运算。必须提醒大家注意的是,在实际的设计中,我们不希望设计中的运算过于复杂,以免在综合后带来不可预测的后果。经常的情况是,我们把复杂的运算分成几个步骤,分别在不同的时钟周期完成。

// Module Name: tryfunction_simu`define clk_cycle 50module tryfunction_simu;    reg [3:0] n,i;    reg reset,clk;    wire [31:0] result;        initial        begin            n = 0; i = 0;            reset = 1;            clk = 0;            #100 reset = 0;            #100 reset = 1;            for(i=0;i<=10;i=i+1)              begin                #200   n = i;              end             #100 $stop;        end          always #`clk_cycle clk=~clk;     tryfunction tryfunct(.n(n), .clk(clk), .reset(reset), .result(result));endmodule

 

练习七. 在Verilog HDL中使用任务(task)

目的:掌握任务在结构化Verilog HDL设计中的应用。

仅有函数并不能完全满足Veirlog HDL中的运算需求。当我们希望能够将一些信号进行运算并输出多个结果时,采用函数结构就显得非常不方便,而任务结构在这方面的优势则十分突出。任务本身并不返回计算值,但是它通过类似C语言中形参与实参的数据交换,非常快捷地实现运算结果的调用。此外,我们还常常利用任务来帮助我们实现结构化的模块设计,将批量的操作以任务的形式独立出来,这样设计的目的通常一眼看过去就很明了。

下面是一个利用task和电平敏感的always块设计比较后重组信号的组合逻辑的实例。可以看到,利用task非常方便地实现了数据之间的交换,如果要用函数实现相同的功能是非常复杂的;另外,task也避免了直接用一般语句来描述所引起的不易理解和综合时产生冗余逻辑等问题。 【排序程序】

// Module Name: sort.vmodule sort(    input [3:0] a,b,c,d,    output [3:0] ra,rb,rc,rd    );    reg [3:0] ra,rb,rc,rd;    reg [3:0] va,vb,vc,vd;        always @ (a or b or c or d)    begin       {va,vb,vc,vd}={a,b,c,d};        sort2(va,vc); //va 与vc互换。        sort2(vb,vd); //vb 与vd互换。        sort2(va,vb); //va 与vb互换。        sort2(vc,vd); //vc 与vd互换。        sort2(vb,vc); //vb 与vc互换。        {ra,rb,rc,rd}={va,vb,vc,vd};    end task sort2;    inout[3:0] x,y;    reg[3:0] tmp;    if(x>y)        begin        tmp=x; //x与y变量的内容互换,要求顺序执行,所以采用阻塞赋值方式。        x=y;        y=tmp;        endendtask       endmodule
// Module Name: sort_simu.v`timescale 1ns/100psmodule sort_simu;    reg[3:0] a,b,c,d;    wire[3:0] ra,rb,rc,rd;        initial    begin        a=0;b=1;c=2;d=3;        repeat(10)        begin        #100 a ={$random}%15;  // $random(seed) 调用$random会使用一个默认的seed(这个默认值为0?)。也正因此,每次进行仿真时,$random产生的随机数序列都是相同的。            b ={$random}%15;            c ={$random}%15;            d ={$random}%15;        end        #100 $stop;     end    sort sort4(.a(a), .b(b), .c(c), .d(d), .ra(ra), .rb(rb), .rc(rc), .rd(rd));endmodule

仿真了几次之后发现随机生成的值是固定的,查资料后发现:$random(seed) 调用$random会使用一个默认的seed(这个默认值为0?)。也正因此,每次进行仿真时,$random产生的随机数序列都是相同的。

 

练习八. 利用有限状态机进行复杂时序逻辑的设计

目的:掌握利用有限状态机实现复杂时序逻辑的方法;

在数字电路中我们已经学习过通过建立有限状态机来进行数字逻辑的设计,而在Verilog HDL硬件描述语言中,这种设计方法得到进一步的发展。通过Verilog HDL提供的语句,我们可以直观地设计出适合更为复杂的时序逻辑的电路。关于有限状态机的设计方法在教材中已经作了较为详细的阐述,在此就不赘述了。

下例是一个简单的状态机设计,功能是检测一个5位二进制序列“10010”。考虑到序列重叠的可能,有限状态机共提供8个状态(包括初始状态IDLE)。

// Module Name: seqdetmodule seqdet(x,z,clk,rst,state);    input x,clk,rst;    output z;    output[2:0] state;    reg [2:0] state;    wire z;    parameter IDLE='d0, A='d1, B='d2,C='d3, D='d4,E='d5, F='d6,G='d7;    assign z = ( state==E ) ? 1 : 0; always @(posedge clk)    if(!rst)        state <= IDLE;    else        casex(state)        IDLE : if(x==1)                    state <= A;        A: if(x==0)               state <= B;        B: if(x==0)                state <= C;           else                state <= F;        C: if(x==1)                state <= D;           else               state <= G;        D: if(x==0)               state <= E;           else                state <= A;        E:  state <= E;        F: if(x==1)                state <= A;           else                state <= B;        G: if(x==1)                state <= F;         default:state=IDLE; //缺省状态为初始状态。    endcaseendmodule
// Module Name: seqdet_simu`timescale 1ns / 1psmodule seqdet_simu;    reg clk,rst;    reg[23:0] data;    wire[2:0] state;    wire z,x;    reg [4:0] i;    assign x=data[23];        always #10 clk = ~clk;    always @(posedge clk)        begin        if(i<24)            begin            data={data[22:0],data[23]}; // 序列算术左移            i = i + 1;            end        end            initial        begin        clk=0;        i=0;        rst=1;        #2 rst=0;        #15 rst=1;        data ='b1110_1101_1011_0100_1001_0100; //       data ='b1111_1111_1001_0000_1111_1111;        #1500 $stop;        endseqdet m(x,z,clk,rst,state);endmodule

转载地址:https://www.cnblogs.com/l20902/p/10610904.html 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:4.1 Vivado使用技巧(1):了解主界面
下一篇:4.3 Verilog练习(1)

发表评论

最新留言

很好
[***.229.124.182]2024年03月31日 06时43分16秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

mac 系统新功能体验-根据时间变化的动态桌面背景,看壁纸演绎风景大片中的日出与日落 2021-06-30
ADB的安装和使用教程,小米手机连接adb实例演示 2021-06-30
windows 关闭粘滞键-解决Microsoft Remote Desktop输入自动变为快捷键问题 2021-06-30
测试工具 - Postman接口测试入门使用手册,Postman如何进行数据关联、自动更新cookies、简单编程 2021-06-30
PyQt5 技术篇-调用字体对话框(QFontDialog)获取字体,控件设置字体。 2021-06-30
Python 技术篇-将python项目打包成exe独立运行程序,pyinstaller库打包python代码实例演示 2021-06-30
Geany 权限问题:"Error opening file ... : permission denied.",原因及解决办法。 2021-06-30
CSDN博客主页增加赞赏码收钱模块,高端大气上档次! 2021-06-30
PyQt5 技术篇-调用文件对话框获取文件、文件夹路径。文件对话框返回选中的多个文件路径 2021-06-30
SSM 整合实现 增删改查、PageHelper 实现分页 2021-06-30
[增删改查] Lucene 5 索引 CRUD 2021-06-30
使用 SpringBoot 写增删改查接口 2021-06-30
初步使用 JFreeChart 生成报表与感受 2021-06-30
前端使用 BootStrap 写一些后台常用的界面 2021-06-30
使用 SpringBoot + Ckeditor 富文本编辑器、图片上传 2021-06-30
全栈式使用 SpringBoot + SpringSecurity 做登录认证 2021-06-30
[Java爬虫] 使用 Jsoup + HttpClient 爬取网页图片 2021-06-30
使用 Git 并借助 Eclipse + Coding 合作开发项目 2021-06-30
[Java爬虫] 使用 Xpath + HtmlUnit 爬取网页基本信息 2021-06-30
[人工智能] 使用百度 API 读取身份证照片的文字 2021-06-30