1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
| 条件操作符是从右向左处理,其他都是从左至有处理 a?b:c?d:f == > a?b:(c?d:f)
算术操作符(其余操作与C语言类似,除去幂运算) +(一元加和二元加) -(一元减和二元减) *(乘) /(除) %(取模) **(幂运算)
整数除法截断任何小数部分,例如:7/4的运算结果为1
**是求幂运算符:a**b表示a的b次方,即a表示底数,b表示指数; %是取模运算符:a % b 按照a 和 b中的长度长的补齐。 除法只能取整数;
算数操作符中任意操作数中只要有一位为x 或 z ,则整个结果为x 。例如:4’b10x1+5'b01111 结果为不确定数 5'bxxxxx
算术运算结果的位宽 算术运算结果的位宽由最大操作数的位宽决定。赋值语句下,算术运算结果的位宽也由赋值等号左边目标变量的位宽决定 reg [0B:3] mask_intr,test_ctrl,raw_intr; //位宽为四,0B的代表,二进制标识,0位 reg [0:5] int_req;
mask_intr = test_ctrl+raw_intr; //结果位宽由 mask_intr test_ctrl raw_intr 位宽决定 ,加法操作的溢出部分被丢弃 int_req = test_ctrl+raw_intr; //结果位宽由 int_req test_ctrl raw_intr 位宽决定,位宽为6,任何一处的位将被存储在结果位int_req[5]中
较大表达式中,运算中间结果的位宽确定的规则:表达中的所有中间结果应取最大操作数的位宽(在赋值时,此规则也包括赋值等号左端的目标变量) wire [4:1]intra_ena,test_reg; wire [1:5]next_iev; wire [1:6]peg_intr; wire [1:8]adt_sense;
assign adt_sense = (intra_ena+next_iev)+(test_reg + peg_intr); //赋值等号右边表达式最大位宽6 ,包含左边时。最大变量位宽8.所以加法运算使用8位进行
有符号和无符号数 执行算术和赋值时,哪些操作当无符号操作,哪些操作当有符号操作非常重要
无符号数值存储:线网中、reg(寄存器)变量中、用普通(没有有符号标记s)的基数格式表示的整型中
有符号数值存储:用s(有符号)标记的基数格式表示的整型中、十进制形式的整数中、有符号的reg变量中、有符号线网中
reg[0:5]burst_data; integer mtx_addr;
burst_data = -4'd12; //reg变量burst_data的十进制数为52 既向量 110100 (有符号赋值到无符号) mtx_addr = -4'd12; //整型数mtx_addr的十进制数为-12,二进制表示110100 (有符号赋值到有符号) -4'd12/4 //结果是1073741821 (-4'd12转换成32位数,以无符号显示 取最大的位宽进行运算) -12/4 //结果为 -3 都是有符号数据
burst_data 是无符号寄存器,右边表达式值为 6’d110100(-12二进制补码),因此赋值后,burst_data存储的是十进制52。
关系运算符 (> < >= <=) 若操作数中有一位为x或z,则结果为x 52<16'hxFF //结果为x,
操作数位宽不同,所有操作数都是无符号 ,则位宽较小的操作数高位补0对齐 'b1000 >= 'b01100 ==》 'b01000 >= 'b01100 若两个操作数都是有符号数,则用符号位将位数较小的操作数的位数补齐 4'sb1011 <=8'sh1A ==> 8'sb11111011 <= 8'sb00011010 结果为真 若表达式中一个操作数是无符号,则该表达式的其余操作数均被当作无符号数处理 (8'sb9*4'd2) < 4 ==> 假(18 < 4) (4'sd9*2)<4 ==> 真(-14<4)
相等操作符号(结果假为0 结果真为1) ==(逻辑相等) !=(逻辑不等) ===(全等,case equality) !===(非全等,) 全等比较中,把x和z当作数值(而不考虑其物理含义)严格地按字符值进行比较,结果不是1就是0 ,不会出现其他地值。 逻辑比较中,值x和z具有物理含义(物理含义:有大小区别),结果可能出现不确定值(==)参与比较的两个操作数必须逐位相对,其结果才为1,如果某些值是不定态X或高阻态Z,那么得到的结果是不定值X; 例: sw_data = 'b11x0; //没有指定位数,默认32位数据比较 sw_addr = 'b11x0; sw_data == sw_addr; //结果为x,按照规定, sw_data === sw_addr; //结果为1,按照规定,
'b010x != 'b11x0 上式中的两个操作数中都有x,但比较结果为真,是因为第一位不同 若操作数的位宽不相等,位宽较小的操作数在左侧以0补齐,例: 2’b10 == 4'b0010 ==> 4'b0010 == 4'b0010 ==>结果为真
若操作数位宽不同,两个操作数都是有符号数,较小的操作数用符号位扩位补齐,例 `define WIDTH 8 wire [WIDTH:0] mux_bus,byte_a,byte_b,byte_c,byte_d; wire [1:0] select;
reg [4:0] a = 5'b11x01; reg [4:0] b = 5'b11x01; a == b 返回的结果是X; a===b 的返回结果为 1 (!=)和(!==)的用法类似;
归约运算符:归约与(&) 归约与非(~&) 归约或(|) 归约或非(~|) 归约异或(~^) 注意:归约运算符的操作数只有一个,并只产生一位结果:举例a=0101,则&a=0(a中的所有位进行与操作); |a=1(a中的所有位进行或操作);
逻辑操作符 (逻辑与 或 非) && || ! 对逻辑值0或1进行操作,逻辑操作产生的结果为0或1 mlock = 'b0 mport = 'b1 mlock && mport ==>结果为0(假) mlock || mport ==>结果为1(真) !mport ==>结果为0(假)
对向量操作数而言,非0向量被当作1处理 rdy_bus = 'b0110; intr_bus = 'b0100;
rdy_bus || intr_bus 的结果为1 rdy_bus && intr_bus 的结果为1 并且!rdy_bus !intr_bus的结果相同,均为0
操作数内某一位为x 或 z,若逻辑操作的结果是未定的,则运算的结果为x 1'b1& 1'bx 结果 x 'b1 || 'bx 结果1 'b0 && 'bZ 结果0 !x 的结果x
按位操作符 (5种) ~ (一元非) & (二元与) | (二元或) ^ (二元异或) ~^,^~ (二元同或) 这些操作符对输入的操作数进行逐位操作,逐位操作就对应位进行操作,产生一个向量的结果 与 逐位操作结果 或 逐位操作结果 ------------------- --------------------- & | 0 | 1 | x | z | | | | 0 | 1 | x | z | 0 | 0 | 0 | 0 | 0 | | 0 | 0 | 1 | x | x | 1 | 0 | 1 | x | x | | 1 | 1 | 1 | 1 | 1 | x | 0 | x | x | x | | x | x | 1 | x | x | z | 0 | x | x | x | | z | x | 1 | x | x | ------------------- ---------------------
异或 逐位操作结果 同或 逐位操作结果 ------------------- --------------------- ^ | 0 | 1 | x | z | | ^~| 0 | 1 | x | z | 0 | 0 | 1 | x | x | | 0 | 1 | 0 | x | x | 1 | 1 | 0 | x | x | | 1 | 0 | 1 | x | x | x | x | x | x | x | | x | x | x | x | x | z | x | x | x | x | | z | x | x | x | x | ------------------- ---------------------
取反逐位操作结果 ------------------ ~| 0 | 1 | x | z | | 1 | 0 | x | x | ------------------
按位运算中,两个操作数的位宽不等,且其中一个操作数是无符号操作数,则位宽较小的操作数高位补0对齐;(最终奥义就是不改变值的大小) 若两个操作数为有符号数,则位宽小的操作数用符号位在高位进行补齐,然后再操作 'b0110^'b10000 ==> 'b00110^'b10000 =>'b10110
4'sb1010 & 8'sb 01100010 ==> 8'b11111010 & 8'b01100010 => 8'b01100010
缩减操作符(对单个操作数进行操作) 对单一操作数上的所有位进行操作,产生1位的操作结果,缩减操作符有6种。 1)&(缩减与)操作数只要有任意一位的值为0,则结果为0,操作数中只要有任意一位为x或z,则结果为x;否则操作结果为0;
2)~&(缩减与非) 缩减与操作结果取反
3)|(缩减或)操作数中只要有任意一位的值为1,则该操作的结果便为1,操作数中只要有任意一位为x或z,则结果为x;否则操作结果为1;
4)~|(缩减或非)缩减或操作结果取反 5)^(缩减异或) 操作数中只要有任意一位为x或z,则结果为x; 若操作数中有偶数个1,则结果为0 ,否则结果为1
6)~^(缩减同或)缩减异或操作结果取反
a= 'b0110; b ='b0100;
|b //结果1 &b //结果0 ~^a //结果1
缩减异或操作符可以用来确定向量中是否存在值x得位 addr_port = 4'b01x0; //对addr_port异或结果为x 对上述功能,可以使用如下的if语句进行检查; if(addr_port === 1'bx) begin
end
移位操作符 << (逻辑左移) >> (逻辑右移) <<< (算术左移) >>> (算术右移) 移位操作符右侧操作数是一个无符号数,若右侧操作数值为x或z,则移位操作结果为x。 逻辑移位,移动的位置总是填0;算术移位,左移空出位置填0,右移位,若操作数为无符号数,空出来位填0,若操作数为有符号数,则空出来的位总是填写符号位。
reg[7:0] qreg = 8'h17; //0001 0111 reg signed [3:0] pmaster = 4'b1011;
qreg >> 2 结果为 0000 0101 qreg << 2 结果01011100 qreg <<<4 结果 0111 0000 qreg <<-2 //因为右操作数总是一个无符号数,因此向左移位了2**31-2 2的31次方数-2
qreg >> 4 结果 0000 0001 qreg >>>2 结果 0000 0101 pmaster >>>2 结果 1110
移位操作符可以用来完成指数(幂运算); 例如,若计算2的 num_bits 幂, 32'b1<< num_bits //num_bits必须小于32 //指数(幂)操作符也可以用 2** num_bits
也可以用移位操作符为2-4译码器建立verilog模型 wire [3:0]decode_out = 4'b1 << address[1:0]; address分别可取值 0 1 2 3 decode_out对应值 4'd0001 4'd0010 4'd0100 4'd1000
算术右移是有符号的除2运算,分数部分被移位到下一个最低位的整型中。 qreg>>>2 //运算结果5(23/4) pmaster>>>2 //结果是-2(-5/2)
算术移位操作符场合,存在一种特殊情况,操作数是有符号,移位却是0, 这是一个操作符有符号,一个无符号,按无符号数处理 reg signed [3:0]xfer_port; 3'd4+xfer_port>>>1 //因为xfer_port当作无符号处理,所以移位空出位补0
条件操作符 cond_expr?expr1:expr2; 和C语言类似,不同处若cond_expr为x或z,则操作结果按以下逻辑执行 expr1与expr2按位操作;0与0得到结果0,1与1得到结果1,其余情况下的结果为x; 例: wire [2:0] student = (marks>18)?grade_a:grade_c; 计算(marks>18) 为真则赋值grade_a ,若 marks <= 18 则赋值grade_c
拼接和复制操作符 拼接(concatenation)是将小表达式中的位拼接起来形成一个由多个位组成的大表达式的操作,语法: {expr1,expr2,...,exprn} 例: wire [7:0]dbus; wire [11:0]abus;
assign dbus[7:4] = {dbus[0],dbus[1],dbus[2],dbus[3]}; //dbus的第四位值以颠倒的顺序,赋值给其高四位 assign abus[7:0] = {dbus[3:0],dbus[7:4]};//dbus的高4位与低4位交换后赋值给abus[7:0]
未指定位宽的常数其位数是未知的,拼接不允许出现未指定位宽的常数。 {dbus,5} //不允许在拼接操作中出现5,这样未指定位宽的常数 拼接是非法的。
abus = {3{4'b1011}}; //位向量12‘b101110111011 就是3个4位数拼接 abus = {{4{dbus[7]}},dbus} /*符号扩展*/
{3{1'b1}} //结果为111 {3{ack}} //结果与{ack,ack,ack}等效
重复操作也可以被参数化, parameter LENGTH = 8; {LENGTH{1'b0}} //一个由8个0组成的字符串
拼接操作计算2的幂指数、符号的扩展以及0的扩展 parameter POWER_OF = 4, PAD_BY = 5; wire[7:0]cgr_reg;
wire [31:0] power_of_two = {1'b1,{POWER_OF{1'b0}}}; //二次幂 wire [12:0] sign_extension = {{PAD_BY{cgr_reg[7]}},cgr_reg}; //标志扩展 wire [11:0] zero_extension = {{4{1'b0}},cgr_reg}; //符号扩展
表达式的类型
操作符对操作数进行逐位操作, ()[https://www.runoob.com/w3cnote/verilog-expression.html]
缩减操作符 {% endcodeblock %}
|