HDLbits笔记

HDLBits

Created: Apr 25, 2021
Created by: Martin Ma
Tags: Work

Implicit nets are often a source of hard-to-detect bugs. In Verilog, net-type signals can be implicitly created by an assign statement or by attaching something undeclared to a module port. Implicit nets are always one-bit wires and causes bugs if you had intended to use a vector. Disabling creation of implicit nets can be done using the `default_nettype none directive.

隐式网络通常是难以发现的错误的来源。在Verilog中,网络类型的信号可以通过Assign语句或通过将未声明的内容附加到模块端口来隐式创建。隐式网络始终是一位导线,如果您打算使用矢量,则会导致错误。可以使用`default_nettype none指令禁用隐式网络的创建。

wire [2:0] a, c;   // Two vectors
assign a = 3'b101;  // a = 101
assign b = a;       // b =   1  implicitly-created wire
assign c = b;       // c = 001  <-- bug
my_module i1 (d,e); // d and e are implicitly one-bit wide if not declared.
                    // This could be a bug if the port was intended to be a vector.

Adding `default_nettype none would make the second line of code an error, which makes the bug more visible.

添加`default_nettype none不会使第二行代码出错,从而使该错误更明显。


When using vectors, the distinction between the two operator types (bitwise or logical) becomes important. A bitwise operation between two N-bit vectors replicates the operation for each bit of the vector and produces a N-bit output, while a logical operation treats the entire vector as a boolean value (true = non-zero, false = zero) and produces a 1-bit output.

使用向量时,两种运算符类型(位运算符或逻辑运算符)之间的区别变得很重要。两个N位向量之间的按位运算会复制该向量的每个位的运算并产生N位输出,而逻辑运算会将整个向量视为布尔值(真=非零,假=零),并且产生1位输出。


This replicates vector by num times. num must be a constant. Both sets of braces are required.

Examples:

{5{1'b1}}           // 5'b11111 (or 5'd31 or 5'h1f)
{2{a,b,c}}          // The same as {a,b,c,a,b,c}
{3'd5, {2{3'd6}}}   // 9'b101_110_110. It's a concatenation of 101 with
                    // the second vector, which is two copies of 3'b110.

By name

Connecting signals to a module’s ports by name allows wires to remain correctly connected even if the port list changes. This syntax is more verbose, however.

mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) );

The above line instantiates a module of type mod_a named “instance2”, then connects signal wa (outside the module) to the port named in1, wb to the port named in2, and wc to the port named out. Notice how the ordering of ports is irrelevant here because the connection will be made to the correct name, regardless of its position in the sub-module’s port list. Also notice the period immediately preceding the port name in this syntax.


1-bit full adder

sum = a ^ b ^ cin

将三个输入a,b,cin按位进行异或。

addsub 减法器,可由加法器得来,当 cin = ‘0’ 时,sum = a+b+0 ; 当 cin = ‘1’ 时,sum = a+(~b)+1

Adder-subtractor - Wikipedia


There are three types of assignments in Verilog:

  • Continuous assignments (). Can only be used when not inside a procedure (“always block”). assign x = y;(连续赋值)
  • Procedural blocking assignment: (). Can only be used inside a procedure. x = y;(阻塞赋值)
  • Procedural non-blocking assignment: (). Can only be used inside a procedure. x <= y;(非阻塞赋值)

在这里插入图片描述

In a combinational always block, use blocking assignments. In a clocked always block, use non-blocking assignments. A full understanding of why is not particularly useful for hardware design and requires a good understanding of how Verilog simulators keep track of events. Not following this rule results in extremely hard to find errors that are both non-deterministic and differ between simulation and synthesized hardware.

在组合逻辑块中,使用阻塞赋值。在时序逻辑块中,使用非阻塞赋值。


在这里插入图片描述

An if statement usually creates a 2-to-1 multiplexer, selecting one input if the condition is true, and the other input if the condition is false.

always @(*) begin
    if (condition) begin
        out = x;
    end
    else begin
        out = y;
    end
end

This is equivalent to using a continuous assignment with a conditional operator:

assign out = (condition) ? x : y;

However, the procedural if statement provides a new way to make mistakes. The circuit is combinational only if out is always assigned a value.


casez

//检测第一个‘1’在哪一位
always @(*) begin
    casez (in[3:0])
        4'bzzz1: out = 0;   // in[3:1] can be anything
        4'bzz1z: out = 1;
        4'bz1zz: out = 2;
        4'b1zzz: out = 3;
        default: out = 0;
    endcase
end

在每个分支一定要对所有输出都进行赋值

always @(posedge clk)         // A T-flip-flop.
  q <= toggle ? ~q : q;

//多输入逻辑门
& 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]

奇偶校验(parity check):通过检查输入的数据中“1”的个数来确定传输数据的正确性。奇偶校验位可以通过对数据的每一位按位逐一进行异或操作来得到。对于奇校验,偶数个“1”,输出为0;奇数个“1”,输出为1。偶校验则相反。(eg. 1 ^ 0 ^ 1 ^ 1 ^ 0,结果为1)


//计算输入中含有多少个“1”
module pop_count(
	input [254:0] in,
	output [7:0] out
);

integer i;

always@(*) begin
	out = 8'd0; //essential!!
	for(i=0;i<255;i=i+1) begin
		if(in[i]==1) out = out + 1'b1;
		else out = out;
	end
