语法要点详细讲解课件.ppt

上传人:本田雅阁 文档编号:3306414 上传时间:2019-08-10 格式:PPT 页数:144 大小:683.04KB
返回 下载 相关 举报
语法要点详细讲解课件.ppt_第1页
第1页 / 共144页
语法要点详细讲解课件.ppt_第2页
第2页 / 共144页
语法要点详细讲解课件.ppt_第3页
第3页 / 共144页
语法要点详细讲解课件.ppt_第4页
第4页 / 共144页
语法要点详细讲解课件.ppt_第5页
第5页 / 共144页
点击查看更多>>
资源描述

《语法要点详细讲解课件.ppt》由会员分享,可在线阅读,更多相关《语法要点详细讲解课件.ppt(144页珍藏版)》请在三一文库上搜索。

1、语法要点详细讲解,有关测试模块编写的语法 ; 语法的高级部分: 函数、任务、文件、存贮器建立模型、 双向总线、UDP、综合指令。,语法详细讲解 Verilog测试模块的编写,目的: 复习如何编写较复杂的测试文件,对所做的设计 进行完整的测试和验证。 掌握组织模块测试的常用方法;学会编写常用的 测试代码。,语法详细讲解 用Verilog设计的步骤,注:虚线表示编译器能检查输入文件的可读性和是否存在以及是否允许生成输出文件,include 文件,设计文件,厂家元件 库文件,输入文件:激励和期望的输出信号,输出文件:激励和实际输出的信号,编译器,仿真器,仿真器,语法详细讲解 测试平台的组成,激励 信

2、号,需要验证的 设计,激励信号 和用于验 证的结果 数据,需要验证的 设计,简单的测试平台,复杂的测试平台,语法详细讲解 并行块,在测试块中常用到forkjoin块。用并行块能表示以同一个时间起点算起的多个事 件的运行,并行地执行复杂的过程结构,如循环或任务。举例说明如下: module inline_tb; reg 7:0 data_bus; initial fork data_bus= 8b00; #10 data_bus = 8h45; /这两个repeat开始执行时间不同,但能同时运行 #20 repeat (10) #10 data_bus = data_bus +1; #25 re

3、peat (5) # 20 data_bus = data_bus 1; #140 data_bua = 8h0f; join endmodule,语法详细讲解 并行块,时间 data_bus 0 8b0000_0000 10 8b0100_0101 30 8b0100_0110 40 8b0100_0111 45 8b1000_1110 50 8b1000_1111 60 8b1001_0000 65 8b0010_0000 70 8b0010_0001,时间 data_bus 80 8b0010_0010 85 8b0100_0100 90 8b0100_0101 100 8b0010_0

4、001 105 8b0100_0110 110 8b1000_1100 120 8b1000_1110 125 8b0001_1100 140 8b0000_1111,上面模块的仿真输出如下:,语法详细讲解 强制激励,在一个过程块中,可以用两种不同的方式对信号变量或表达式进行连续赋值。 过程连续赋值往往是不可以综合的,通常用在测试模块中。 两种方式都有各自配套的命令来停止赋值过程。 两种不同方式均不允许赋值语句间的时间控制。 assign和deassign 适用于对寄存器类型的信号 (例如:RTL级上的节点或测试模块中在多个地方被赋值的信号)进行赋值。 initial begin #10 as

5、sign top.dut.fsml.state_reg = init_state;,#20 deassign top.dut.fsml.state_reg; end force 和 release 用于寄存器类型和网络连接类型(例如:门级扫描寄存器的输出)的强制赋值,强制改写其它地方的赋值。 initial begin # 10 force top.dut.counter.scan_reg.q=0; # 20 release top.dut.counter.scan_reg.q; end 在以上两个例子中,在10到20 这个时间段内,网络或寄存器类型的信号被强制赋值,而别处对该变量的赋值均无效

