目录
2.5.1Conditional temary operator (Conditional)
2.5.2Reduction operator (Reduction)
2.5.3Reduction:Even wider gates (Gates100)
2.5.4Combinational for-loop:Vector reversal 2 (Vector100r)
2.5.5Combinational for-loop:255-bit population count(Popcount255)
2.5.6Generate for-loop:100-bit binary adder 2(Adder100i)
2.5.7Generate for-loop:100-digit BCD adder (Bcdadd100)
前言
HDLbits网站如下
Problem sets - HDLBits (01xz.net)
从本期开始我们继续HDLbits第二章Verilog Language的学习,本期的内容是2.5More Verilog Features
2.5.1Conditional temary operator (Conditional)
Verilog中像C语言一样有一个三目条件运算符(?:):
(condition ? if_true : if_false)
这可用于根据一行上的条件(数据选择器!)选择两个值之一,而无需在组合 always 块中使用 if-then。
Examples:
(0 ? 3 : 5) // 条件为假所以值为5 (sel ? b : a) // A 2-to-1 multiplexer between a and b selected by sel. always @(posedge clk) // T触发器 q <= toggle ? ~q : q; always @(*) // 单输入有限状态机的状态转换逻辑 case (state) A: next = w ? B : A; B: next = w ? A : B; endcase assign out = ena ? q : 1'bz; // 三态缓冲器 ((sel[1:0] == 2'h0) ? a : // 3选1数据选择器 (sel[1:0] == 2'h1) ? b : c )
A bit of practice
找到给定4个无符号数中最小的。无符号数可用标准比较运算符进行比较(a<b)。使用条件运算符构建一个两路最小值电路,然后组合它来构建一个四路最小值电路。您可能需要一些用于中间结果的wire向量。
期望的答案长度:大概5行
Solution:
module top_module (
input [7:0] a, b, c, d,
output [7:0] min);//
wire [7:0] intermediate_result1,intermediate_result2;
assign intermediate_result1 = (a<b)? a: b;
assign intermediate_result2 = (c<d)? c: d;
assign min = (intermediate_result1<intermediate_result2)?intermediate_result1:intermediate_result2;
endmodule
2.5.2Reduction operator (Reduction)
相信你已经对按位运算符很熟悉了,比如a&b 、a^b。有时,你想创建一个对某个向量的所有位进行操作的门,例如a[0] & a[1] & a[2] & a[3] ... ,但是如果向量太长的话就会变得很冗长。
而缩减运算符可以对向量所有位之间进行与、或、异或操作,并产生一位输出:
& a[3:0] // AND: a[3]&a[2]&a[1]&a[0]. 等价于 (a[3:0] == 4'hf) | b[3:0] // OR: b[3]|b[2]|b[1]|b[0]. 等价于 (b[3:0] != 4'h0) ^ c[2:0] // XOR: c[2]^c[1]^c[0]
这些是只有一个操作数的一元运算符(类似于取反运算符!和 ~)。你还可以对这些输出取反以创建与非门、或非门、同或门,例如~& d[7:0]。
现在你可以重温2.2.5 4-input gates 和2.5.3100-input gates.
A bit of practice
当通过不完善的信道传输数据时,奇偶校验通常用作检测错误的简单方法。创建一个电路来计算 8 位字节的奇偶校验位(这将向字节添加第 9 位)。我们将使用偶校验,其中奇偶校验位是所有 8 个数据位的异或。
期望的答案长度:大概1行
Solution:
module top_module (
input [7:0] in,
output parity);
assign parity = ^in;
endmodule
对于偶校验,原始8位字节 + 奇偶检验位总共有偶数个1
比如8’b10110001
奇校验是 9'b1_10110001 奇数个1
偶校验是 9'b0_10110001 偶数个1
2.5.3Reduction:Even wider gates (Gates100)
构建具有100个输入(in[99:0])的组合电路
有以下3个输出:
- out_and: 100个输入的与
- out_or : 100个输入的或
- out_xor: 100个输入的异或
Hint:缩减运算符更有用!
Solution:
module top_module(
input [99:0] in,
output out_and,
output out_or,
output out_xor
);
assign out_and = ∈
assign out_or = |in;
assign out_xor = ^in;
endmodule
2.5.4Combinational for-loop:Vector reversal 2 (Vector100r)
把给定100位输入向量的位序翻转并输出。
Hint:for 循环(在组合的 always 块或generate块中)在这里很有用。在这种情况下,我更喜欢组合 always 块,因为不需要模块实例化(generate块需要)。
Solution:
module top_module (
input [99:0] in,
output reg [99:0] out
);
always @(*) begin
for (integer i=0;i<$bits(out);i++) // $bits() 系统函数可以返回信号的位宽
out[i] = in[$bits(out)-i-1]; // $bits(out) = 100
end
endmodule
2.5.5Combinational for-loop:255-bit population count(Popcount255)
“人口计数”电路计算输入向量中“1”的数量。为 255 位输入向量构建人口计数电路。
Hint:试试for循环吧
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
2.5.6Generate for-loop:100-bit binary adder 2(Adder100i)
实例化100个全加器来构建一个100位纹波进位加法器。加法器将2个100位输入与低位的进位相加,以产生100位和以及进位。为了鼓励您实际实例化全加器,还要输出纹波进位加法器中每个全加器的进位。cout[99] 是最后一个全加器的最终进位,也是你经常看到的进位。
Hint:这里有很多全加器需要例化,实例化数组或者generate语句在这里会更有帮助。
Solution:
//method1:generate语句
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
full_adder add_0(a[0],b[0],cin,cout[0],sum[0]);
generate
genvar i;
for(i=1;i<100;i=i+1) begin:full_adder
full_adder add_i(a[i],b[i],cout[i-1],cout[i],sum[i]);
end
endgenerate
endmodule
module full_adder(
input a,b,
input cin,
output cout,
output sum);
assign {cout,sum}= a + b + cin;
endmodule
cout[i-1]=cin[i],i>0;
故先例化第一个全加器,之后再用generate语句例化
//method2 例化数组
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
full_adder add_0(a[0],b[0],cin,cout[0],sum[0]);
full_adder add[99:1](a[99:1],b[99:1],cout[98:0],cout[99:1],sum[99:1]);
endmodule
module full_adder(
input a,b,
input cin,
output cout,
output sum);
assign cout = a&b | a&cin | b&cin;
assign sum = a ^ b ^ cin;
endmodule
2.5.7Generate for-loop:100-digit BCD adder (Bcdadd100)
为您提供了一个名为 bcd_fadd 的 一位BCD加法器,它将两个 BCD 数字和进位相加,并产生一个总和和进位。
module bcd_fadd { input [3:0] a, input [3:0] b, input cin, output cout, output [3:0] sum );
实例化100个bcd_add副本以创建一个100位BCD纹波进位加法器。你的加法器应将两个100位BCD数(等价于400位向量)和一个进位相加,以产生100位的总和以及进位。
Hint:实例化数组或者generate语句在这里会更有帮助。
Solution:
module top_module(
input [399:0] a, b,
input cin,
output cout,
output [399:0] sum );
wire [99:0]cout0;
bcd_fadd fadd0 (a[3:0],b[3:0],cin,cout0[0],sum[3:0]);
generate
genvar i;
for(i=1;i<100;i=i+1) begin:bcd
bcd_fadd faddi(a[(3+4*i):(4*i)],b[(3+4*i):(4*i)],cout0[i-1],cout0[i],sum[(3+4*i):(4*i)]);
end
endgenerate
assign cout = cout0[99];
endmodule
好了,第二章Verilog language终于结束了,接下来会开始第三章Circuits~