Verilog HDLBits 第六期:2.5More Verilog Features

目录

前言

 2.5.1Conditional temary operator  (Conditional)

A bit of practice

Solution:

 2.5.2Reduction operator  (Reduction)

A bit of practice

Solution:

 2.5.3Reduction:Even wider gates (Gates100)

Solution:

 2.5.4Combinational for-loop:Vector reversal 2 (Vector100r)

Solution:

2.5.5Combinational for-loop:255-bit population count(Popcount255)

Solution:

2.5.6Generate for-loop:100-bit binary adder 2(Adder100i)

Solution:

2.5.7Generate for-loop:100-digit BCD adder (Bcdadd100)

Solution:


前言

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 = &in;
    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~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值