第三章、Verilog高级语法及用法
casex和casez语句 锁存器的生成和利用 Verilog HDL 内置元件的例化
用户自定义的module例化 例化中的参数传递 Generate语句 向量的部分选择
casex和casez语句
在上一章中,使用了case语句描述了一个4为输入的二进制数用相应的数字显示到7段数码管上的实例。在这个实例中,仔细考虑din输入情况。如果在din的四个位中出现了高阻态z或者是不定态x的情况,case语句如何执行呢?
从语法角度上讲,case语句在进行敏感表达式和分支值进行比较的时候,每个比较的位都具有4种情况,即:0、1、x、z 四个不同的值,所以如果有分支选项对应的某个位只要不同,该分支就不会执行。而实际上,从物理意义上讲,高阻态相当于从电路中“断开”,所以这样的位实际过程中是不对电路的执行有影响的,作为分支选项应该考虑这种情况;另外,x不定态是我们研究电路的时候不关心的,或者说这个位应该是0或1、或者是Z的其中任何一个,通常在研究过程中这个位对对运算的结果没有影响。例如:假设din是4位,只要din的最高位为1,低3位不管为什么都执行某一条语句的情况。所以,verilog又设计了casez和casex语句来解决这两类现象。
casez和casex的语法格式和case完全一样,只是将case关键字换成了casez或casex。
casez(敏感信号表达式)
值1: 语句1;//case分支 值2: 语句2; ……
值n: 语句n;
default:语句n+1; endcase
在casez语句中,如果敏感信号表达式和分支表达式某些位的值(考虑对应二进制的情况下)为高阻态(即z或Z),那么对这些位的比较就会忽略,不予考虑,而只关注其他位的比较结果。 例:
casez(sel)
2'b00:out=2'b01; 2'b1?:out=2'b10; 2'b01:out=2'b11; endcase
这里“?”是高阻态z的另一种表示形式,它只出现在case语句的分支选项中!有一种错
casex(敏感信号表达式)
值1: 语句1;//case分支 值2: 语句2; ……
值n: 语句n;
default:语句n+1; endcase
误的理解方式认为它是不关心态,要注意!即,它只表示z,不表示x。
若sel的电平值为2’b11或者2’b1z或者2’b10或者2’b1x时,系统会输出out=2’b10。注:此casez语句在Quartus II中仿真结果不一定对,请使用专业的Verilog HDL仿真工具如modelsim去验证该语句的正确性。
在casex语句中,如果敏感信号表达式和分支表达式某些位的值(考虑对应二进制的情况下)为高阻态或不定态(即z或x),则在进行敏感信号表达式和分支值比较时,这些位不参与比较(也就是忽略该位),而只关注其他位的比较结果。 例:
casex(sel)
2'b1x:out=2'b01; ……
endcase
当sel端的值为2’b10或者2’b11或者2’b1z或者2’b1x均有out=2'b01;语句成立。
大多数情况下,一般使用casez语句,case语句用的也较少,强烈不推荐使用casex语句。不过需要说明的是,这三个case语句都是可综合的,都能生成RTL电路。引自《ANALYSIS OF CASE STATEMENTS》一文。
casez语句的另一种应用------并行case语句。通过实例来说明。 代码如下: module parallel_case (sel, a, b, c); input [2:0] sel; output a, b, c; reg a, b, c;
always @(sel) begin
{a, b, c} = 3'b0;
casez (sel) 3'b1??: a = 1'b1; 3'b?1?: b = 1'b1; 3'b??1: c = 1'b1; endcase end
endmodule
在这个代码中,如果sel端恰巧是3’b111的情况,那么,a、b和c输出值应该是多少呢?从代码上看,如果sel的高位为高电平的话,a就输出高电平,否则保持初始化值0;同理,当sel的中间位为1的话,b输出1,否则输出初始化值0;当sel的最低位为1的话,c输出1,否则输出0。在接下来的波形仿真验证之前,请准备好自己的答案。先看一下RTL电路:
Decoder0b~0sel[2..0]IN[2..0]OUT[7..0]bDECODERWideOr0ac 仿真结果,
从仿真图上我们看出,实际上的输出结果为a高电平,b和c均为低电平。 从语句本身上看,代码的作者想用sel中的每一个位分别控制a、b和c中的各个引脚的输出电平。而实际上只有第一条语句执行了,因为初始化时候a、b、c均为低,而执行后只有第一条语句运行了,很显然,sel为111的时候第一条分支语句满足了,于是第一条语句执行,然后case语句就退出了!它相当于c语言中的每条分支语句后面的break的作用!换句话说,这里的case语句是有优先级的,当第一条分支语句执行后,case语句跳出,后面的语句都不执行了。
如果说不想让case语句具有优先级,可以在case语句的后面加上综合属性,当Quartus II综合的时候会根据综合属性改变其综合后的结果。//synthesis parallel_case 是并行综合属性,它以注释的形式出现在case语句后面,它可以使case语句综合后不在具有优先级,用法见下面代码:
module parallel_case (sel, a, b, c); input [2:0] sel; output a, b, c; reg a, b, c;
always @(sel) begin
{a, b, c} = 3'b0;
casez (sel) //synthesis parallel_case 3'b1??: a = 1'b1; 3'b?1?: b = 1'b1; 3'b??1: c = 1'b1; endcase end
endmodule
再次综合,看RTL电路图:
sel[2..0]abc 这和刚才的RTL视图完全不同,可以看出sel的三个输入分别接到了abc三个输出端上。仿真图如下:
当sel为111时候,abc也都输出了高电平。为其他值时,对应的a、b、c端口也随之变化。
另一个综合属性------full case语句
在case语句(含casez和casex)中,通常使用default选项来对分支选项中没有列举到的敏感信号表达式的值做统一的处理,从功能上看,如果不需要处理的分支值一般来说是我们不需要的功能,可以不写,但对于综合器来说,如果分支选项不全的话,对FPGA/CPLD硬件的资源的使用甚至是性能的使用是有影响的。
以下下通过实例演示说明default选项的作用: