Verilog入门精简教程

Verilog入门

1 关键字

1.1 module

module()

endmodule

代表一个模块,我们的代码写在这个两个关键字中间

1.2 input output

input关键词,模块的输入信号,比如input Clk,Clk是外面关键输入的时钟信号;

output关键词,模块的输出信号,比如output[3:0]Led; 这个地方正好是一组输出信号。其中[3:0]表示0~3共4路信号。

inout模块输入输出双向信号。数据总线的通信中,这种信号被广泛应用;

wire关键词,线信号。例如:wire C1_Clk; 其中C1_Clk就是wire类型的信号;

线信号,三态类型,我们一般常用的线信号类型有input,output,inout,wire;

reg关键词,寄存器。和线信号不同,它可以在always中被赋值,经常用于时序逻辑中。比如reg[3:0]Led;表示了一组寄存器。

1.3 always

always@()括号里面是敏感信号。

always@(posedge Clk)敏感信号是posedge Clk含义是在上升沿的时候有效。

敏感信号还可以negedge Clk含义是下降沿的时候有效,

这种形式一般时序逻辑都会用到。

还可以是这个一符号,如果是一个则表示一直是敏感的,一般用于组合逻辑。

1.4 assign

assign用来给output,inout以及wire这些类型进行连线。

assign相当于一条连线,将表达式右边的电路直接通过wire(线)连接到左边,

左边信号必须是wire型(output和inout属于wire型)。

当右边变化了左边立马变化,方便用来描述简单的组合逻辑。

示例:

wire a, b, y;

assign y = a & b;

1.5 if…else…

这些语句含义上都和高级语言一样:

if(…)

begin

end

if(…)

begin

end

else begin

end

if(…)

begin

endelse

if(…)

begin

end

case(…)

endcase

1.6 case…endcase

case…

endcase

作用域用于状态机的编写

case(s)

1:

begin …end

2:

begin …end

default:

begin…end

endcase

1.7 begin…and

begin

end

作用域范围,类似于C的大括号。

用法举例:

always@(posedge clk)

begin

end

1.8 parameter

parameter定义一个符号a为常数(十进制180找个常量的定义等效方式):

parameter a = 180;//十进制,默认分配长度32bit(编译器默认)

parameter a = 8’d180;//十进制

parameter a = 8’HB4; //十六进制

parameter a = 8’b1011_0100; //二进制

1.9 include&define

Include 和define都是预处理命令,用于常量阐述的定义

//--------------------------------include file1.v

//--------------------------------define X = 1;

//--------------------------------deine Y;

ifdef YZ=1;

else Z=0;

endif//--------------------------------

有的时候我们一些公共的宏参数,我们可以放在一个文件中,比如这个文件名字为xx.v那么我们可以`include xx.v就可以包含找个文件中定义的一些宏参数。我还是来详细说明下吧!

话说Verilog 的`include和C语言的include用法是一样一样的,要说区别可能就在于那个点吧。

include一般就是包含一个文件,对于Verilog这个文件里的内容无非是一些参数定义,所以这里再提几个关键字:ifdefdefine `endif(他们都带个点,呵呵)。

他们联合起来使用,确实能让你的程序多样化,就拿VGA程序说事吧。

首先,你可以新建一个.v文件(可以直接新建一个TXT,让后将后缀换成.v)其实这个后缀没所谓,.v也是可以的,我觉得,写成.v更能体现出这个文件的意义。

其次`include “xxx.v” 这个路径也有一点讲究,xxx.v作为引用lcd_para.v的文件它和lcd_para.v在同一文件夹下才能怎么写,就是相对路径一说了。也就是以xxx.v为当前路径去引索lcd_para.v文件的位子。所以如果他们不再一个文件夹那么请写出更详细(正确)的路径。顺便说一句,lcd_para.v添不添加到工程是无所谓的,只要路径

对了即可,当然我还是建议添加到工程,且和.v文件放在同一文件夹下,以方便观察和管理。

1.10 符号部分

“;”分号用于每一句代码的结束,以表示结束,和C语言一样。

“:”冒号,用在数组,和条件运算符以及case语句结构中。