6、。 force的赋值优先级高于assign。 如果先使用assign,再使用force对同一信号赋值,则信号的值为force所赋 的值,,语法详细讲解 强制激励,语法详细讲解 强制激励,当执行release后,则信号的值为assign所赋 的值。 如果用force对同一个信号赋了几次值,再执行release,则所有赋的值均不再存在。 可以对信号的某(确定)位、某些(确定)位或拼接的信号,使用force和release赋值;但不能对信号的可变位使用force和release 来赋值。 不能对寄存器类型的信号某位或某些位使用 assign 和deassign 来赋值。,虽然有时在设计中会包含时钟,

7、但时钟通常用在测试模块中。下面 三个例子分别说明如何在门级和行为级建立不同波形的时钟模型。 例1 简单的对称方波时钟:,reg clk; always begin #period/2 clk=0; #period/2 clk=1; end,reg go; wire clk; nand #(period/2) ul (clk,clk,go); initial begin go=0; #(period/2) go=1; end,注:在有些仿真器中,如果设计所用的时钟是由与其相同抽象级别的时钟模型产生的,则仿真器的性能就能得到提高。,语法详细讲解 建立时钟,例2简单的带延迟的对称方波时钟:,语法详细

8、讲解 建立时钟,reg clk; initial begin clk=0; #(period) forever #(period/2) clk=!clk end,reg go; wire clk; nand #(period/2) ul (clk,clk,go); initial begin go=0; #(period) go=1; end,注:这两个时钟模型有些不同,行为描述的模型延迟期间一直是低电平,而门级描述的模型开始延迟有半个周期是不确定的。,例3. 带延迟、头一个脉冲不规则的、占空比不为1的时钟:,reg clk; initial begin #(period+1) clk=1;

9、#(period/2-1) forever begin #(period/4) clk=0; #(3*period/4) clk=1; end end,reg go; wire clk; nand #(3*period/4,period/4) ul (clk,clk,go); initial begin #(period/4+1) go=0; #(5*period/4-1) go=1; end,注:这两个时钟模型也有些不同,行为描述的模型一开始就有确定的电平,而门级描述的模型有延迟, 开始时电平是不确定的。,语法详细讲解 建立时钟,例2简单的带延迟的对称方波时钟:,语法详细讲解 建立时钟,re

10、g clk; initial begin clk=0; #(period) forever #(period/2) clk=!clk end,reg go; wire clk; nand #(period/2) ul (clk,clk,go); initial begin go=0; #(period) go=1; end,注:这两个时钟模型有些不同,行为描述的模型延迟期间一直是低电平,而门级描述的模型开始延迟有半个周期是不确定的。,语法详细讲解 怎样使用任务,举例说明如何使用任务: module bus_ctrl_tb; reg 7:0 data; reg data_valid, data_

11、rd; cpu ul(data_valid,data,data_rd); initial begin cpu_driver (8b0000_0000); cpu_driver (8b1010_1010); cpu_driver (8b0101_0101); end,语法详细讲解 怎样使用任务,task cpu_driver; input 7:0 data_in; begin #30 data_valid =1; wait (data_rd = =1); #20 data = data_in; wait (data_rd= =0); #20 data = 8hzz; #30 data_valid

12、 = 0; end endtask endmodule,语法详细讲解 怎样使用任务,在测试模块中使用任务可以提高程序代码的效率,可以用任务把多次重复的操作包装起来。,语法详细讲解 存储建模,目标 学会如何用Verilog对存储器建模。 学会如何用Verilog中对双向(即输入/输出)端口, (inout)建模。,存储器建模必须注意以下两个方面的问题: 声明存储器容量的大小。 明确对存储器访问操作的权限。 例如:指出可以对存储器做以下哪几种操作: 1)只读 2)读写 3)同步读写 4)多次读,同时进行一次写 5)多次同步读写,同时提供一些方法保证一致性,语法详细讲解 存储器建模,timescal

13、e 1ns/10ps module myrom(read_data,addr,read_en_); input read_en_; input 3:0 addr; output 3:0 read_data; reg 3:0 read_data; reg 3:0 mem 0:15; initial $readmemb(“my_rom_data”,mem); always (addr or read_en_) if(!read_en_) read_data=memaddr; endmodule,语法详细讲解 简单 ROM 建模,my_rom_data 0000 0101 1100 0011 110

