版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
EDA技术及应用高等职业教育本科精品教材PART01单元1EDA概述PART02单元2VerilogHDL结构与要素PART03单元3VerilogHDL描述语句PART05单元5常用模块电路的VerilogHDL设计PART06单元6基础设计PART07单元7IP核的应用目录CONTENTSPART04单元4QuartusPrime设计基础PART08单元8综合设计PART03单元3VerilogHDL描述语句3.1赋值语句3.2条件语句3.3结构说明语句3.4循环控制语句3.5生成语句3.6语句的顺序执行与并行执行3.7元件例化语句3.8参数传递语句3.1赋值语句3.1赋值语句3.1.1连续赋值语句实时更新左边目标变量的值,这种实时性保证了逻辑电路能迅速对输入的变化做出相应的输出调整。其语法格式如下:3.1赋值语句连续赋值语句中被赋值变量需要定义为wire型。Verilog中的变量默认为wire型,因此不用重复定义。【例3.1】设计实现一个二输入与门逻辑。3.1赋值语句在例3.1中,通过连续赋值语句assignout=a&b,将输入信号a和b进行与运算后的值实时赋给输出信号out。其仿真波形如图31所示,只要a和b的值发生变化,out的值就会立刻根据逻辑关系相应改变。3.1赋值语句在连续赋值语句中,被赋值的变量不能被重复赋值。在例3.2代码中,第二个assign语句中的c被再次赋值是错误的。【例3.2】错误使用assign语句对同一信号重复赋值。3.1赋值语句3.1.2过程赋值语句过程赋值语句必须在块语句中使用,如always块语句、function语句等。需要注意的是过程赋值语句中被赋值的每个信号都必须定义成reg型。IEEEVerilog标准中提供了两种过程赋值语句:阻塞赋值语句和非阻塞赋值语句。同一块内的阻塞赋值语句之间有先后执行顺序。阻塞的含义是在同一个块中,当前阻塞赋值语句正在执行时,禁止其后的所有其他赋值语句执行。只有当前阻塞赋值语句执行完成后,其后的赋值语句才能被执行,即语句是顺序执行的。非阻塞赋值语句之间没有先后执行顺序。非阻塞的含义是在同一个块中,当前非阻塞赋值语句执行的同时允许其他语句执行,即语句是并行执行的。1.阻塞赋值在块语句内采用符号“=”的赋值语句为阻塞赋值语句。其基本语法格式为:3.1赋值语句例3.3说明了阻塞赋值语句的应用。【例3.3】阻塞赋值示例。3.1赋值语句在always块内,当满足时钟上升沿(posedgeclk)这个触发条件时,会顺序执行赋值语句。首先执行b=a,将a的值赋给b,并且只有当这条赋值语句执行完成后,才会执行c=b这条赋值语句,即语句是顺序执行的。例3.3仿真波形如图32所示。3.1赋值语句阻塞赋值常用于构建简单的顺序执行的组合逻辑块,在这种场景下,要求严格按照语句书写的顺序来更新变量的值。在实际的逻辑设计中,有时会对一些临时变量进行赋值,并且后续语句依赖这些临时变量确定更新后的数值,而阻塞赋值恰好能保证这种逻辑的准确性,避免出现因赋值顺序混乱而导致的逻辑错误。2.非阻塞赋值在块语句内采用符号“<=”的赋值语句为非阻塞赋值语句。其基本语法格式为:3.1赋值语句例3.4说明了非阻塞赋值语句的应用。【例3.4】非阻塞赋值示例。3.1赋值语句仿真波形如图33所示。3.1赋值语句在例3.4中,满足时钟上升沿(posedgeclk)这个触发条件时,就会执行非阻塞赋值操作。非阻塞赋值语句执行时,同一语句块内的所有非阻塞赋值语句会同时启动。不会像阻塞赋值语句那样按照顺序依次执行,而是各自独立地进行赋值操作,不会相互阻塞。虽然非阻塞赋值语句是同时启动的,但不会立即更新目标变量的值。在一个时钟周期内,即使在always块中存在多个非阻塞赋值语句,时钟边沿触发后也不会马上改变变量的值,而是在该时钟周期末尾同步更新,以此保证赋值操作的同步性。非阻塞赋值语句在时序逻辑电路中应用广泛。例如在构建计数器、移位寄存器、状态机等时序逻辑电路时,能确保在时钟边沿触发时,各个寄存器的赋值操作有序且同步更新,避免出现逻辑错误。3.2条件语句3.2条件语句Verilog中的条件语句是实现逻辑控制和分支选择的重要工具,主要包括if-else语句和case语句。3.2.1
if-else语句if-else语句根据表达式的值来执行块中的内容,其格式与C语言中的if-else语句相似,具备不同的分支形式,以适应多样化的逻辑需求。1.单分支if语句语法格式如下:3.2条件语句条件表达式是一个逻辑表达式,其计算结果为布尔值(真或假)。begin和end用于将多条语句组合成一个语句块。如果语句块中只有一条语句,begin和end可以省略。【例3.5】单分支if语句示例。3.2条件语句在例3.5中,当a的值为真(即逻辑值为1)时,会执行result=1;这条赋值语句,将result的值设置为1。如果a的值为假(即逻辑值为0),则不会执行该赋值语句,result的值保持不变。仿真波形如图34所示。3.2条件语句2.双分支if-else语句语法格式如下:3.2条件语句【例3.6】双分支if-else语句示例。3.2条件语句在例3.6中,if语句判断a是否为真,若条件成立,result被赋值为1,若条件不成立,执行else分支,result被赋值为0。仿真波形如图35所示,result的值会根据a的电平状态改变。3.2条件语句3.多分支语句语法格式如下:3.2条件语句【例3.7】多分支语句示例。3.2条件语句【例3.7】多分支语句示例。3.2条件语句在例3.7中,模块compare用于比较两个2位宽的输入信号com1和com2,并根据比较结果输出三个信号q1、q2和q3。具体功能是,如果com1大于com2,则q1=1,q2=0,q3=0;如果com1小于com2,则q1=0,q2=1,q3=0;如果com1等于com2,则q1=0,q2=0,q3=1。比较器仿真波形如图36所示。3.2条件语句if-else语句可以嵌套使用,但为保证综合性能,避免冗长的路径延迟,不建议使用过长的if嵌套结构。因为if语句对条件的判断是有先后顺序的,所以if语句常用来实现具有优先权的电路,例如优先编码器等。在优先编码器中,当多个输入信号同时有效时,根据if语句的先后顺序,会优先对前面的条件进行判断并输出相应的编码结果。3.2.2
case语句case语句与if-else语句类似,但它是一种多分支选择语句,适合实现平衡条件电路,常用于描述总线、译码器和普通编码器的结构。case语句有case、casez、casex三种表示方式。1.case语句语法格式如下:3.2条件语句if-else语句可以嵌套使用,但为保证综合性能,避免冗长的路径延迟,不建议使用过长的if嵌套结构。因为if语句对条件的判断是有先后顺序的,所以if语句常用来实现具有优先权的电路,例如优先编码器等。在优先编码器中,当多个输入信号同时有效时,根据if语句的先后顺序,会优先对前面的条件进行判断并输出相应的编码结果。3.2.2
case语句case语句与if-else语句类似,但它是一种多分支选择语句,适合实现平衡条件电路,常用于描述总线、译码器和普通编码器的结构。case语句有case、casez、casex三种表示方式。1.case语句语法格式如下:3.2条件语句在case语句中,选择表达式可以是一个变量,也可以是一个表达式。将选择表达式的值与常量表达式的值进行比较,当选择表达式的值与某个常量表达式的值匹配时,执行该常量表达式对应的语句块。default是可选的,当选择表达式的值与所有常量表达式都不匹配时,执行默认语句块。【例3.8】case语句示例。3.2条件语句在例3.8中,select是选择表达式,根据select的值,case语句选择相应的语句块执行,将不同的值赋给result。仿真波形如图37所示。3.2条件语句case语句中,各个常量表达式的值必须是唯一的,否则会导致不可预测的结果。建议使用default分支来处理未预料到的输入情况,避免出现不确定的输出。当case语句的分支较多时,要注意代码的排版和注释,以提高代码的可读性。2.casez语句与casex语句casez语句与casex语句是case语句的两种变体。在case语句中,表达式与选择值之间必须保证对应位全等。但是在casez语句和casex语句中,如果分支表达式某些位的值是z或x,那么这些位的比较就不予考虑,只需关注其他位的比较结果即可。3.2条件语句在casez语句里,z表示该位不参与比较。【例3.9】casez语句示例。3.2条件语句在例3.9中,当value_z的最低位为0时,无论最高位是0、1还是z,都会执行it_is=1'b1这条语句。在casex语句中,x和z都表示该位不参与比较。【例3.10】casex语句示例。3.2条件语句在例3.10中,当value_x的最低位为0时,无论最高位是0、1、x还是z,都会执行it_is=1'b1这条语句。casez语句和casex语句在处理一些不需要精确匹配所有位的情况时非常有用,能够简化代码。不过,这两种语句引入了不参与比较的位,可能会导致综合结果的不确定性,所以在使用时需要谨慎。3.3结构说明语句3.3结构说明语句Verilog包括4种结构说明语句:initial语句、always块语句、task语句、function语句。其中,initial语句通常用于仿真的初始化,仅执行一次;always块语句则不断重复执行;task和function语句可以在程序模块中的一处或多处调用,调用时注意参数的类型要和task及function语句定义中的参数类型保持一致。3.3.1
initial语句在Verilog中,initial语句是一种过程性语句,主要用于初始化变量、生成测试激励信号以及进行仿真控制等操作。initial语句的语法格式如下:3.3结构说明语句【例3.11】initial语句示例。3.3结构说明语句在例3.11的initial语句块内,先将a的初始值设置为十六进制的0,即4'h0,随后利用延时语句配合赋值操作,使得变量a的值随时间按照设定的顺序依次变化,生成一个随时间变化的信号a。需要注意的是,begin-end块内每条语句的延迟是累加的,每条语句执行的时间点是在前一条语句执行时间的基础上加上相应的延迟时间。在实际的电路仿真场景中,不仅需要对变量进行初始化,还需要为设计的模块提供各种符合实际情况的测试激励信号,以此全面检验模块的功能是否正确。比如在测试一个计数器模块时,可以通过initial语句来模拟时钟信号以及复位信号等激励信号的变化情况,进而观察计数器的计数功能是否符合预期。initial块中的语句在仿真开始时只执行一次,执行完毕后不会再次执行。在一个模块中可以有多个initial块,这些initial块是并行执行的,它们的执行顺序不确定,这是由仿真工具的内部机制以及代码的具体布局等因素共同决定的。3.3结构说明语句在initial块中可以使用延时语句来控制语句的执行时间,但延时只在仿真中有效,在综合时会被忽略。initial语句主要用于仿真,一般情况下是不可综合的,这是因为在实际的硬件电路中,电路的运行更多是基于信号的电平变化、时钟边沿触发等物理机制。因此,在进行硬件设计时,如果涉及综合来生成实际硬件电路的代码部分,应当避免使用initial语句进行变量初始化等操作。可以使用always块结合复位信号的方式来实现硬件的初始化,例如通过检测复位信号的上升沿或下降沿,在相应条件下对寄存器等硬件进行复位操作,使其达到初始状态。3.3.2
always块语句always块语句是Verilog中的常用语句,可以用来设计组合逻辑电路和时序逻辑电路。其语法格式如下:3.3结构说明语句其中,always是关键字,用于声明一个always块。@是敏感列表的起始符号。敏感列表指定了always块的触发条件,即当敏感列表中的信号发生变化时,always块内的代码会always块语句被执行。敏感列表的类型分为电平敏感和边沿敏感。1.电平敏感敏感列表中列出的信号是电平信号时,当这些信号的电平发生变化,always块内的代码会立即执行。通常用于描述组合逻辑电路。【例3.12】电平敏感示例。3.3结构说明语句例3.12中定义了两个输入信号a和b,以及一个输出信号c,always块的敏感列表为aorb,表示当a或b的电平发生变化时,c=a&b这条语句会被执行,从而实现了一个简单的与门逻辑。基于这种方式,可以利用电平敏感的always块构建不同复杂程度的组合逻辑电路,比如加法器、多路选择器等,只要将相应的逻辑表达式写在always块内的执行语句部分即可。此外,还有一种简化的写法,即使用∗来表示对块内所有输入信号敏感。可将例3.12中的always@(aorb)修改为always@(∗)。电平敏感示例仿真波形如图38所示。3.3结构说明语句2.边沿敏感敏感列表中使用posedge(上升沿)或negedge(下降沿)关键字来指定信号的边沿触发条件,常用于描述时序逻辑电路,如寄存器、计数器等。【例3.13】边沿敏感示例。3.3结构说明语句例3.13中定义了时钟信号clk、复位信号rst以及4位的计数输出信号count。always块的敏感列表为posedgeclkorposedgerst,表示当clk信号的上升沿到来或者rst信号的高电平到来时,always块内的代码会被执行。如果rst信号为高电平,则将count寄存器清零,使其恢复初始状态4'b0000;而当复位信号无效即rst为低电平时,在每个clk信号的上升沿,count寄存器的值就会加1,实现十六进制计数器功能。边沿敏感示例仿真波形如图39所示。3.3结构说明语句3.3.3
task语句在Verilog中,task语句用于定义可重复使用的代码块。其语法格式如下:3.3结构说明语句任务名需要遵循Verilog标识符的命名规则,用来唯一标识这个任务,方便在模块中对其进行调用。局部变量是在任务内部使用的变量,只在任务执行期间有效。执行语句包含任务的具体操作内容。通过任务名对任务进行调用,调用时需要提供相应的参数,其语法格式如下:3.3结构说明语句【例3.14】task语句示例。3.3结构说明语句例3.14中定义了一个名为my_task的任务,它有两个输入端口a和b,以及一个输出端口c,任务内部通过assign语句将a和b进行与运算,再将值赋值给c。调用这个任务的格式为my_task(in1,in2,out),in1、in2分别对应两个输入参数,out则是任务执行后输出结果的变量。task语句可以将一些重复出现或者逻辑相对独立的代码块封装,使得代码结构更加清晰,易于维护和阅读。比如在大型数字系统设计中,如果经常需要对不同的数据进行相同的复杂运算或处理,则可以将这些操作封装成一个task,然后在需要的地方调用,避免了代码的重复编写,提高了代码的复用性。3.3.4
function语句在Verilog中,function语句用于定义一个可重复使用的代码块,function语句可接收输入参数并返回一个值,常用于执行一些简单的计算或逻辑操作。其语法格式如下:3.3结构说明语句3.3结构说明语句返回值类型明确指定了函数返回值的数据类型,可以是寄存器类型reg、整数类型integer等,如果在定义函数时省略返回值类型,默认返回值类型为1位的reg类型。函数名同样需要遵循Verilog标识符的命名规则,用于在模块中唯一标识这个函数。端口声明列表用于定义函数的输入端口,需要注意的是,函数只能有输入端口,不能有输出端口和双向端口,这是函数与task的一个重要区别,它决定了函数主要是用于进行一些计算并返回结果,而task可以进行更复杂的多方向的数据交互。局部变量声明部分定义的变量只在函数内部使用,在函数执行期间有效。执行语句包含了函数要执行的具体操作,例如算术运算、逻辑运算等,通过这些操作得到一个中间结果,然后通过返回值表达式,即将表达式的值赋给函数名的方式来返回函数的结果。函数通过函数名进行调用,调用时需要提供相应的参数(如果函数有定义输入端口),函数调用可以出现在表达式中,语法格式如下:3.3结构说明语句【例3.15】function语句示例。3.3结构说明语句例3.15中定义了一个名为fun的函数,用于比较两个2位宽的输入信号x和y,并根据比较结果返回一个值。具体逻辑是,如果x>y,则函数fun返回x的按位取反结果;否则,返回y的按位取反结果。模块的输入为a和b,输出为out,其值由函数fun的计算结果决定,通过assignout=fun(a,b);语句实现函数的调用以及结果的赋值。函数是立即执行的,不允许包含延时语句。调用函数时,传递的参数数量、类型和顺序必须与函数定义中的端口声明一致,否则会导致编译错误。函数可以嵌套调用其他函数,嵌套调用时要注意避免出现无限递归的情况,一旦出现无限递归,程序就会陷入死循环,无法正常执行。3.4循环控制语句3.4循环控制语句Verilog提供了多种循环控制语句,用于重复执行特定的代码块,这些语句在生成测试向量、进行数组操作等场景中非常有用。3.4.1
for循环语句for循环语句要放在结构说明语句内部,其语法格式如下:3.4循环控制语句初始化语句在循环开始前执行一次,通常用于初始化循环控制变量。在每次循环开始前对条件表达式进行判断,如果表达式的值为真(非零),则执行循环体;否则,退出循环。步进语句在每次循环体执行完毕后执行,用于更新循环控制变量的值。【例3.16】for循环语句示例。3.4循环控制语句例3.16中使用for循环语句,以移位相加的方式实现4位乘法器的设计。先是将输出结果寄存器r初始化为0,然后通过for循环,以变量i作为循环控制变量,从1开始,每次循环i的值增加1,只要i的值小于等于3,就会进入循环体执行逻辑。在循环体内部判断b[i]的值,如果其为真,就会执行r=r+(a<<i);即将a左移i位后与当前的r值相加,通过多次循环实现4位乘法的功能。4位乘法器仿真波形如图310所示。进行逻辑综合时,for循环的使用存在一定限制。循环次数必须是可确定的常量,这是因为综合工具需要知道循环执行的次数,以便将其转换为硬件电路。3.4循环控制语句3.4.2
while循环语句while循环语句与for循环语句相似,while循环语句的语法格式如下:3.4循环控制语句执行while循环语句时,首先根据“循环控制条件表达式”的计算结果判断是否满足继续循环的条件。如果表达式的值为真,“循环体语句结构”中的所有语句执行一次;一旦该表达式的值为假,即不满足循环表达式的条件时,循环就会立即结束。使用while循环语句时,必须在“循环体语句”中包含类似for语句的“循环控制变量增值表达式”,循环控制变量的值能够随着循环的进行不断变化,使其计算结果可以在条件式中进行比较,以此决定循环是否继续执行。【例3.17】while循环语句示例。3.4循环控制语句3.4循环控制语句3.4循环控制语句在例3.17中,当rst信号为高电平时,会执行复位操作,将count计数器复位为0,即4'b0。当rst信号为低电平时,进入计数相关的逻辑部分。首先定义一个整数变量temp_count,并将其初始化为当前count的值,然后通过while循环模拟计数过程。只要temp_count的值小于max_count,循环就会持续执行,在循环体内部,将temp_count的值加1,当temp_count不再小于max_count时,循环结束,最后把temp_count的值赋给count,实现计数器的功能。作为硬件描述语言的循环语句,每一次循环就要增加一个具有相应功能的硬件模块。因此,循环语句的使用要关注逻辑资源的耗用量和利用率,以及可用资源的多少等因素,尽量使性能和硬件成本成正比。3.4循环控制语句3.4.3
repeat循环语句repeat循环语句的语法格式如下:3.4循环控制语句与for语句不同,repeat语句的循环次数是在进入此语句执行前就已经决定的,无须循环次数控制增量表达式及其计算。语句中的“循环次数”表达式可以是数值确定的整数、变量或定义了常数的参数标识符等。【例3.18】repeat循环语句示例。3.4循环控制语句3.4循环控制语句例3.18中使用repeat循环实现了简单的累加器,将一个4位输入信号累加指定的次数。首先,将输出的累加和寄存器out_sum初始化为0,然后通过repeat循环,循环次数由输入信号repeat_count决定,每一次循环都会执行循环体中的语句out_sum=out_sum+in_data;将当前的输入数据in_data累加到out_sum上。3.4.4
forever循环语句在Verilog中,forever语句通常在仿真中使用,用于生成时钟信号或其他周期性信号,它会持续不断地执行其内部的语句块,直到仿真结束。forever循环语句的语法格式如下:3.4循环控制语句【例3.19】forever循环语句示例。3.4循环控制语句例3.19中定义了一个寄存器类型的变量clk,用于表示时钟信号。在initial块里,首先将clk初始化为0,给时钟信号赋予初始的电平状态。接着,使用forever循环实现时钟信号的周期性变化。通过语句forever#5clk=~clk;每经过5个时间单位(这里的时间单位由前面的timescale指令定义,为1ns),就会对clk的值进行取反操作,让clk的电平从低电平变为高电平或者从高电平变为低电平,如此循环,生成一个周期为10个时间单位的时钟信号。这种方式在仿真中应用较多,可以为数字电路模块进行基于时钟驱动的功能验证提供标准的时钟信号源,确保仿真能够准确地模拟实际硬件电路在时钟作用下的运行情况。3.5生成语句3.5生成语句在Verilog中,生成语句允许在编译时依据特定的条件或参数创建并实例化模块、语句块等内容,提高了代码的复用性和可维护性,使得代码在应对不同的设计需求和场景变化时能够更加高效地进行调整与扩展。通常情况下,generate语句与for循环语句、if语句或case语句配合使用。3.5.1
generate-for语句使用generate语句内的for循环时,索引循环变量应声明为genvar类型。genvar类型的变量主要用于生成语句的编译阶段、控制循环的执行次数以及生成相应的实例等操作,不会在运行时产生变化。3.5生成语句【例3.20】generate-for语句示例。3.5生成语句【例3.20】generate-例3.20中实现了一个将格雷码转换为二进制码的电路功能。首先定义一个genvar类型的变量i作为循环变量,通过generatefor循环来逐位处理格雷码与二进制码之间的逻辑转换。循环从i=0开始,每次递增1,直到i<8,总共循环8次,对应8位的码值转换。在generatefor循环中,begin关键字后面的codeconvert为generate块名,块名在整个设计中具有重要作用。QuartusPrime要求generatefor块必须为命名块,否则在编译时不会成功。通过generate-for语句实现的循环生成结构,在处理类似多位数据的重复操作场景时非常方便,如多位编码转换、数据的并行处理或具有规律结构的逻辑生成等。同时,由于是在编译时就确定了循环的次数和生成的逻辑结构,因此能够更好地被综合工具转化为实际的硬件电路。for语句示例。3.5生成语句3.5.2
generate-if语句generate-if语句为Verilog设计带来了一种条件性实例化的能力,它允许模块、用户定义原语、Verilog门原语、连续赋值、initial初始块和always块等设计元素根据设计时确定的表达式有条件地实例化到另一个模块中。需要强调的是,条件表达式的值必须是一个确定的常数,确保生成语句在编译阶段能够准确进行逻辑判断和实例化操作。【例3.21】generate-if语句示例。3.5生成语句例3.21中定义了输入信号a1和a2,输出信号y,以及一个参数w,其默认值被设置为1。通过generate语句结合if条件判断,依据参数w的值来决定具体实例化的逻辑。当w的值为真,即其值等于1时,将实例化assigny=a1&a2这条连续赋值语句,实现与门逻辑;当w的值为假即0时,则实例化assigny=a1a2语句,实现或门逻辑。generate-if语句的应用场景广泛,比如在设计可配置的电路模块时,可根据不同的配置参数,选择实例化不同的逻辑功能模块或者实现不同的逻辑运算方式,使一个模块能够不同的需求下表现出相应的功能,提高代码的复用性和模块的通用性。由于是在编译时基于确定的常数条件进行判断和实例化,因此综合工具能够准确地生成对应的硬件电路结构,避免了运行时动态变化带来的不确定性和复杂性。3.5生成语句3.5.3
generate-case语句generate-case语句允许模块、用户定义原语、Verilog门原语、连续赋值、initial初始块和always块根据设计时确定的case选择值实例化到另一个模块中。与generate-if语句类似,case选择值必须是一个确定的常数,以此保证编译过程中生成语句能够按照预期进行逻辑构建和实例化操作。【例3.22】generate-case语句示例。3.5生成语句3.5.3
generate-case语句generate-case语句允许模块、用户定义原语、Verilog门原语、连续赋值、initial初始块和always块根据设计时确定的case选择值实例化到另一个模块中。与generate-if语句类似,case选择值必须是一个确定的常数,以此保证编译过程中生成语句能够按照预期进行逻辑构建和实例化操作。【例3.22】generate-case语句示例。3.5生成语句例3.22中同样定义了输入信号a1、a2和输出信号y,以及参数w。通过generate语句与case语句的结合,根据参数w的不同取值来决定具体实例化的逻辑。当w的值为0时,会实例化assigny=a1&a2语句,实现与门逻辑;当w的值为1时,实例化assigny=a1a2语句,实现或门逻辑;而default分支在这里只是一个占位符,当w出现其他未定义的取值情况时,不会进行额外的实例化操作。在实际应用中可以根据具体需求在default分支添加相应的处理逻辑,比如给出提示信息或者进行默认的逻辑设定等。generate-case语句在处理具有多个明确分支条件的可配置电路设计场景中非常实用。例如,在设计一个多功能的数据处理模块时,可以根据不同的配置参数值,通过generatecase语句来实例化不同的数据处理逻辑,如不同的运算方式、不同的数据流向控制等,使得模块能够根据具体的应用场景灵活切换功能,而且代码结构清晰,易于理解和维护。同时,在编译过程中,综合工具能够基于确定的case选择值生成对应的硬件电路,确保硬件实现与设计意图相符,提高了整个设计的可靠性和可扩展性。3.6语句的顺序执行与并行执行3.6语句的顺序执行与并行执行在Verilog中,语句的执行方式分为顺序执行和并行执行两种,语句执行方式影响电路的设计结果。3.6.1顺序执行顺序执行语句按照代码书写的顺序依次执行,这种执行方式在Verilog中主要用于描述电路中的时序逻辑或者算法流程。顺序执行语句通常出现在initial块和always块中。initial块常用于在仿真开始阶段进行一些初始化操作,例如对变量赋初始值、生成特定的初始测试激励信号等,它内部的语句按照书写顺序依次执行一次,执行完毕便不再重复执行。always块可以根据敏感信号的变化来触发执行,进而实现各种不同的逻辑功能。always块内部阻塞赋值语句是顺序执行的,在敏感信号触发时,例如在时钟信号的上升沿或者其他设定的电平变化触发条件满足时,语句按照书写的顺序执行,每一条阻塞赋值语句必须等待前一条语句执行完成后才会开始执行。示例代码如下。3.6语句的顺序执行与并行执行3.6语句的顺序执行与并行执行在这个例子中,当clk信号的上升沿到来时,首先执行b=a这条赋值语句,将a的值赋给b,只有当这条语句执行完毕后,才会接着执行c=b语句,把更新后的b值赋给c。这种顺序执行的特性使得它非常适合用于描述需要按照特定顺序进行数据处理或者逻辑运算的场景。比如在一些具有先后顺序依赖关系的算法实现或者状态机的状态转移过程中,通过阻塞赋值的顺序执行可以准确地控制每一步操作。例3.23描述了一个时序逻辑电路,时钟clk上升沿触发,将输入d赋值给q0,d取反赋值给q1。【例3.23】顺序执行示例。3.6语句的顺序执行与并行执行在例3.23中,时钟clk上升沿触发后,按照顺序先执行q0=d,将输入d的值赋给q0,接着执行q1=~d,将d取反后的值赋给q1。例3.23的仿真波形如图311所示,综合电路如图312所示。从电路中可以看出,这段代码描述了两个并列输出的触发器,两个触发器之间没有移位寄存的关系,只是在时钟上升沿触发时按照顺序更新各自的值,体现了顺序执行在时序逻辑电路设计中的具体表现形式和最终实现的电路结构特点。3.6语句的顺序执行与并行执行3.6语句的顺序执行与并行执行3.6.2并行执行并行执行语句不按照代码书写的顺序执行,而是同时执行。在Verilog中,非阻塞赋值语句、连续赋值语句以及多个always块之间是并行执行的,常用于描述组合逻辑电路。在同一个always块内,非阻塞赋值语句之间是并行执行的,如例3.24所示。【例3.24】并行执行示例1。3.6语句的顺序执行与并行执行在例3.24中,当clk信号上升沿触发时,q0<=d和q1<=q0两条非阻塞赋值语句会同时启动,各自依据时钟边沿触发时刻之前相关信号的值进行操作。在时钟周期末尾同步更新时,q0会跟随d改变,而q1则会跟随时钟边沿触发前的q0值改变,与前一条语句中更新后的q0值不同,因此形成了d→q0→q1的信号传递关系。其仿真波形如图313所示,综合电路如图314所示。3.6语句的顺序执行与并行执行这种并行执行的非阻塞赋值方式在描述一些具有数据传递和存储顺序要求的时序逻辑电路时,能够准确地控制信号在不同寄存器之间的传递顺序和时间点。连续赋值语句也是并行执行的,如例3.25所示。【例3.25】并行执行示例2。3.6语句的顺序执行与并行执行在例3.25中,两个assign语句是并行执行的。无论代码中这两条语句的书写顺序如何,当a或b的值发生变化时,c和d都会根据对应的逻辑运算同时更新自己的值。并行更新的特性使得连续赋值语句适合用于描述组合逻辑电路,能够快速地根据输入信号的变化,实时输出结果。比如实现各种逻辑门的组合功能,或者构建一些简单的布尔逻辑表达式对应的电路结构。多个always块之间也是并行执行的,每个always块根据自己的触发条件独立执行。【例3.26】并行执行示例3。3.6语句的顺序执行与并行执行在例3.26中,第一个always块在时钟上升沿触发,只要时钟clk的上升沿到来,便执行内部的counter1<=counter1+1语句,对counter1进行加1操作;第二个always块也在时钟上升沿触发,当clk的上升沿出现时,便执行counter2<=counter2-1语句,使counter2的值减1。这两个always块并行执行,按照自己的触发条件和逻辑进行操作,互不影响,共同实现了一个具有不同时钟沿触发更新功能的计数器结构,可以方便地实现多个不同时序逻辑功能的集成与协同工作。例3.26的仿真波形如图315所示,综合电路如图316所示。3.7元件例化语句3.7元件例化语句元件例化是Verilog中实现层次化设计的基础。通过将复杂的系统分解为多个小模块,然后在更高层次的模块中实例化小模块,可以提高设计的可维护性和可重用性。Verilog中有两种元件例化的关联方式:位置关联和名称关联。3.7.1位置关联位置关联是一种较为直观但要求相对严格的元件例化关联方式,它需要按照被实例化模块端口定义的顺序依次列出连接的信号。其语法格式如下:3.7元件例化语句含了输入端口、输出端口以及内部实现的逻辑功能。进行元件例化时,需要指出要实例化的是哪个模块。instance_name为实例化后的模块实例名,其作用是在当前模块中唯一标识该实例。由于在一个复杂的高层次模块中可能会多次实例化同一个基础模块,因此为了区分不同的实例,需要给每个实例赋予一个独一无二的名称,方便在后续的代码编写、调试以及综合等过程中对其进行引用和操作。signal1,signal2,…,signalN是与被实例化模块端口连接的信号列表,信号的顺序必须与被实例化模块端口定义的顺序一致。如果被实例化模块的端口定义顺序是先输入端口a,再输入端口b,接着输出端口sum,最后输出端口co,那么在进行位置关联实例化时,连接信号也必须按照对应的顺序依次排列,不能随意调换位置。这种严格的顺序要求虽然在一定程度上增加了代码编写时的难度,但在一些简单且逻辑清晰的设计场景中,能够清晰地体现模块之间的连接关系,只要遵循端口顺序,就能快速完成元件例化操作。对于简单的数字电路设计,如果有一个已经定义好的基本模块basic,其端口定义顺序为输入端口in1、in2,输出端口out1、out2,若要在高层次模块中通过位置关联对其进行实例化,则代码如下:3.7元件例化语句假设signal_a和signal_b是与in1、in2对应的输入信号,signal_c和signal_d是与out1、out2对应的输出信号,它们的顺序必须与basic_module端口定义顺序相匹配,以此完成元件例化,实现basic_module在高层次模块中的功能嵌入。3.7.2名称关联名称关联是通过指定被实例化模块端口的名称进行连接,这种方式最大的优点就是不要求信号的顺序与被实例化模块端口定义的顺序一致,在面对端口较多或者复杂的模块连接情况时,能够更加清晰、准确地描述模块之间的连接关系,避免因顺序问题而出现的错误。其语法格式如下:3.7元件例化语句module_name和instance_name的含义与位置关联方式中的相同,分别代表被实例化的模块名以及实例化后的模块实例名,用于明确要实例化的具体模块以及在当前模块中对实例进行唯一标识。.port_name1(signal1),…,.port_nameN(signalN)是每个端口名和与之连接的信号,用点号连接,并用逗号分隔,表明了每个端口具体连接的是哪个信号,即使信号的排列顺序与被实例化模块端口定义顺序不同,也能建立连接关系。对于一个具有多个输入/输出端口的复杂模块complex,其端口包括input_1、input_2、output_1、output_2等,若要通过名称关联进行实例化,可以写成如下形式:3.7元件例化语句在这个例子中,虽然信号的顺序与complex原本的端口定义顺序不一致,但通过明确指定端口名称和对应的连接信号,也能够实现元件例化,将signal_x连接到input_1,signal_y连接到output_2,以此类推。此连接方式方便开发者阅读和理解代码逻辑,同时降低了因端口顺序混淆而导致连接错误的风险。下面通过一个全加器设计案例进一步说明元件例化语句的实际应用。全加器是数字电路中常用的基本运算单元,在加法运算中起关键作用。图317所示为全加器的电路图,由3个逻辑模块组成,包含两个半加器和一个或门。3.7元件例化语句表31所列为半加器真值,可根据此表进行1位半加器电路模块的Verilog描述,如例3.27所示。3.7元件例化语句【例3.27】1位半加器电路模块的Verilog描述。3.7元件例化语句根据全加器的
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026人工智能产业知识产权保护政策体系构建与技术创新壁垒突破及营商环境优化分析报告
- 2026中国洗衣粉行业商业销售数据建模与市场预测
- 2026中国智能家居系统市场竞争技术迭代评估规划研究报告
- 2026秋新北师大版数学四年级上册教学课件:第4单元 我们生活的空间(二)(全单元合并)
- 2026中国肿瘤消融设备联合免疫治疗协同效应与临床路径报告
- 2026中国智能水处理行业市场供需分析及投资评估规划分析研究报告
- 2026汽车制造业竞争格局分析及技术革新与产能扩张论文
- 2026中国无人驾驶汽车商业化路径与政策环境分析报告
- 2026中国新材料技术研发行业市场深度调研及发展趋势与投资前景研究报告
- 2026中国手术导航系统学术推广效果评估与标杆医院合作模式报告
- 2026中国网络游戏玩家群体分析市场现状供需关系研究报告
- 2026新教材语文 21 第一场雪 教学课件
- 人工智能概论 课件全套 廉师友 第1-11章 人工智能的概念、内容和方法-人工智能编程语言与开发平台
- DB32T 4357-2022 建筑工程施工机械安装质量检验规程(修)
- 建筑施工安全保函
- DZ∕T 0339-2020 矿床工业指标论证技术要求(正式版)
- 普通螺栓理论重量表
- 高压配电室安全管理制度
- 2017版银皮书(中英文完整版)FIDIC设计采购施工交钥匙项目合同条件
- 发展经济学 马工程课件 2.第二章 发展的概念与度量
- 交互设计1课件
评论
0/150
提交评论