“<=”赋值符号,非阻塞赋值,在一个always模块中,所有语句一起更新。它也可以表示小于等于,具体是什么含义编译环境根据当前编程环境判断,如果“<=”是用在一个if判断里如:if(a <= 10);当然就表示小于等于了。

“=”阻塞赋值,或者给信号赋值,如果在always模块中,这条语句被立刻执行。阻塞赋值和非阻塞赋值将再后面详细举例说明。

“+,-,*,/,% ”是加、减、乘、除运算符号,这些使用和C语言基本是一样的,当你用到这些符号时,编译后会自动生成或者消耗FPGA原有的加法器或是乘法器等。其中符号/,%会消耗大量的逻辑,谨慎使用。

“<”小于,比如A

“<=”小于等于,比如A<=B含义就是A和B比较,如果A小于等于B就是TURE,否则为FALSE。

“>”大于,比如A>B含义就是A和B比较,如果A大于B就是TURE,否则为FALSE。

“>=”大于等于,比如A>=B含义就是A和B比较,如果大于等于B就是TURE,否则为FALSE。

”等于等于,比如AB含义就是A和B比较,如果A等于B就是TURE,否则为FALSE。

“!=”不等于,A!=B含义是A和B比较,如果A不等于B就是TURE,否则为FALSE.

“>>”右移运算符,比如A>>2表示把A右移2位。

“<<”左移运算符,比如A<<2表示把A左移2位。

”按位取反运算符,比如A=8’b1111_0000;则A的值为8’b0000_1111;

“&”按位于与,比如A=8’b1111_0000;B=8’b1010_1111;则A&B结果为8’b1010_0000;

”异或运算符,比如A=8’b1111_0000;B=8’b1010_1111;则AB结果为8’b0101_1111;

“&&”逻辑与,比如A1,B2;则A&&B结果为TRUE;如果A1,B0,则A&&B结果为FALSE,一般用于条件判断。

A = B ? C : D是一个条件运算符,含义是如果B为TRUE则把C连线A,否则把D连线A。B通常是个条件判断,用小括弧括起:

assign C1_Clk = (C1==25’d24999999) ? 1 : 0 ;

C1_Clk,是一个wire类型的信号,当C1==25’d24999999时候,连线到1,否则连线到0.

“{}”在Verilog中表示拼接符,{a,b}这个的含义是将括号内的数按位并在一起,比如:{1001,1110}表示的是10011110。

拼接是Verilog相对于其他语言的一大优势。

2 Verilog中数值表示的方式

如果我们要表示一个十进制是180的数值,在Verilog中的表示方法如下:

二进制:8’b1011_0100; //其中“_”是为了容易观察位数,可有可无。

十进制:8’d180;

16进制:8’HB4;

3 阻塞赋值和非阻塞赋值详解

说到阻塞赋值和非阻塞赋值,是很多初学者很迷惑的地方。

原因是C语言没有可以类比的东西。

学习FPGA和单片机最大的区别在于,学FPGA时,你必须时刻都有着时钟的概念。不像单片机时钟相关性比较差,FPGA你必须却把握每一个时钟。

首先来说说非阻塞赋值,这个在时序逻辑中随处可见:

reg A;

reg B;

always @(posedge clk)
    begin
       A <= 1'b1;
       B <= 1'b1;/***或者**B <= 1'b1;A <= 1'b1;*********/
end 

这段程序里,A和B是同时被赋值的,具体是说在时钟的上升沿来的时刻,A和B同时被置1。调换A和B的上下顺序,将得到相同的结果。

接着看另外一段程序:

reg A;
reg B;
always @(posedge clk)
    begin
        A <= 1'b1;
        end
always @(posedge clk)
    begin
        B <= 1'b1;
end 

这段程序,与第一段程序也是完全等价的,A和B在同一时刻被赋值。两段程序综合出的逻辑也是完全相同的。这就是非阻塞赋值的特点,体现了FPGA的并行性!

接着来看阻塞赋值,它少了一个非,表示会阻塞住,那么体会下这个阻塞:

always @(posedge clk)
    begin
        A  = 1'b1;
        B  <= 1'b1;
    end

