HDLBits(3)8.24
2 Verilog语言
2.2 向量
2.2.4 逐位操作符(x)与逻辑操作符(xx)
逐位:对一个n bit输入向量进行逻辑运算,在n bit上逐位进行,并产生一个n bit长的结果
逻辑:任何类型的输入都会被视作布尔值,零->假,非零->真,将布尔值进行逻辑比较后,输出一个 1 bit的结果
eg:分别输出a,b逐位或;a,b逻辑或;a,b按位取反
assign out_or_bitwise = a | b;
assign out_or_logical = a || b;
assign out_not[2:0] = ~a;
assign out_not[5:3] = ~b;
2.2.5 四输入门
多输入的逻辑门可以使用位展开的写法和缩减运算符的写法,如下:
/* 缩减运算符 */
assign out_and = & in;
assign out_or = | in;
assign out_xor = ^ in;
/* 位展开运算符 */
assign out_and = in[3] & in[2] & in[1] & in[0];
assign out_or = in[3] | in[2] | in[1] | in[0];
assign out_xor = in[3] ^ in[2] ^ in[1] ^ in[0];
2.2.6 向量串联运算符(连续操作符)
将较小的向量连接在一起,创建更大的向量
基本语法:assign { a , b } = c;
一定要标注位宽,否则综合器不知道结果需要多少位宽
连接符既可用于赋值语句的右侧创造更大的向量,也可用于左侧奇偶啊换字节顺序,eg:
input [15:0] in;
output [23:0] out;
assign {out[7:0], out[15:8]} = in; // 连接符用于赋值语句左侧,交换了字节的顺序
assign out[15:0] = {in[7:0], in[15:8]}; // 连接符用于赋值语句右侧,交换了字节的顺序
assign out = {in[7:0], in[15:8]}; // 此语句作用上与上两句相同交换了字节顺序,但不同的是赋值语句右侧为16位
//赋予左值后,右值扩展为24位,高8位赋零,前两句中,高8位为未赋值状态
题目:
module top_module (
input [4:0] a, b, c, d, e, f,
output [7:0] w, x, y, z
);
assign w = {a,b[4:2]};
assign x = {b[1:0],c,d[4]};
assign y = {d[3:0],e[4:1]};
assign z = {e[0],f,2'b11};
endmodule
2.2.7 矢量反转
module top_module(
input [7:0] in,
output [7:0] out
);
assign {out[0],out[1],out[2],out[3],out[4],out[5],out[6],out[7]} = in;
endmodule
可以使用连接符来实现,但这种方法比较笨,不适用于较大位宽的向量,由于是多个重复操作,想到使用for循环来实现:
module top_module(
input [7:0] in,
output [7:0] out
);
integer i;
always @(*) begin
for (i=0; i<8; i++) //Use integer for pure Verilog.
out[i] = in[8-i-1];
end
endmodule
首先创建循环变量i,注意,HDLBits 上的 solution 中,i 定义于 for 循环的括号中,这在 Verilog 的语法中是不被允许的,是 SystemVerilog 的语法,Verilog 的语法需要提前定义 integer 变量,即整形变量
再创建组合逻辑always块,
always块是Verilog中用来描述组合逻辑以及时序逻辑的语法,组合逻辑语法为:
always @ (level event) begin
[multiple statements]
end
可以用 * 代替敏感信号,编译器会很具内部内容自动识别,达到简化的目的
值得注意的是,for 循环中的“循环”指的是代码层面的循环,而电路是不存在循环的,无论是信号而是门电路,都不存在循环。实际上,for 循环表示的代码将被综合器解析,for 循环将被分别解析为硬件电路。
除此之外,还可以使用generate 生成块(HDLBits提供的solution)
generate
genvar i;
for (i=0; i<8; i = i+1) begin: my_block_name
assign out[i] = in[8-i-1];
end
生成块与for循环的概念并不相同(一下全是复制粘贴,有待进一步理解)
for 循环和 Verilog 中其他的几种循环语句 while ,forever,repeat 本质上都用于控制语句的执行次数
生成块主要用于动态生成语句,例化 something(不只是例化模块),生成块与上述的过程块循环语句不同,并不是描述电路的一种行为。
生成块可以例化 assign 语句,模块,信号和变量的声明以及 always initial 这样的过程块。循环生成块是生成块中的一种类型,在综合过程中同样被综合器进行编译,这个过程可以看做综合过程中动态生成更多 Verilog 代码的预处理过程。在上面的例子中,generate 块在综合的过程中,综合了 8 句 assign 赋值语句
总的来说,for 循环强调了对电路的行为描述,在综合的过程中循环展开,而生成块则用于综合过程中,动态生成代码,两者有本质上的不同
而且再生成块中的 for 循环中不能像前例一样使用 integer 作为循环变量,而是必须使用 genvar 变量