目录
1 Conditional
Verilog具有三元条件运算符(?:)就像C语言里面:
condition ? if_true : if_false
可以用于根据一行上的条件(多路复用器)选择两个值之一,而无需在组合的always块中使用if-then。
比如说:
(0 ? 3 : 5) // This is 5 because the condition is false.
(sel ? b : a) // A 2-to-1 multiplexer between a and b selected by sel.
always @(posedge clk) // A T-flip-flop.
q <= toggle ? ~q : q;
always @(*) // State transition logic for a one-input FSM
case (state)
A: next = w ? B : A;
B: next = w ? A : B;
endcase
assign out = ena ? q : 1'bz; // A tri-state buffer
((sel[1:0] == 2'h0) ? a : // A 3-to-1 mux
(sel[1:0] == 2'h1) ? b :
c )
question:
给定四个无符号数字,找到最小值。可以将无符号数字与标准比较运算符(a <b)进行比较。使用条件运算符创建双向最小回路,然后组合其中的一些以创建四向最小回路。您可能需要一些线向量作为中间结果。
module top_module (
input [7:0] a, b, c, d,
output [7:0] min);//
// assign intermediate_result1 = compare? true: false;
wire [7:0] k1,k2;
assign k1=(a<b)?a:b;
assign k2=(c<d)?c:d;
assign min=(k1<k2)?k1:k2;
endmodule
2 Reduction operators
2.1 Reduction operators
您已经熟悉两个值之间的按位运算,例如a&b或a ^ b。有时,您想创建一个对一个向量的所有位进行操作的宽门,例如(a [0]&a [1]&a [2]&a [3] …),如果向量很长。
约简运算符可以对向量的位进行AND,OR和XOR,产生一位输出:
& a[3:0] // AND: a[3]&a[2]&a[1]&a[0]. Equivalent to (a[3:0] == 4'hf)
| b[3:0] // OR: b[3]|b[2]|b[1]|b[0]. Equivalent to (b[3:0] != 4'h0)
^ c[2:0] // XOR: c[2]^c[1]^c[0]
这些是只有一个操作数的一元运算符(类似于NOT运算符!和〜)。您还可以反转这些输出以创建NAND,NOR和XNOR门,例如(〜&d [7:0])。
question:
通过不完善的通道传输数据时,奇偶校验通常用作检测错误的简单方法。创建一个电路,该电路将计算8位字节的奇偶校验位(这将在字节中添加第9位)。我们将使用“偶数”奇偶校验,其中奇偶校验位只是所有8个数据位的XOR。
solution:
module top_module (
input [7:0] in,
output parity);
assign parity = ^in[7:0];
endmodule
2.2 Reduction: Even wider gates
question:
用[99:0]构建一个具有100个输入的组合电路。
有3个输出:
- out_and:100输入与门的输出。
- out_or:100输入或门的输出。
- out_xor:100输入XOR门的输出。
solution:
module top_module(
input [99:0] in,
output out_and,
output out_or,
output out_xor
);
assign out_and = &in[99:0];
assign out_or = |in[99:0];
assign out_xor = ^in[99:0];
endmodule
3 Combinational for-loop
3.1 Vector reversal 2
question:
给定100位输入向量[99:0],请反转其位顺序。
for循环(在组合的always块或generate块中)在这里很有用。在这种情况下,这里可以使用always block,因为不需要模块实例化(需要生成块)。
solution:
module top_module(
input [99:0] in,
output [99:0] out
);
always @(*) begin
for (int i=0;i<=99;i++)
begin
out[i] = in[99-i];
end
end
endmodule
anoter solution:
module top_module (
input [99:0] in,
output reg [99:0] out
);
always @(*) begin
for (int i=0;i<$bits(out);i++) // $bits() is a system function that returns the width of a signal.
out[i] = in[$bits(out)-i-1]; // $bits(out) is 100 because out is 100 bits wide.
end
endmodule
3.2 255-bit population count
question:
“人口计数”电路对输入向量中的“ 1”进行计数。建立一个255位输入向量的填充计数电路。
solution:
module top_module(
input [254:0] in,
output [7:0] out );
always @(*) begin
out = 8'b0000_0000; // noted:initial out
for (int i=0;i<=254;i++)
begin
if (in[i] == 1'b1)
out=out+8'b1;
end
end
endmodule
another solution:
module top_module (
input [254:0] in,
output reg [7:0] out
);
always @(*) begin // Combinational always block
out = 0;
for (int i=0;i<255;i++)
out = out + in[i];
end
endmodule
4 Generate for-loop
4.1 100-bit binary adder 2
question:
通过实例化100个完整的加法器来创建一个100位的二进制纹波进位加法器。
加法器将两个100位数字和一个进位相加,以产生100位和。为了鼓励您实际实例化完全加法器,还请在脉动进位加法器中输出每个完全加法器的进位。
提示:有许多要实例化的完整加法器。实例数组或generate语句将在这里有所帮助。cout [99]是最后一个完整加法器的最终进位,并且是通常看到的进位。(注意:这里要一位一位进行运算)
solution:
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
assign cout[0] = a[0]&b[0] | a[0]&cin | b[0]&cin;
assign sum[0] = a[0]^b[0]^cin;
always @(*) begin
for (int i=1;i<=99;i++)
begin
cout[i] = a[i]&b[i] | a[i]&cout[i-1] | b[i]&cout[i-1];
sum[i] = a[i]^b[i]^cout[i-1];
end
end
endmodule
4.2 100-digit BCD adder
question:
为您提供了一个名为bcd_fadd的BCD一位数字加法器,该加法器将两个BCD数字和进位相加,并产生总和和进位。bcd_fadd模块如下:
module bcd_fadd {
input [3:0] a,
input [3:0] b,
input cin,
output cout,
output [3:0] sum );
现在试着实例化100个bcd_fadd副本以创建一个100位的BCD纹波进位加法器。您的加法器应将两个100位的BCD编号(打包为400位向量)相加,并随身携带一个100位的总和并执行。
这道题与上一题类似,都需要先利用cin来初始化,但是不同的地方有两点:
- 一个是cout这里没有指定长度,不妨假设一个temp当做中间变量来充当cout的中间值,整个过程我们将进行100次(0、4、8、…、396这99个数字);
- 另一个是这里是使用模块进行实例化,那么就涉及到generate这个函数的问题,参考这里,我们知道:在本题中我们采用generate语句。
什么是generate语句?
生成语句可以动态的生成verilog代码,当对矢量中的多个位进行重复操作时,或者当进行多个模块的实例引用的重复操作时,或者根据参数的定义来确定程序中是否应该包含某段Verilog代码的时候,使用生成语句能大大简化程序的编写过程。
使用关键字generate 与 endgenerate来指定范围。generate语句有generate-for、generate-if、generate-case三种语句,本题中我们使用generate-for语句。generate-for语句:
(1) 必须有genvar关键字定义for语句的变量。
(2)for语句的内容必须加begin和end(即使就一句)。
(3)for语句必须有个名字。
solution:
module top_module(
input [399:0] a, b,
input cin,
output cout,
output [399:0] sum );
wire [99:0] temp;
bcd_fadd bcd_1 (a[3:0],b[3:0],cin,temp[0],sum[3:0]);
assign cout = temp[99];
generate
genvar i;
for (i=4;i<=399;i=i+4)
begin : bcdadd
bcd_fadd bcd_2 (a[i+3:i],b[i+3:i],temp[(i-4)/4],temp[i/4],sum[i+3:i]);
end
endgenerate
endmodule