看到,上面这个程序是阻塞和非阻塞的混合使用,一般教材是极力反对这种写法的。其实只要你理解了,有的时候这种用法还能帮上大忙。只不过,不理解的话乱用会导致时序违规。

回到正题,我们这么写是为了更好的理解阻塞赋值:当时钟上升沿来临的时刻,首先A会被置1,然后B寄存器再置1。区别就是A和B不再同时置1。A要比B提前零点几纳秒。这样就出现了先后顺序。这个过程还是在一个时钟内完成的,但是数据到达B寄存器相比上面两段程序晚了那么零点几纳秒!

当我们的时钟跑的比较慢的时候,比如50M,一个周期有20ns,那么这么短暂的延时基本可以忽略不计,但是随着设计的复杂,以及时钟速度的提高,这样的语句就要小心。

假设,我们要计算AB求和再除以2的结果。先用非阻塞方法去实现,由于AB求和再除以2是两个步骤,而非阻塞所以的事情都在一个时钟完成,所以这里我们用状态机,将两个步骤分配到两个时钟里去完成:

module unblock(
    input clk_i,
    input rst_n_i,
    output reg [4:0]result_o 
); 
    reg [3:0]A;  
    reg [3:0]B; 
    reg [4:0]C;  
    reg i; 
    always @(posedge clk_i ) 
        if(!rst_n_i) 
            begin 
                #2  A <= 4'd4;  
                B <= 4'd12;  
                C <= 5'd0;  
                result_o = 5'd0; 
            end  
    else 
        begin 
        #2   
            C <= A + B;  
            result_o <= (C >> 1); 
            end
endmodule

第一个时钟上升沿来临时,完成C <= A + B;

第二个时钟来临时完成result <= (C >> 1);

求出结果,这个过程耗费两个时钟。(不考虑复位消耗的时钟)

再来,用添加阻塞的方式实现:

module block(
    input clk_i,
    input rst_n_i,
    output reg [4:0]result_o 
);  
    reg [3:0]A;  
    reg [3:0]B; 
    reg [4:0]C; 
    always @(posedge clk_i) 
        if(!rst_n_i)  
            begin 
                #2 
                A = 4'd4; 
                #0.2 
                B = 4'd12; 
                #0.2 
                C = 5'd0;  
                #0.2 
                result_o = 5'd0; 
            end 
    else 
        begin  
            #2  
            C = A + B;  
            #0.2 
            result_o = (C >> 1);  
        end 
endmodule

4 Verilog HDL代码规范

  1. 接口时序设计规范

模块和模块之间的通过模块的接口实现关联,因此规范的时序设计,对于程序设计的过程,以及程序的维护,团队之间的沟通都是非常必要的。

img

命名规则

1、顶层文件

对象+功能+top

比如:video_oneline_top

2、逻辑控制文件

介于顶层和驱动层文件之间

对象+ctr

比如:ddr_ctr.v

3、驱动程序命名

对象+功能+dri

比如:lcd_dri.v、uart_rxd_dri.v

4、参数文件命名

对象+para

比如:lcd_para.v

5、模块接口命名:文件名+u

比如lcd_dir lcd_dir_u(…)

6、模块接口命名:特征名+文件名+u

比如 mcb_read c3_mcb_read_u

7、程序注释说明

8、端口注释

input Video_vs_i,//输入场同步入

9、信号命名

命名总体规则:对象+功能(+极性)+特性

10、时钟信号

对象+功能+特性

比如:phy_txclk_i、sys_50mhz_i

11、复位信号

对象+功能+极性+特性

比如:phy_rst_n_i、sys_rst_n_i

12、延迟信号

对象+功能+特性1+特征2

比如:fram_sync_i_r0、fram_sync_i_r1

13、特定功能计数器

对象+cnt

比如:line_cnt、div_cnt0、div_cnt1

功能+cnt

比如:wr_cnt、rd_cnt

对象+功能+cnt

比如:fifo_wr_cnt、mcb_wr_cnt、mem_wr_cnt

对象+对象+cnt

比如:video_line_cnt、video_fram_cnt

14、一般计数器

cnt+序号

用于不容易混淆的计数

比如:cnt0、cnt1、cnt2

15、 时序同步信号