14、1 0010 0011 1111 1000 1001 1000 0001 1101 1010 0001 1101,ROM的数据存储在另外的一个独立的文件中,语法详细讲解 简单ROM建模,上页所示的ROM模型说明: 如何在Verilog中用二维的寄存器组来定义存储器。 ROM中的数据保存在一个独立的文件中,如上页的右边的虚线方框所示。 这是一种保存ROM数据的通用的方法,它可以使数据和ROM模型分开。,语法详细讲解 简单RAM建模,timescale 1ns/1ns module mymem(data,addr,read,write); inout 3:0 data; inout 3:0 add

15、r; input read, write; reg 3:0 memory 0:15; /4 bits, 16 个单元 /从存储器读出到总线上 assign data=read? memoryaddr:4bz; /从总线写入存储器 always (posedge write) memoryaddr=data; endmodule,语法详细讲解 简单RAM建模,RAM模型比ROM模型稍微复杂: 它必须具有读写能力; 进行读写时通常使用相同的数据总线; 需要新技术来处理双向总线; 当读信号无效时,RAM模型与总线脱离,如果此时写 信号也无效,总线无驱动源,则总线进入高阻状态, 这就避免了RAM中的读

16、写竞争。 上页的 RAM 模块是可综合的,但综合出来是一大堆寄存器,占比较大的面积,经济上不太合算。,例: module scalable_ROM (mem_word, address); parameter addr_bits=8; /size of address bus parameter wordsize=8; /width of a word parameter words=(1addr_bits); /size of mem output wordsize:1 mem_word; /word of memory input addr_bits:1 address; /address

17、 bus reg wordsize:1 mem 0 : words-1; /mem declaration /output one word of memory wire wordsize:1 mem_word=memaddress; endmodule,语法详细讲解 存储量可变的只读存储器建模,语法详细讲解 存储量可变的只读存储器建模,上述的例子演示了怎样通过设置字长和地址位数来编 写 只读存储器的行为模块。 注意 ! 在上例中,存储字的范围从0开始的,而不是从1开始,这是因为存储单元是直接通过地址线寻址定位的。 同样地,也可以用下面的方法来定义存储器和寻址: reg wordsize:1

18、mem 1:words; /存储器地址 从1 开始 /地址一个一个地增加直到包含了每个地址对应的存储器 wire wordsize:1 mem_word = memaddress+1;,可以在初始化块中用一个循环或系统任务把初始数据存入存储器的每个单元。 使用循环把值赋给存储器数组。 for(i=0;imemsize;i=i+i) / initialize memory memai=wordsize1b1; 调用$readmem系统任务。 /从文件 mem_file.txt 中, 把初始数据存入存储器(mem)的每个单元 $readmemb(“mem_file.txt”,mem); 注意:上面

19、两项必须写 在initial 块中,加载这些初始化数据不需要时间。,语法详细讲解 存储器的加载,语法详细讲解 怎样使用双向口,使用inout关键字声明端口为双向口。 inout 7:0 databus; 使用双向口必需遵循下面的规则: inout口只能声明为网络连接类型, 不允许把它声明为寄存器类型。(所以仿真器能确定多个驱动源的最终值。) 在设计中,每次只能从一个方向来驱动inout口。 例如:当使用总线读RAM中的数据时,如果同时又向RAM模型的双向数据总线写数据,就会产生逻辑竞争,导致总线数据无法确定。所以必须为inout口设计控制逻辑,只有这样才能保证正确的操作。,语法详细讲解 怎样使

20、用双向口,注意: 声明一个inout口,可以用来输入或输出数据。inout口默认为网络连接类型。不允许在过程块(initial 或always块)中对网络连接类型的数据进行过程赋值;但可以在过程块外把一个寄存器数据类型通过连续赋值语句赋给它(inout口),或者把它与用户定义的源语(UDP)相连。 必须为inout口设计控制逻辑,用来保证正确的操作。当把inout口作为输入口时,必须通过控制逻辑禁止输出到inout口。,使用Verilog中的基本元件(bufif1)为双向口建模:,语法详细讲解 双向口建模,语法详细讲解 双向口建模,注意: 在上页的例子中,使用en_a_b和en_b_a 来控制

