Verilog基础:case类语句(case、casex和casez)
相关文章Verilog基础专栏https://blog.csdn.net/weixin_45791458/category_12263729.html一、前言Verilog中的case类语句是多路选择语句用于检查一个表达式的值是否与其他多个表达式的值相等如果相等则进行分支跳转执行相应语句。Verilog中的case类语句就像是C语言中的switch语句一样但case类语句还有以下特性除了case语句还有casez语句和casex语句两个变种。case_expression和case_item可以是变量也可以是常量。既可以实现平行结构(parallel)也可以实现优先级结构(priority)。如果使用时不注意可能会产生锁存器(latch)。仿真器和综合器对x值和z值的理解不同可能造成前/后仿真不一致。full_case和parallel综合指令也可能造成前/后仿真不一致。二、case类语句的定义为了全面理解case类语句的各种特性首先介绍其各个组成部分。case类语句整体在Verilog中case类语句就是所有包含在case head和endcase之间的代码逻辑上等价于if语句如下所示。case(case_expression) case_item1: case_item_statement1; case_item2: case_item_statement2; case_item3: case_item_statement3; case_item4: case_item_statement4; default: case_item_statement5; endcase // 等价于 if (case_expression case_item1) case_item_statement1; else if(case_expression case_item2) case_item_statement2; else if(case_expression case_item3) case_item_statement3; else if(case_expression case_item4) case_item_statement4; else case_item_statement5;case headcase语句头包含case/casex/casez关键字后面跟随着括号内的case expression当向一个case语句使用full_case/parallel_case综合指令时这些指令就加在case语句头的case expression的后面。case expressioncase expression是紧随case关键字并由括号包围的表达式用于和case item进行匹配。case itemcase item用于和case expression进行匹配。不像VHDLVerilog中的case item可以是变量也不像C语言Verilog中的case语句隐含了break语句。在每次case语句检查相等时是从第一个case item开始如果成功会导致对应的case item statement执行并跳出case语句后续的case item不会被检查。case item statementcase item statement是当case item匹配成功时要执行的语句如果需要执行多条语句那么就要使用块语句begin-end或fork jion包围这些语句以提供执行顺序的参考。case defaultcase default是可选的当没有定义的case item匹配成功时就会匹配默认选项。在所有case item最后编写default语句是好习惯即使标准没有强制要求default语句的位置。casezcasez语句是case语句的一个变种特点是z值在匹配时被当做不关心的值如果z值出现在case expression中或case item中时那么就不关心对应的位即不匹配对应的位。?值和z值在是等价的只不过用?值更加清晰一点。注意要小心使用casez且最好使用?值而不是z值。casexcasex语句是case语句的一个变种特点是x值和z值在匹配时被当做不关心的值如果x值和z值出现在case expression中或case item中时那么就不关心对应的位即不匹配对应的位。?值和z值是等价的只不过用?值更加清晰一点。注意最好不要使用casex。三、case类语句的执行case类语句的执行过程如下每次执行case类语句时括号内的case expression只计算一次然后按照从上到下的顺序与每个case item匹配。如果在匹配时遇到了case default则忽略它。如果在匹配时有一个case item与case expression匹配成功那么就执行其对应的case item statement然后终止case类语句。如果所有匹配都失败了并且存在case default那么就执行其对应的case item statement然后终止case类语句否则直接终止case类语句。C语言的switch语句是跳转表即case item都是互斥的然后根据情况跳转到不同的地址去执行对应的表达式而不会一个一个去比较case item。但在Verilog中case item是从上到下依次比较这就赋予了靠前项更高的优先级当然如果每个case item是互斥的那这个优先级无任何影响。四、注意事项在指定case expression和case item时尽量保持位宽一致如果位宽不一致则会把case expression和case item都位宽拓展至其中的最大位宽如果case expression和case item中有一个是无符号数进行补零拓展如果case expression和case item全是有符号数进行符号拓展。对于case语句在进行匹配时每一位都需要精确匹配才算匹配成功从上面等价的if语句中也能看到这一点我们使用的是严格相等而不是普通相等。case语句提供提供一种检测出x值和z值的方法与此等价的if语句需要使用才能检测出x值和z值而casez语句和casex语句这两个变种则提供了比较时不关心x值和z值的机制。如果在case语句的case expression和case item中出现了x值或z值则综合时会忽略相关分支。case语句、casex语句、casez语句都是部分可综合的部分可综合指的是某些特性可能不被支持如在case语句中使用x值或z值。五、case语句的应用例1下面的代码可以检测x值和z值。case(sig) 1bz: $display(signal is floating); 1bx: display(signal is unknown); default: $display(signal is %b,sig); endcase例2下面的代码综合时会忽略case item中存在x值和z值的相关分支。case(select) 2b00: result 0; 2b01: result flaga; 2b0x,2b0z: result flaga ? 1bx : 1b0; 2b10: result flagb; 2bx0,2bz0: result flagb ? 1bx : 1b0; default: result 1bx; endcase例3下面的代码是优先级编码器使用了反向case语句。case(1b1) encode[2] : $displsy(Select Line 2); encode[1] : $displsy(Select Line 1); encode[0] : $displsy(Select Line 0); default : $display(Error : one of the bits expected); endcasecase语句可以是full和parallelfull代表case item覆盖了所有可能取值不包括x值和z值不会生成锁存器如果存在case default则视为覆盖了所有可能取值parallel代表case item是互斥的不会生成优先级结构。综合工具一般可以自行推导出是否是full或parallel。例4下面的代码是full和parallel的综合结果即不会生成锁存器也不会生成优先级结构。case(sel) 2b00: y a; 2b01: y b; 2b10: y c; 2b11: y d; endcase例5下面的代码使用if语句表面上看会形成优先结构但实际上综合工具能推断出这些选项是互斥的继而综合出并行结构。if(sel 2b00) y a; else if(sel 2b01) y b; else if(sel 2b10) y c; else (sel 2b11) y d;例4与例5的综合结果是一样的如下图所示。例6下面的代码虽然没有case default但不会生成锁存器因为case语句前面对变量赋了初值它看起来比较啰嗦难以维护容易出错。iprdata32b0; case({rbr_en,dll_en,dlh_en,ier_en,iir_en,lcr_en,mcr_en,lsr_en,msr_en,scr_en}) 10h10_0000_0000: iprdata[LEGACY_RW-1 : 0] rbr[LEGACY_RW-1 : 0]; 10h01_0000_0000: iprdata[LEGACY_RW-1 : 0] dll[LEGACY_RW-1 : 0]; 10h00_1000_0000: iprdata[LEGACY_RW-1 : 0] dlh[LEGACY_RW-1 : 0]; 10h00_0100_0000: iprdata[LEGACY_RW-1 : 0] ier[LEGACY_RW-1 : 0]; 10h00_0010_0000: iprdata[LEGACY_RW-1 : 0] iir[LEGACY_RW-1 : 0]; 10h00_0001_0000: iprdata[LEGACY_RW-1 : 0] lcr[LEGACY_RW-1 : 0]; 10h00_0000_1000: iprdata[LEGACY_RW-1 : 0] mcr[MCR_RW-1 : 0]; 10h00_0000_0100: iprdata[LEGACY_RW-1 : 0] lsr[LEGACY_RW-1 : 0]; 10h00_0000_0010: iprdata[LEGACY_RW-1 : 0] msr[LEGACY_RW-1 : 0]; 10h00_0000_0001: iprdata[LEGACY_RW-1 : 0] scr[LEGACY_RW-1 : 0]; endcase例7下面的代码使用了反向case语句看起来更简洁也更好维护。因为在信号定义中限制了同一时间最多只有一个*_en信号有效综合时会考虑这个限制从而综合出无优先级结构即case语句的综合和信号来源的限制是有关系的但如果对信号来源无限制则依旧会综合出优先级结构且rbr_en信号优先级最高。iprdata32b0; case(1b1) rbr_en: iprdata[LEGACY_RW-1 : 0] rbr[LEGACY_RW-1 : 0]; dll_en: iprdata[LEGACY_RW-1 : 0] dll[LEGACY_RW-1 : 0]; dlh_en: iprdata[LEGACY_RW-1 : 0] dlh[LEGACY_RW-1 : 0]; ier_en: iprdata[LEGACY_RW-1 : 0] ier[LEGACY_RW-1 : 0]; iir_en: iprdata[LEGACY_RW-1 : 0] iir[LEGACY_RW-1 : 0]; lcr_en: iprdata[LEGACY_RW-1 : 0] lcr[LEGACY_RW-1 : 0]; mcr_en: iprdata[LEGACY_RW-1 : 0] mcr[MCR_RW-1 : 0]; lsr_en: iprdata[LEGACY_RW-1 : 0] lsr[LEGACY_RW-1 : 0]; msr_en: iprdata[LEGACY_RW-1 : 0] msr[LEGACY_RW-1 : 0]; scr_en: iprdata[LEGACY_RW-1 : 0] scr[LEGACY_RW-1 : 0]; endcase