对象+功能+特性

比如:line_sync_i、fram_sync_i

16、 使能信号

功能+en

比如:wr_en、rd_en

对象+功能+en

比如:fifo_wr_en、mcb_wr_en

5 状态机

状态机的状态转移图,通常也可根据输入和内部条件画出。

一般来说,状态机的设计包含下列设计步骤:

• 根据需求和设计原则,确定是Moore型还是Mealy型状态机;

• 分析状态机的所有状态,对每一状态选择合适的编码方式,进行编码;

• 根据状态转移关系和输出绘出状态转移图;

• 构建合适的状态机结构,对状态机进行硬件描述。

状态机的描述通常有三种方法,称为一段式状态机,二段式状态机和三段式状态机。

一段式状态机是应该避免使用的,该写法仅仅适用于非常简单的状态机设计,不符合组合逻辑与时序逻辑分开的原则,整个结构代码也不清晰,不利用维护和修改。

两段式状态机采用两个always模块实现状态机的功能,其中一个always采用同步时序逻辑描述状态转移,另一个always采用组合逻辑来判断状态条件转移。两段式状态机是推荐的状态机设计方法。

三段式状态机在第一个always模块采用同步时序逻辑方式描述状态转移,第二个always模块采用组合逻辑方式描述状态转移规律,第三个always描述电路的输出。通常让输出信号经过寄存器缓存之后再输出,消除电路毛刺。这种状态机也是比较推崇的,主要是由于维护方便,组合逻辑与时序逻辑完全独立。

状态机的描述通常包含以下四部分:

1)利用参数定义语句parameter描述状态机各个状态名称,即状态编码。状态编码通常有很多方法包含自然二进制编码,One-hot编码,格雷编码码等;

2)用时序的always块描述状态触发器实现状态存储;

3)使用敏感表和case语句(也采用if-else等价语句)描述状态转换逻辑;

4)描述状态机的输出逻辑。

6 仿真测试

编写Testbench测试文件的过程如下:

• 产生模拟激励(波形);

• 将产生的激励加入到被测试模块中并观察其响应;

• 将输出响应与期望值相比较。

一个完整的测试文件其结构为:

module Test_bench();//通常无输入无输出

信号或变量声明定义

逻辑设计中输入对应reg型

逻辑设计中输出对应wire型

使用initial或always语句产生激励

例化待测试模块监控和比较输出响应

endmodule

时钟激励设计

/*----------------------------------------------------------------

时钟激励产生方法一:50%占空比时钟

----------------------------------------------------------------*/

parameter ClockPeriod=10;

initial

begin

clk_i=0;

forever

#(ClockPeriod/2) clk_i=~clk_i;

end

/*----------------------------------------------------------------

时钟激励产生方法二:50%占空比时钟

----------------------------------------------------------------*/

initial

begin

clk_i=0;

always #(ClockPeriod/2) clk_i=~clk_i;

end



/*----------------------------------------------------------------

时钟激励产生方法四:产生固定数量的时钟脉冲

----------------------------------------------------------------*/

initial

begin

clk_i=0;

repeat(6)

#(ClockPeriod/2) clk_i=~clk_i;

end



/*----------------------------------------------------------------

时钟激励产生方法五:产生非占空比为50%的时钟

----------------------------------------------------------------*/

initial

begin

clk_i=0;

forever

begin

#((ClockPeriod/2)-2) 
    clk_i=0;

#((ClockPeriod/2)+2)
    clk_i=1;

end

end

复位信号设计

/*----------------------------------------------------------------

复位信号产生方法一:异步复位

----------------------------------------------------------------*/

initial

begin

rst_n_i=1;

#100;

rst_n_i=0;

#100;

rst_n_i=1;

end



/*----------------------------------------------------------------

复位信号产生方法二:同步复位

----------------------------------------------------------------*/

initial

begin

rst_n_i=1;

@(negedge clk_i)

rst_n_i=0;

#100; //固定时间复位

repeat(10) @(negedge clk_i); //固定周期数复位

@(negedge clk_i)

rst_n_i=1;

end



/*----------------------------------------------------------------

复位信号产生方法三:复位任务封装

----------------------------------------------------------------*/