21、元器件bufifl,如果控制信号同时有效,则结果无法确定。 所以必须把控制信号 en_a_b 和 en_b_a 在时间上分开。,module bus_xcvr(bus_a,bus_b,en_a_b,en_b_a); inout bus_a,bus_b; input en_a_b,en_b_a; bufifl b1(bus_b,bus_a,en_a_b); bufifl b2(bus_a,bus_b,en_b_a); /结构模块逻辑 endmodule,当en_a_b=1时,元器件b1激活,bus_a的值传到bus_b上,当en_b_a=1时,元器件b1激活,bus_b的值传到bus_a上,使用

22、连续赋值为双向口建模:,语法详细讲解 双向口建模,注意:在assign语句中,通过en_a_b和en_b_a控制bus_a与bus_b之间的数据交换。如果控制信号同时有效,则结果不能确定。所以必须把控制信号 en_a_b 和 en_b_a 在时间上分开。,语法详细讲解 双向口建模,存储器的端口建模:,语法详细讲解 双向口建模,注意: 上页中存储单元在wr的下降沿到达时存入数据。上页模块在 wr处于高电平时,通过数据总线写入数据,但必须保证wr的高电平维持时间长于数据的写入时间。 在rd处于高电平时,上述存储单元通过数据总线读出数据。由于此模型为单口存储模型,因此wr变低电平时,rd不能同时为高

