区别:按位运算符进行逐位的逻辑运算(如:与或非),输出与输入位数一致;
逻辑运算符进行逻辑运算,不关注输入的某一位而是将输入作为整体进行逻辑操作,输出位数为1;
列举:
与:& 按位与;&& 逻辑与;
或:| 按位或;|| 逻辑或;
非:~ 按位非;! 逻辑非;
灵活使用缩位运算符,可以简化代码,避免重复工作;
如:
&a 可实现a各位间的与运算,即:&a等价于 a(0)&a(1)&...&a(n)
| a 可实现a各位间的或运算,即:| a等价于 a(0)|a(1)|...|a(n)
连接功能:将若干个寄存器类型/线网类型的变量首尾连接,形成一个更大位宽的变量;
如:
a = 2'b10;
b = 3'b010;
有{a,b} = 5'b10010;
迭代功能:把一个变量复制多次,首尾连接组成一个更大位宽的变量;(实际仍为连接功能的一个特例:连接元素相同)
如:
a = 2'b10;
有{4{a}},即{a,a,a,a}
注意:
要保证迭代的完整性:{ {4{a}},b} ({4{a}}为迭代功能,括号不能少;即不能写为{ 4{a},b} )
迭代连接运算符还可用于常量操作:{ {4{1'b1}},2'b10}
列举:
<< 逻辑左移运算符;<<< 数字左移运算符;
>> 逻辑右移运算符;>>> 数字右移运算符;
区别:逻辑移位运算符不关心符号位;逻辑左移右端补零,逻辑右移左端补零;
数字左移位运算符不关心符号位,与逻辑左移一样;数字右移运算符关心符号位,左端补符号位;
如:
1010101010,其中[]是添加的位
逻辑左移一位:010101010[0]
算数左移一位:010101010[0]
逻辑右移一位:[0]101010101
算数右移一位:[1]101010101
进行部分仿真(感觉很简单,着手去编写的时候却碰见了不少问题,万不可眼高手低!!!),代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer: guoliang CLL
//
// Create Date: 2020/02/19 10:15:53
// Design Name:
// Module Name: operation
// Project Name:
// Target Devices:
// Tool Versions:
// Description: 常见操作符测试
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module operation(
input [1:0]a,
input [2:0]b,
input signed[5:0]c,
//input signed[5:0]d,
output [5:0]e,// {3{a}}
output [4:0]f, // {a,b}
output [5:0]g,// {
{2{2'b10}},b}
output [5:0]sl, // 逻辑左移
output [5:0]sr,// 逻辑右移
output [5:0]sl1, // 数字左移
output [5:0]sr1 // 数字右移
);
integer N = 2'b11;
assign e = {3{a}};
assign f = {a,b};
assign g = { {2{2'b11}} ,a};
assign sl = c << 1;
assign sr = c >> 1;
assign sl1 = c <<< 1;
assign sr1 = c >>> 1;
endmodule
添加测试文件:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/02/19 10:59:51
// Design Name:
// Module Name: operation_tsb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module operation_tsb(
);
reg [1:0]a;
reg [2:0]b;
reg signed[5:0]c;
//input signed[5:0]d,
wire [5:0]e;// {3{a}}
wire [4:0]f; // {a,b}
wire [5:0]g;// {
{2{2'b11}},b}
wire [5:0]sl; // 逻辑左移
wire [5:0]sr;// 逻辑右移
wire [5:0]sl1; // 数字左移
wire [5:0]sr1; // 数字右移
initial
begin
a = 2'b10;
b = 3'b101;
c = 6'b110010;
# 20
c = 6'b010011;
end
operation ins(
.a(a),
.b(b),
.c(c),
.e(e),
.f(f),
.g(g),
.sl(sl),
.sr(sr),
.sl1(sl1),
.sr1(sr1)
);
endmodule
仿真结果以及RTL电路:
可以验证与文中移位、迭代连接操作的描述统一;
g的输出正确,证明迭代连接运算符确实可以用于常量操作,并且可以常量与变量混用,即仿真中的{ 2{2‘b11},a}
出现了问题:
验证迭代连接运算符确实可以用于常量操作时,如果将常量声明为integer类型,g的输出就不正确,即仿真中的integer N=2‘b11;
g = { {2{N}},a}时输出不对;改为parameter类型时,输出正确;
交流群里请教了大家后发现,原因在于interger默认为32位宽,拼接后被截取导致只有低位,因此不正确;(但是定义时我限定了位宽呀,为何还是32位??)参考博客后发现,integer好像就是位宽不能精确定义,这也是在位宽敏感时避免使用的原因;
仿真如下:
本文参考了:
逻辑左移、算术左移、逻辑右移、算术右移区别
Verilog编码规则:不使用integer类型,使用精确定义位宽的wire\reg类型