task reset;

    input [31:0] reset_time; //复位时间可调,输入复位时间

RST_ING = 0; //复位方式可调,低电平或高电平

begin

rst_n = RST_ING; //复位中

#reset_time; //复位时间

rst_n_i=~RST_ING; //撤销复位,复位结束

end

endtask

双向信号设计

/*----------------------------------------------------------------

双向信号描述一:inout在testbench中定义为wire型变量

----------------------------------------------------------------*/

//为双向端口设置中间变量inout_reg作为inout的输出寄存,其中inout变

//量定义为wire型,使用输出使能控制传输方向

//inout bir_port;

wire bir_port;

reg bir_port_reg;

reg bi_port_oe;

assign bi_port=bi_port_oe ? bir_port_reg : 1'bz;



/*----------------------------------------------------------------

双向信号描述二:强制force

----------------------------------------------------------------*/

//当双向端口作为输出口时,不需要对其进行初始化,而只需开通三态门

//当双向端口作为输入时,只需要对其初始化并关闭三态门,初始化赋值需

//使用wire型数据,通过force命令来对双向端口进行输入赋值

//assign dinout=(!en) din :16'hz; 完成双向赋值

initial

begin

force dinout=20;

#200

force dinout=dinout-1;

end


特殊信号设计

/*----------------------------------------------------------------

特殊激励信号产生描述一:输入信号任务封装

----------------------------------------------------------------*/

task i_data;

input [7:0] dut_data;

begin

@(posedge data_en); send_data=0;

@(posedge data_en); send_data=dut_data[0];

@(posedge data_en); send_data=dut_data[1];

@(posedge data_en); send_data=dut_data[2];

@(posedge data_en); send_data=dut_data[3];

@(posedge data_en); send_data=dut_data[4];

@(posedge data_en); send_data=dut_data[5];

@(posedge data_en); send_data=dut_data[6];

@(posedge data_en); send_data=dut_data[7];

@(posedge data_en); send_data=1;

#100;

end

endtask

//调用方法:i_data(8'hXX);

/*----------------------------------------------------------------

特殊激励信号产生描述二:多输入信号任务封装

----------------------------------------------------------------*/

task more_input;

input [7:0] a;

input [7:0] b;

input [31:0] times;

output [8:0] c;

begin

repeat(times) //等待times个时钟上升沿

@(posedge clk_i)

c=a+b; //时钟上升沿a,b相加

end

endtask

//调用方法:more_input(x,y,t,z);  //按声明顺序

/*----------------------------------------------------------------

特殊激励信号产生描述三:输入信号产生,一次SRAM写信号产生

----------------------------------------------------------------*/

initial

begin

cs_n=1; //片选无效

wr_n=1; //写使能无效

rd_n=1; //读使能无效

addr=8'hxx; //地址无效

data=8'hzz; //数据无效

#100;

cs_n=0; //片选有效

wr_n=0; //写使能有效

addr=8'hF1; //写入地址

data=8'h2C; //写入数据

#100;

cs_n=1;

wr_n=1;

#10;

addr=8'hxx;

data=8'hzz;

end



/*----------------------------------------------------------------

Testbench中@与wait

----------------------------------------------------------------*/

//@使用沿触发

//wait语句都是使用电平触发

initial

begin

start=1'b1;