23、电平,否则就无法确定存储器的读出/写入的结果。,语法详细讲解 双向口建模,目标: 学会怎样定义或调用任务和函数。 学会怎样使用命名块。 学会怎样禁止命名块和任务。 理解有限状态机的作用,学会如何显式地为有限状态机建模。,语法详细讲解 Verilog中的高级结构,通过把代码分成小的模块或者使用任务和函数,可把一项任务分成许多较小的、易于管理的部分,从而提高代码的可读性、可维护性和可重用性。 任务: 一般用于编写测试模块或者行为描述的模块。其中可以包含时间控制(如:# delays, , wait);也可以包含input, output 、inout 端口定义和参数;也可以调用其他的任务或函数,语

24、法详细讲解 Verilog中的高级结构,函数: 一般用于计算,或者用来代替组合逻辑。 不能包含任何延迟;函数在零时间执行。 函数只有input变量,虽然没有output变量, 但可以通过函数名返回一个值。 可以调用其他的函数,但不可以调用任务,语法详细讲解 Verilog中的高级结构,注意: 只能调用本模块内的任务和函数。 在任务和函数中不能声明网络连接类型的变量。 所有的输入和输出变量实际上都是本地寄存器 。 只有当任务或函数调用并执行完后,才能有返回值。 举例说明: 若任务或函数中包含一个forever循环时,永远无法执行完,就不可能有返回值。,语法详细讲解 Verilog中的高级结构,语

25、法详细讲解 Verilog 任务,下面模块中的任务含有定时控制和一个输入,并且引用了一个本模块的变量,但是没有输出,也没有双向总线和内部变量,不显示任何内容。 用于定时控制的信号,例如 clk,绝对不能作为任务的输入,这是因为输入值只向任务内部传递一次。 module top; reg clk, a, b; DUT u1(out, a, b, clk); always #5 clk=!clk;,语法详细讲解 Verilog 任务,task neg_clocks; input 31:0 number_of_edges; repeat(number_of_edges) (negedge clk);

26、 endtask initial begin clk=0; a=1; b=1; neg_clocks(3); /任务调用 a=0; neg_clocks(5); b=0; end endmodule,要点: 任务调用是通过在Verilog模块中写入任务名来实现的。 任务中可以包含input, output和inout端口变量的声明。 传递给任务的变量与任务I/O端口变量的声明次序相同。虽然传递给任务的变量名可以和任务内声明的I/O端口变量名相同,但是为了使任务成为一个独立的可共用的任务块,建议不要使用与任务内声明的I/O端口变量名相同的变量名,最好给传递到任务的变量起新的不同的名字。 在任务中

27、可以使用时间控制。 任务使Verilog有更广阔的适用范围。 关键字disable可以用来禁止任务的执行。,语法详细讲解 Verilog 任务,注意: 不要在程序的不同部分同时调用同一个任务。这是因为任务只有一组本地变量,同一时刻调用两次相同的任务将会导致错误。这种情况常发生在使用定时控制的任务中。 在任务或函数中,引用父模块中声明的变量时要特别注意(即注意变量的层次命名规则)。若想在其它模块中调用任务或函数,该任务和函数中所使用的变量必须全都包含在输入/输出口列表中。,语法详细讲解 Verilog 任务,下面模块中的任务只含有一个双向总线(inout)端口和一个内部变量,没有其它输入端口、输

28、出端口和定时控制,没有引用模块变量,不显示任何内容。 在任务调用时,任务的输入变量(端口)在任务内部被当作寄存器类型变量处理。,语法详细讲解 Verilog 任务,parameter MAX_BITS=8; reg MAX_BITS:1 D; task reverse_bits; inout 7:0 data; /双向总线端口被当作寄存器类型! integer K; for (k=0; kMAX_BITS; K=K+1) reverse_bits MAXBITS (K+1) = dataK; endtask always (posedge clk) reverse_bits (D); ,语法详

29、细讲解 Verilog 任务,下面模块中定义的任务含有输入、输出、时间控制和一个内部变量,并且引用了一个本模块的变量,但是没有输出,不显示任何内容。任务调用时变量顺序应与任务定义中声明的顺序相同。,语法详细讲解 Verilog 任务,module mult(clk, a, b, out, en_mult); input clk, en_mult; input 3:0 a, b; output 7:0 out; reg 15:0 out; always (posedge clk) multme(a, b, out); /任务调用,task multme; /任务定义 input 3:0 xme,

30、 tome; output 7:0 result; wait (en_mult) result=xme*tome; endtask endmodule,语法详细讲解 Verilog 任务,module orand (a, b, c, d, e, out); input 7:0 a, b, c, d, e; output 7:0 out; reg 7:0 out; always (a or b or c or d or e) out = f_or_and (a, b, c, d, e); /函数调用 function 7:0 f_or_and; input 7:0 a, b, c, d, e;

31、if (e= =1) f_or_and = (a|b) endfunction endmodule,语法详细讲解 Verilog 函数,虽然函数不能包含定时控制,但是可以在包含定时控制的过程块中调用函数。在模块中,使用名为f_or_and的函数时,是把它作为名为f_or_and 的寄存器类型变量来处理的。,语法详细讲解 Verilog 函数,要点 函数定义不能包含任何定时控制语句。 函数必须至少有一个输入,但绝不能含有任 何输出和总线口; 一个函数只能返回一个值,该值的变量名与 函数同名,数据类型默认为reg类型。 传递给函数的变量顺序与函数输入口声明的 顺序相同。 函数定义必须包含在模块定义

32、之内。 函数不能调用任务,但任务可以调用函数。 函数使Verilog有更广阔的适用范围。 虽然函数只能返回一个值,但是它的返回值 可以直接赋给一个由多个子信号拼接构成的 信号变量, 使其实际等效于产生了多个输出。 o1, o2, o3, o4 = f_or_and(a, b, c, d, e);,语法详细讲解 Verilog 函数,在函数定义时,如果在函数名前面定义了位宽,该函数就可以返回由多位构成的矢量。如果定义函数的语句比较多时,可以用 begin 和end 把它们组合起来。 在函数内,无论以函数名命名的变量被赋了多少次值,函数只有一个返回值。 下例中的函数,声明了一个内部整型变量。举例说

33、明如下:,语法详细讲解 Verilog 函数,module foo; input 7:0 loo; /也可以用连续赋值语句调用函数 wire 7:0 goo = zero_count (loo); function 3:0 zero_count; input 7:0 in_bus; integer I; begin zero_count = 0; for (I=0; I8; I= I+1) if (!in_busI) zero_count = zero_count +1; end endfunction endmodule,语法详细讲解 Verilog 函数,若把函数定义为整型、实型或时间类型

34、,就可以返回相应类型的数据。我们可以在任何类型的表达式中调用函数。 module checksub(neg,in_a,in_b); output neg; input a, b; reg neg; function integer subtr; input 7:0 in_a, in_b; subtr = in_a in_b; /运算结果可以为负数 endfunction,语法详细讲解 Verilog 函数,always (a or b) begin if ( subtr (a,b) 0) neg = 1; else neg = 0; end endmodule,语法详细讲解 Verilog 函

35、数,函数类型、端口和行为定义时也可以使用参数, 这样就可以构成参数化函数使其返回的数据类型、输入端口的位宽等很容易做修改。所以参数化函数就有更广泛的适用范围。,语法详细讲解 Verilog 函数,. parameter MAX_BITS =8; reg MAX_BITS:1 D; function MAX_BIT:1 reverse_bits; input 7:0 data; for(K=0; K MAX_BITS; K=K+1) reverse_bits MAX_BITS (K+1) = data K; endfunction always (posedge clk) begin . D=

36、reverse_bits(D); end ,语法详细讲解 Verilog 函数,语法详细讲解 命名块,可以通过在关键字begin或fork后加上:块名来给块命名。 module named_blk; begin :seq_blk end fork : par_blk join endmodule 可以在命名块中声明本地变量。 可以使用disable禁止命名块。,注意: 命名块使Verilog有更广阔的适用范围。 命名块的使用缩短了仿真的时间。,语法详细讲解 命名块,语法详细讲解 禁止命名块和任务,module do_arith(out, a, b, c, d, e, clk, en_mult)

37、; input clk, en_mult; input 7:0 a, b, c, d, e; output 15:0 out; reg 14:0 out; always (posedge clk) begin : arith_block /*命名名为arith_block的块* reg 3:0 tmp1, tmp2; /*本地变量* tmp, tmp2 = f_or_and(a, b, c, d, e); / 函数调用 if(en_mult) multme(tmp1, tmp2, out); /任务调用 end,语法详细讲解 禁止命名块和任务,always (negedge en_mult)

38、begin /停止计算 disable multme; /*禁止任务的执行 diable arith_block; /*禁止命名块的执行 end /在此定义任务和函数 endmodle,注意: disable语句用来终止命名块或任务的执行。这是指在尚未执行该命名块或任务任何一条语句前,就从该命名块/任务执行中返回。 语法: disable 块名 或 disable 任务名 禁止执行命名块或任务后,所有在事件队列中由该命名块/任务安排的事件都将被删除。 一般 情况下disable语句是不可综合的。 在上页的例子中,只禁止命名块也可以得到预期的结果:命名块中所有的事件,包括任务和函数的执行都将被取

39、消。,语法详细讲解 禁止命名块和任务,目的: 学习LPM(Library of Parameterrized Modules) 资源的利用; 学习调试用系统任务的利用: $random; $fmonitor; $fdisplay $fopen ; $fclose; $readmemh,语法详细讲解 系统资源和任务的利用,语法详细讲解 怎样利用参数化模块,在LPM库中必须已经有该具体参数化模块,名称和使用注意点已经通过阅读说明书搞清楚了,举例如下:,语法详细讲解 随机数的产生$random,语法要点:$random; $random(); 举例如下:,语法详细讲解 文件的使用,语法要点:$fop

40、en(“文件名“); file_handle=$fopen(“文件名“); /标准的输出显示器 descriptor=32h0000_0001(bit 0 set) integer handle1, handle2; initial begin handle1= $fopen(“file1.out“); /bit 1 set handle2= $fopen(“file2.out“); /bit 2 set handle3= $fopen(“file3.out“); /bit 2 set end,语法详细讲解 写到文件中去,语法要点: $fdisplay (,p1,p2,.pn); $fmoni

41、tor (,p1,p2,.pn); integer desc1,desc2,desc3; initial begin desc1=handle1|1; fdisplay(desc1, “ Display 1“,); /写到文件file1.out (handle1)和显示器(1)(stdout) desc2=handle2|handle1; fdisplay(desc2, “ Display 2“,); /写到文件file1.out (handle1)和文件file2.(handle2) desc3=handle3; fdisplay(desc3, “ Display 3“,); /只写到文件f

42、ile3.out (handle1)中 end,语法详细讲解 关闭文件,语法要点: $fclose (); 举例: $fclose(handle1); /关闭file1.out,语法详细讲解 层次信息的显示,可以用于任何显示任务如:$display,$write,$monitor,$strobe. 举例: module M; . initial $display (“Displaying in %m“); endmodule module top; M m1( ); /显示层次信息 M m2( ); M m3( ); . endmodule,语法详细讲解 层次信息的显示,显示任务结果如下:,语

43、法详细讲解 用文件中的数据初始化存储器,语法要点: $readmemb(文件名,存储器名); $readmemb(文件名, 存储器名,起始地址); $readmemh(文件名, 存储器名,起始地址); 举例: module test; reg 7:0 memory 0:1023 integer i; inititial begin $readmemb (“init.dat“,memory); for (i=0;i1024;i=i+1;) $display (“memory %0d=%b“, i, memory); end endmodule,语法详细讲解 用文件中的数据初始化存储器,init.

44、dat 文件内容: 002 1111_1111 0101_0101 0000_0000 1010_1010 008 Zzzz_1111 0000_1111 1111_0000 0001_1000 .,memory 0=xxxxxxxx memory 1=xxxxxxxx memory 2=11111111 memory 3=01010101 memory 4=00000000 memory 5=10101010 memory 6=xxxxxxxx memory 7=xxxxxxxx memory 8=zzzz1111 memory 9=00001111 memory 10=11110000 m

45、emory 11=00011000 . ,语法详细讲解 有限状态机(FSM),隐式FSM: 不需要状态寄存器 仿真更加有效 只能很好地处理线性的状态改变 大部分综合工具不支持隐式FSM,state 1,state 2,state 3,state 4,语法详细讲解 有限状态机(FSM),显式FSM: 结构比较复杂 可以很方便地用来处理默认状态 能够处理复杂的状态改变 所有的综合工具均支持显式FSM 的综合,state A,state B1,state B2,state C,state D,注意: 在隐式状态机中,只要发生在一个时钟周期内写数据,在另一个时钟周期内读数据的情况,都会生成寄存器。 任

46、何状态机都必须有复位控制信号,状态的改变必需只与某单一时钟信号沿同步。 一般情况下,如果状态改变比较简单,又定义得比较好,而且综合工具支持隐式状态机的综合,就可以使用隐式状态机。如果状态改变比较复杂,最好使用显式状态机,这样效果更好。 隐式状态机属于行为级,不属于RTL级。代码中主要包含循环语句、嵌入的定时控制,有时也含有命名事件、wait 和 disable 语句。一般情况下,常用的综合工具不支持隐式状态机的综合。,语法详细讲解 有限状态机(FSMs),语法详细讲解 显式有限状态机,module exp(out, datain, clk, rst); input clk, rst, data

47、in; output out; reg out; reg state; always (posedge clk or posedge rst) if(rst) state, out=2b00; else case(state) 1b0: begin out=1b0; if(!datain) state=1b0; else state=1b1; end 1b1 begin,状态变量,case语句,out=datain; state=1b0; end default: state, out=2b00; endcase endmodule 注: 在过程块中可以使用一个时钟沿和 case 语句来描述一个显式状态机。 必须指定一个状态变量,来记录状态机的状态。 要改变当前的状态,必须改变状态变量的值, 其改变要与时钟沿同步。 写得比较好的状态机常为不应产生的条件规定一个默认动作。,语法详细讲解 显式有限状态机,转到下一个状态,默认状态指针,begin: seq_block out=1b0; if(!datain) /状态一:输出零 disabl

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1