end

endmodule
//100bits ripple-adder 100位行波进位加法器
module top_module( 
    input [99:0] a, b,
    input cin,
    output [99:0] cout,
    output [99:0] sum );

    full_adder add0(.a(a[0]), .b(b[0]), .cin(cin), .sum(sum[0]), .cout(cout[0]));
    
    genvar i;
    
    generate 
        for(i=1;i<100;i=i+1) begin: adder_inst
            full_adder add_inst(
                .a(a[i]),
                .b(b[i]),
                .cin(cout[i-1]),
                .sum(sum[i]),
                .cout(cout[i])
            );
        end
    endgenerate
    
endmodule

module full_adder(
	input a,b,
    input cin,
    output sum,
    output cout
);
    assign sum = a ^ b ^ cin;
   	assign cout = a&b | a&cin | b&cin;
   
endmodule

同或 = 异或非;


Gatesv

//my code
module top_module( 
    input [3:0] in,
    output [2:0] out_both,
    output [3:1] out_any,
    output [3:0] out_different );

    genvar i;
    generate 
        for(i=0;i<3;i=i+1) begin:both
            assign out_both[i] = (in[i] & in[i+1]) ? 1'b1 : 1'b0;
        end
    endgenerate
        
    genvar j;
    generate
        for(j=1;j<4;j=j+1) begin:any
            assign out_any[j] = (in[j] | in[j-1]) ? 1'b1 : 1'b0;
        end
    endgenerate
    
    assign out_different[3] = in[3] ^ in[0];    
    genvar k;
    generate
    	for(k=0;k<3;k=k+1) begin:different
            assign out_different[k] = (in[k] ^ in[k+1]) ? 1'b1 : 1'b0;
        end
    endgenerate
        
endmodule

//solution
module top_module (
	input [3:0] in,
	output [2:0] out_both,
	output [3:1] out_any,
	output [3:0] out_different
);

	// Use bitwise operators and part-select to do the entire calculation in one line of code
	// in[3:1] is this vector:   					 in[3]  in[2]  in[1]
	// in[2:0] is this vector:   					 in[2]  in[1]  in[0]
	// Bitwise-OR produces a 3 bit vector.			   |      |      |
	// Assign this 3-bit result to out_any[3:1]:	o_a[3] o_a[2] o_a[1]

	// Thus, each output bit is the OR of the input bit and its neighbour to the right:
	// e.g., out_any[1] = in[1] | in[0];	
	// Notice how this works even for long vectors.
	assign out_any = in[3:1] | in[2:0];

	assign out_both = in[2:0] & in[3:1];
	
	// XOR 'in' with a vector that is 'in' rotated to the right by 1 position: {in[0], in[3:1]}
	// The rotation is accomplished by using part selects[] and the concatenation operator{}.
	assign out_different = in ^ {in[0], in[3:1]};
	
endmodule

动态位宽的verilog表示

module top_module (
	input [1023:0] in,
	input [7:0] sel,
	output [3:0] out
);

	// We can't part-select multiple bits without an error, but we can select one bit at a time,
	// four times, then concatenate them together.
	assign out = {in[sel*4+3], in[sel*4+2], in[sel*4+1], in[sel*4+0]};

	// Alternatively, "indexed vector part select" works better, but has an unfamiliar syntax:
	// assign out = in[sel*4 +: 4];		// Select starting at index "sel*4", then select a total width of 4 bits with increasing (+:) index number.
	// assign out = in[sel*4+3 -: 4];	// Select starting at index "sel*4+3", then select a total width of 4 bits with decreasing (-:) index number.
	// Note: The width (4 in this case) must be constant.

endmodule

半加器(hadd)

module top_module( 
    input a, b,
    output cout, sum );

    assign sum = a ^ b;
    assign cout = a & b;
    
endmodule

全加器(fadd)

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

  	assign sum = a ^ b ^ cin;
    assign cout = a&b | a&cin | b&cin;
    
endmodule

//行为级描述
module top_module( 
    input [99:0] a, b,
    input cin,
    output cout,
    output [99:0] sum );

    assign {cout,sum} = a+b+cin;
    
endmodule

//同步高电平复位
module top_module (
    input clk,
    input reset,            // Synchronous reset
    input [7:0] d,
    output [7:0] q
);

    always@(posedge clk) begin //reset 不在敏感表中
        if(reset) q <= 8'd0;
        else q <= d;
    end
    
endmodule

//异步高电平复位
module top_module(
	input clk,
	input [7:0] d,
	input areset,
	output reg [7:0] q);
	
	// The only difference in code compared to synchronous reset is in the sensitivity list.
	always @(posedge clk, posedge areset)
		if (areset)
			q <= 0;
		else
			q <= d;

	// In Verilog, the sensitivity list looks strange. The FF's reset is sensitive to the
	// *level* of areset, so why does using "posedge areset" work?
	// To see why it works, consider the truth table for all events that change the input 
	// signals, assuming clk and areset do not switch at precisely the same time:
	
	//  clk		areset		output
	//   x		 0->1		q <= 0; (because areset = 1)
	//   x		 1->0		no change (always block not triggered)
	//  0->1	   0		q <= d; (not resetting)
	//  0->1	   1		q <= 0; (still resetting, q was 0 before too)
	//  1->0	   x		no change (always block not triggered)
	
endmodule
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Martin_MaB

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值