引自免费微信小程序:皆我百晓生
在Verilog 2005标准中,整型变量(integer类型)和有符号整型变量(signed类型的reg或wire)在处理时有一些特殊的规则。当将一个整型变量赋值给一个具有不同数据宽度的有符号或无符号整型变量时,会进行位扩展。
对于intA = -4'd12; 这一行语句, -4'd12 是一个带符号的十进制整数常量,其二进制补码表示为 1111111111111101,因为 Verilog 规定负数的表示方式为补码,并且这个常量前面的 -4'd 指定了它是一个长度为4位的整数。
由于 intA 是一个整型变量,它的长度没有指定,因此它会默认为最宽的整型,通常是32位。所以当 -4'd12 被赋值给 intA 时,按照 Verilog 的规定,整型变量的扩展是通过对最高有效位(MSB)进行零填充来进行的,因为 intA 是正数还是负数并不影响扩展方式。因此,-4'd12 在赋值给 intA 后,会被扩展为 00000000000000000000000001111101。
然后,当我们将 intA 的值除以3并赋给 regA 时,regA 是一个16位的无符号整数,所以再次发生位扩展。这里需要注意的是,在Verilog中,除法操作符 / 对于整数来说总是返回一个无符号整数值。由于 intA 是32位的,我们将其转换到16位时,会遵循与整型变量相同的扩展策略,即对最高有效位进行零填充。所以 intA 的值会被扩展为 00000000000000000000000001111101,然后再除以3得到 00000000000000000000000000111111,即十六进制的 65532。
如果你想要确保结果为有符号整数,你需要显式地转换 intA 到 regS,这是一个16位的有符号整数,这样在扩展时会保持符号信息:
integer intA;
reg [15: 0] regA;
reg signed [15: 0] regS;
intA = -4'd12;
regA = intA / 3; // expression result is 65532
regS = $signed(intA) / 3; // expression result will be correct as a signed value
在这个版本中,$signed 函数用于将 intA 的值解释为有符号整数,然后进行除法运算。这将正确地保留符号信息,得到正确的表达式结果。注意,这样做可能会导致溢出错误,因为在有符号和无符号之间的转换过程中可能丢失符号信息。在实际设计中,应当谨慎处理这些转换,以防止意外的行为。