wait(en=1'b1);

#10;

start=1'b0;

end

仿真控制语句及系统任务描述

/*----------------------------------------------------------------

仿真控制语句及系统任务描述

----------------------------------------------------------------*/

$stop     //停止运行仿真,modelsim中可继续仿真

$stop(n) //带参数系统任务,根据参数0,1或2不同,输出仿真信息

$finish   //结束运行仿真,不可继续仿真

$finish(n)  //带参数系统任务,根据参数0,1或2不同,输出仿真信息

//0:不输出任何信息

//1:输出当前仿真时刻和位置

//2:输出当前仿真时刻、位置和仿真过程中用到的memory以及CPU时间的统计

$random //产生随机数

$random % n //产生范围-n到n之间的随机数

{$random} % n //产生范围0到n之间的随机数



/*----------------------------------------------------------------

仿真终端显示描述

----------------------------------------------------------------*/

$monitor //仿真打印输出,大印出仿真过程中的变量,使其终端显示

/*

$monitor($time,,,"clk=%d reset=%d out=%d",clk,reset,out);

*/

$display //终端打印字符串,显示仿真结果等

/*

$display(” Simulation start ! ");

$display(” At time %t,input is %b%b%b,output is %b",$time,a,b,en,z);



*/

$time //返回64位整型时间

$stime //返回32位整型时间

$realtime //实行实型模拟时间

/*----------------------------------------------------------------

文本输入方式:$readmemb/$readmemh

----------------------------------------------------------------*/

//激励具有复杂的数据结构

//verilog提供了读入文本的系统函数

$readmemb/$readmemh("<数据文件名>",<存储器名>);

$readmemb/$readmemh("<数据文件名>",<存储器名>,<起始地址>);

$readmemb/$readmemh("<数据文件名>",<存储器名>,<起始地址>,<结束地址>);

$readmemb:/*读取二进制数据,读取文件内容只能包含:空白位置,注释行,二进制数

数据中不能包含位宽说明和格式说明,每个数字必须是二进制数字。*/

$readmemh:/*读取十六进制数据,读取文件内容只能包含:空白位置,注释行,十六进制数

数据中不能包含位宽说明和格式说明,每个数字必须是十六进制数字。*/

      /*当地址出现在数据文件中,格式为@hh...h,地址与数字之间不允许空白位置,

可出现多个地址*/

module

reg [7:0] memory[0:3];//声明8个8位存储单元

integer i;

initial

begin

$readmemh("mem.dat",memory);//读取系统文件到存储器中的给定地址

//显示此时存储器内容

for(i=0;i<4;i=i+1)

$display("Memory[%d]=%h",i,memory[i]);

end

endmodule



/*mem.dat文件内容

@001

AB CD

@003

A1

*/

//仿真输出为

Memory[0] = xx;

Memory[1] = AB;

Memory[2] = CD;

Memory[3] = A1;
  • 43
    点赞
  • 408
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
目 录 译者序 前言 第1章 简介 1 1.1 什么是Verilog HDL? 1 1.2 历史 1 1.3 主要能力 1 第2章 HDL指南 4 2.1 模块 4 2.2 时延 5 2.3 数据流描述方式 5 2.4 行为描述方式 6 2.5 结构化描述形式 8 2.6 混合设计描述方式 9 2.7 设计模拟 10 第3章 Verilog语言要素 14 3.1 标识符 14 3.2 注释 14 3.3 格式 14 3.4 系统任务和函数 15 3.5 编译指令 15 3.5.1 `define和`undef 15 3.5.2 `ifdef、`else 和`endif 16 3.5.3 `default_nettype 16 3.5.4 `include 16 3.5.5 `resetall 16 3.5.6 `timescale 16 3.5.7 `unconnected_drive和 `nounconnected_drive 18 3.5.8 `celldefine 和 `endcelldefine 18 3.6 值集合 18 3.6.1 整型数 18 3.6.2 实数 19 3.6.3 字符串 20 3.7 数据类型 20 3.7.1 线网类型 20 3.7.2 未说明的线网 23 3.7.3 向量和标量线网 23 3.7.4 寄存器类型 23 3.8 参数 26 第4章 表达式 28 4.1 操作数 28 4.1.1 常数 28 4.1.2 参数 29 4.1.3 线网 29 4.1.4 寄存器 29 4.1.5 位选择 29 4.1.6 部分选择 29 4.1.7 存储器单元 30 4.1.8 函数调用 30 4.2 操作符 30 4.2.1 算术操作符 31 4.2.2 关系操作符 33 4.2.3 相等关系操作符 33 4.2.4 逻辑操作符 34 4.2.5 按位操作符 35 4.2.6 归约操作符 36 4.2.7 移位操作符 36 4.2.8 条件操作符 37 4.2.9 连接和复制操作 37 4.3 表达式种类 38 第5章 门电平模型化 39 5.1 内置基本门 39 5.2 多输入门 39 5.3 多输出门 41 5.4 三态门 41 5.5 上拉、下拉电阻 42 5.6 MOS开关 42 5.7 双向开关 44 5.8 门时延 44 5.9 实例数组 45 5.10 隐式线网 45 5.11 简单示例 46 5.12 2-4解码器举例 46 5.13 主从触发器举例 47 5.14 奇偶电路 47 第6章 用户定义的原语 49 6.1 UDP的定义 49 6.2 组合电路UDP 49 6.3 时序电路UDP 50 6.3.1 初始化状态寄存器 50 6.3.2 电平触发的时序电路UDP 50 6.3.3 边沿触发的时序电路UDP 51 6.3.4 边沿触发和电平触发的混合行为 51 6.4 另一实例 52 6.5 表项汇总 52 第7章 数据流模型化 54 7.1 连续赋值语句 54 7.2 举例 55 7.3 线网说明赋值 55 7.4 时延 55 7.5 线网时延 57 7.6 举例 57 7.6.1 主从触发器 57 7.6.2 数值比较器 58 第8章 行为建模 59 8.1 过程结构 59 8.1.1 initial 语句 59 8.1.2 always语句 61 8.1.3 两类语句在模块中的使用 62 8.2 时序控制 63 8.2.1 时延控制 63 8.2.2 事件控制 64 8.3 语句块 65 8.3.1 顺序语句块 66 8.3.2 并行语句块 67 8.4 过程性赋值 68 8.4.1 语句内部时延 69 8.4.2 阻塞性过程赋值 70 8.4.3 非阻塞性过程赋值 71 8.4.4 连续赋值与过程赋值的比较 72 8.5 if 语句 73 8.6 case语句 74 8.7 循环语句 76 8.7.1 forever 循环语句 76 8.7.2 repeat 循环语句 76 8.7.3 while 循环语句 77 8.7.4 for 循环语句 77 8.8 过程性连续赋值 78 8.8.1 赋值—重新赋值 78 8.8.2 force与release 79 8.9 握手协议实例 80 第9章 结构建模 83 9.1 模块 83 9.2 端口 83 9.3 模块实例语句 83 9.3.1 悬空端口 84 9.3.2 不同的端口长度 85 9.3.3 模块参数值 85 9.4 外部端口 87 9.5 举例 89 第10章 其他论题 91 10.1 任务 91 10.1.1 任务定义 91 10.1.2 任务调用 92 10.2 函数 93 10.2.1 函数说明部分 93 10.2.2 函数调用 94 10.3 系统任务和系统函数 95 10.3.1 显示任务 95 10.3.2 文件输入/输出任务 97 10.3.3 时间标度任务 99 10.3.4 模拟控制任务 99 10.3.5 定时校验任务 100 10.3.6 模拟时间函数 101 10.3.7 变换函数 102 10.3.8 概率分布函数 102 10.4 禁止语句 103 10.5 命名事件 104 10.6 结构描述方式和行为描述方式的 混合使用 106 10.7 层次路径名 107 10.8 共享任务和函数 108 10.9 值变转储文件 110 10.9.1 举例 111 10.9.2 VCD文件格式 112 10.10 指定程序块 113 10.11 强度 114 10.11.1 驱动强度 114 10.11.2 电荷强度 115 10.12 竞争状态 116 第11章 验证 118 11.1 编写测试验证程序 118 11.2 波形产生 118 11.2.1 值序列 118 11.2.2 重复模式 119 11.3 测试验证程序实例 123 11.3.1 解码器 123 11.3.2 触发器 124 11.4 从文本文件中读取向量 126 11.5 向文本文件中写入向量 127 11.6 其他实例 128 11.6.1 时钟分频器 128 11.6.2 阶乘设计 130 11.6.3 时序检测器 132 第12章 建模实例 136 12.1 简单元件建模 136 12.2 建模的不同方式 138 12.3 时延建模 139 12.4 条件操作建模 141 12.5 同步时序逻辑建模 142 12.6 通用移位寄存器 145 12.7 状态机建模 145 12.8 交互状态机 147 12.9 Moore有限状态机建模 150 12.10 Mealy型有限状态机建模 151 12.11 简化的21点程序 153 附录 语法参考 157 参考文献 172

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黄小鹿

帮博主买点六味地黄丸吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值