Verilog基础学习一

HDLBits verilog 语言

Verilog语言入门



前言

根据HDLBits网站code情况记录一下每天学习的新的和体会,便于自己掌握和理解。


一、basic

1.Problem 2 : Wire

wire 的中文可以翻译为导线,但 Verilog 中的 wire 和现实中的导线不同,wire 应该理解为一个信号,信号是有方向性的,wire 从 A 点输出,输入到 B 点和 C 点。wire 一般只有一个 source,即从某一点输出,但可以有多个 sinks,即输入到多个点。A 点通常会被称为一个驱动(driver),把某个值驱动到 wire 上。

把驱动的概念引进到 Verilog 中,可以写作:

	assign left_side = right_side;
	//注意 wire 是有方向的 因此 assign in = out 是不等价的

2.Problem : Simple Gate

按位与 &
逻辑与 &&

按位或 |
逻辑或||

与非~(&)
或非~(|)

按位异或 ^
按位同或 ~^

二、vectors

1.声明向量

向量在声明时,必须遵循:

	type [upper:lower] vector_name;

其中 type 指定了向量的类型,一般为 wire 或者 reg 型。关于 reg 型,会在后续课程过程块的介绍中引入。如果向量为模块的输入输出端口,那么可以在 type 中添加 input/output 定义。


变量隐式声明的危害

你知道吗,变量的隐式声明是 Verilog 中 BUG 的一大来源。
信号变量有两种声明方式,一是使用 wire 或者 assign 语句进行显示声明和定义,二是综合器的隐式声明和定义。
当你将一个未定义声明的信号连接到模块的输入输出端口时,综合器会“热心”地帮助你声明这个信号。但我可以向你保证,综合器没有厉害到能通过上下文,察言观色,“热心而正确”地帮你声明信号,它只会将其声明为 1 bit wire 型信号,当你本来需要使用一个超过 1 bit 的向量,但又忘记声明时,综合器往往就好心办坏事了。

2.片选

使用 [ : ] 语法进行了最朴素和常用的信号片选。

3.Problem16:Vector reversal 1

给定一个 8bit 输入向量,将其反向输出。
integer i;
always @(*) begin	
     for (i=0; i<8; i++)	//Use integer for pure Verilog.
	     out[i] = in[8-i-1];
end

4.Problem 17 : Replication operator

重复操作符的应用场景之一是在有符号数的扩展。有符号数的扩展是将符号位填充待扩展的比特。
比如要将 4bit 的 4'b0101 有符号数扩展为 8bit ,0 是符号位,那么扩展之后为 8'b0000 0101.
现在要求你构建一个电路,将一个 8bit 有符号数扩展为 32bit 数。
module top_module (
    input [7:0] in,
    output [31:0] out );//

    // assign out = { replicate-sign-bit , the-input };
    assign out = {{24{in[7]}},in};
endmodule

将符号位 in[7] 扩展 24 位,后接原本的 8bit 数。

三、Modules

1.概念

截止目前,我们已经对 Verilog 中模块这一概念建立了初步的印象:模块是一个电路,通过输入输出端口和外部的电路联系。无论多大,多复杂的数字电路都是由一个个模块以及其他组成部分(比如 assign 赋值语句以及 always 过程块)互相连接所构成的。在一个模块中可以例化下一级的模块,这就形成了层级的概念(hierarchy)。

2.模块信号连接的两种方式

按端口顺序,mod_a instance1 ( wa, wb, wc ); wa, wb, wc 分别连接到模块的 第一个端口(in1),第二个端口(in2)以及第三个端口(out)。这里所谓的端口顺序指的是模块端口的定义顺序。这种方式的弊端在于,一旦端口列表发生改变,所有模块实例化中的端口连接都需要改变。

module 模块名 (连接信号1,连接信号2,连接信号3);

按端口名称,mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) ); 在这种方式中根据端口名称指定外部信号的连接。这样一来就和端口声明的顺序完全没有关系。一旦模块出现改动,只要修改相应的部分即可。实际上,一般都使用这种方式来进行模块实例化。

module 模块名 (.端口1(连接信号1).端口2(连接信号2).端口3(连接信号3)
				);

3.Problem 23: (Module shift8) (多路选择器)

给出了一个名为my_dff8的模块,包含两个输入和一个输出(实现一个8bit的D触发器)。请实例化三个,并将它们连接在一起,形成一个长度为3的8bit移位寄存器。此外,再写出一个4选1多路复用器(未提供模块模型),根据输入的sel[1:0]选择要输出的内容:输入D的值,在第一个D触发器之后的值,第二个或第三个D触发器之后的值。(可以说sel选择的是输入延迟的的周期数,0~3个时钟周期不等。)

给出的模块如下:

module my_dff8 ( input clk, input [7:0] d, output [7:0] q );

没有给出多路复用器。 一种实现方法是在一个always块内使用case语句。

module top_module (
	input clk,
	input [7:0] d,
	input [1:0] sel,
	output reg [7:0] q
);
	wire [7:0] o1, o2, o3;		// 声明每一个触发器的输出
	
	// Instantiate three my_dff8s
	my_dff8 d1 ( clk, d, o1 );
	my_dff8 d2 ( clk, o1, o2 );
	my_dff8 d3 ( clk, o2, o3 );

	// 这是实现4选1选择器的一种方法  
	always @(*)		// 组合逻辑always块
		case(sel)
			2'h0: q = d;
			2'h1: q = o1;
			2'h2: q = o2;
			2'h3: q = o3;
		endcase
endmodule

4.Problem 25: Adder 2(Module fadd)(全加器)

在本题中,您将描述一个具有两级层次结构的电路。在top_module中,实例化两个add16模块(已为您提供),每个add16中实例化16个add1实例(此模块需要您编写)。所以,您需要描述两个模块:top_module和add1。
与Problem 24: Adder 1(Module add)一样,提供给您一个执行16bit的加法的模块。您需要实例化两个16bit加法模块来实现32bit加法器。一个add16计算加法结果的低16位,另一个计算结果的高16位。您的32位加法器同样不需要处理进位输入(假设为0)和进位输出(无需进位)信号。
如下图所示,将add16模块连接在一起,给出的add16模块如下:

module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );

在这里插入图片描述
在每个add16中,实例化了16个全加器(add1,未给出,需要您自己写出)去执行加法操作。您必须编写具有以下声明的完整全加器(add1):

module add1 ( input a, input b, input cin, output sum, output cout );

总之,本题中一共有三个模块:

1、top_module:包含两个16位加法器的顶级模块;

2、add16(已给出):一个16bit的加法器,由16个全加器构成;

3、add(未给出):1bit全加器

module top_module (
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
    wire c;
    add16 add16_lo(.a(a[15:0]),
                   .b(b[15:0]),
                   .cin(1'b0),
                   .sum(sum[15:0]),
                   .cout(c)
                 );
    add16 add16_hi(.a(a[31:16]),
                   .b(b[31:16]),
                   .cin(c),
                   .sum(sum[31:16]),
                 );

endmodule
//全加器的逻辑表示
module add1 ( input a, input b, input cin,   output sum, output cout );
	assign sum = a ^ b ^ cin;
    assign cout = a&b | a&cin | b&cin;

endmodule

5.Problem 26: Carry-select adder (选择进位加法器)

提供的模块add16如下:

module add16 ( input[15:0] a, input[15:0] b, input cin, output[15:0] sum, output cout );

在这里插入图片描述

module top_module(
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
      wire c;
    wire [31:16] sum0,sum1;     //此处【31:16】应与第17行一致
    add16 add16_lo(.a(a[15:0]),
                   .b(b[15:0]),
                   .cin(1'b0),
                   .sum(sum[15:0]),
                   .cout(c)
                 );
    add16 add16_hi0(.a(a[31:16]),
                   .b(b[31:16]),
                   .cin(1'b0),
                    .sum(sum0[31:16]),
                 );
    add16 add16_hi1(.a(a[31:16]),
                   .b(b[31:16]),
                    .cin(1'b1),
                    .sum(sum1[31:16]),
                 );
    //条件操作符    x=y?a:b   意思为:y为真时,x==a   ;   y为假时,x==b
    assign sum[31:16] = c ? sum1 : sum0;

endmodule
  • 条件操作符 x=y?a:b 意思为:y为真时,x=a ; y为假时,x=b

6.Problem 27: Adder–subtractor (加减法器)

加减法器可以由加法器来构建,可以对其中一个数取相反数(对输入数据取反,然后加1)。最终结果是一个可以执行以下两个操作的电路:a+ba+~b+1减去一个数等于加上这个数的补码(就是题中的按位取反再加1) 。

  • 当sub为1时,使用32位的异或门对B进行取反。(这也可以被视为b[31:0]与sub复制32次相异或)。同时sub信号连接到加法器的进位。
  • 在这里插入图片描述
module top_module(
    input [31:0] a,
    input [31:0] b,
    input sub,
    output [31:0] sum
);
    wire c; 
    wire [31:0] d;
    assign d[31:0] = b ^ {32{sub}};  //按位取反,sub为0时d==b;   sub为1时按位取反
    
    add16 add16_lo(.a(a[15:0]),
                   .b(d[15:0]),
                   .cin(sub),
                   .sum(sum[15:0]),
                   .cout(c)
                 );
    add16 add16_hi(.a(a[31:16]),
                   .b(d[31:16]),
                   .cin(c),
                   .sum(sum[31:16]),
                 );

endmodule

总结

以上就是今天学习的内容,简单学习的Verilog基本的语法规则,和模块的使用与连接。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值