HDL-bits


前言

HDL- bits 记录
HDL-bits


一、Verilog language

1. basic

1. Four wires

Create a module with 3 inputs and 4 outputs that behaves like wires that makes these connections:
a -> w
b -> x
b -> y
c -> z
在这里插入图片描述

module top_module( 
    input a,b,c,
    output w,x,y,z );
    assign w = a;
    assign x = b;
    assign y = b;
    assign z = c;    
endmodule

2. Inverter

Create a module that implements a NOT gate.
在这里插入图片描述

module top_module( input in, output out );
    assign out = ~in;
endmodule

3. NOR gate

在这里插入图片描述
Verilog has separate bitwise-OR (|) and logical-OR (||) operators

module top_module( 
    input a, 
    input b, 
    output out );
    assign out = !(a || b); 
    or assign out = !(a | b);
endmodule

4. XNOR gate

在这里插入图片描述
The bitwise-XOR operator is ^. There is no logical-XOR operator.

module top_module( 
    input a, 
    input b, 
    output out );
    assign out = ~(a^b);
endmodule

5. Declaring wires

在这里插入图片描述

module top_module (
    input in,              // Declare an input wire named "in"
    output out             // Declare an output wire named "out"
);
    wire not_in;           // Declare a wire named "not_in"
    assign out = ~ not_in;  // Assign a value to out (create a NOT gate).
    assign not_in = ~ in;   // Assign a value to not_in (create another NOT gate).
endmodule   // End of module "top_module"

在这里插入图片描述

`default_nettype none
module top_module(
    input a,
    input b,
    input c,
    input d,
    output out,
    output out_n   ); 
    wire two_wires, one_wires;
    assign two_wires = a & b;
    assign one_wires = two_wires || (c & d);
    assign out_n = ~one_wires;
    assign out   =  one_wires;
endmodule
	wire w1, w2;		// Declare two wires (named w1 and w2)
	assign w1 = a&b;	// First AND gate
	assign w2 = c&d;	// Second AND gate
	assign out = w1|w2;	// OR gate: Feeds both 'out' and the NOT gate
	assign out_n = ~out;	// NOT gate

6. 7458 chip

在这里插入图片描述

module top_module ( 
    input p1a, p1b, p1c, p1d, p1e, p1f,
    output p1y,
    input p2a, p2b, p2c, p2d,
    output p2y );
    wire w1,w2,w3,w4;
    assign w1 = p1a & p1b & p1c;
    assign w2 = p1d & p1e & p1f;
    assign w3 = p2a & p2b;
    assign w4 = p2c & p2d;
    assign p2y = w3 || w4;
    assign p1y = w1 || w2;
endmodule

2. Vectors

1. Vectors

wire [99:0] my_vector; // Declare a 100-element vector
assign out = my_vector[10]; // Part-select one bit out of the vector

在这里插入图片描述

module top_module ( 
    input wire [2:0] vec,
    output wire [2:0] outv,
    output wire o2,
    output wire o1,
    output wire o0  ); // Module body starts after module declaration
    assign outv = vec;
    assign o0   = vec[0];
    assign o1   = vec[1];
    assign o2   = vec[2];
    assign {o2,o1,o0} = vec;
endmodule

2. Vectors in more detail

Declaring Vectors
wire [7:0] w;         // 8-bit wire
reg  [4:1] x;         // 4-bit reg
output reg [0:0] y;   // 1-bit reg that is also an output port (this is still a vector)
input wire [3:-2] z;  // 6-bit wire input (negative ranges are allowed)
output [3:0] a;       // 4-bit output wire. Type is 'wire' unless specified otherwise.
wire [0:7] b;         // 8-bit wire where b[0] is the most-significant bit.
Implicit nets
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.
Unpacked vs. Packed Arrays
reg [7:0] mem [255:0];   // 256 unpacked elements, each of which is a 8-bit packed vector of reg.
reg mem2 [28:0];         // 29 unpacked elements, each of which is a 1-bit reg.
Accessing Vector Elements: Part-Select
w[3:0]      // Only the lower 4 bits of w
x[1]        // The lowest bit of x
x[1:1]      // ...also the lowest bit of x
z[-1:-2]    // Two lowest bits of z
b[3:0]      // Illegal. Vector part-select must match the direction of the declaration.
b[0:3]      // The *upper* 4 bits of b.
assign w[3:0] = b[0:3];    // Assign upper 4 bits of b to lower 4 bits of w. w[3]=b[0], w[2]=b[1], etc.

A Bit of Practice
Build a combinational circuit that splits an input half-word (16 bits, [15:0] ) into lower [7:0] and upper [15:8] bytes.

`default_nettype none     // Disable implicit nets. Reduces some types of bugs.
module top_module( 
    input wire [15:0] in,
    output wire [7:0] out_hi,
    output wire [7:0] out_lo );
    assign out_hi = in[15:8];
	assign out_lo = in[7:0];
	// Concatenation operator also works: assign {out_hi, out_lo} = in;
endmodule

3. Vector part select

A 32-bit vector can be viewed as containing 4 bytes (bits [31:24], [23:16], etc.). Build a circuit that will reverse the byte ordering of the 4-byte word.

AaaaaaaaBbbbbbbbCcccccccDddddddd => DdddddddCcccccccBbbbbbbbAaaaaaaa

module top_module (
	input [31:0] in,
	output [31:0] out
);

	assign out[31:24] = in[ 7: 0];	
	assign out[23:16] = in[15: 8];	
	assign out[15: 8] = in[23:16];	
	assign out[ 7: 0] = in[31:24];	
	
endmodule

4. bitwise operators

在这里插入图片描述

module top_module(
	input [2:0] a, 
	input [2:0] b, 
	output [2:0] out_or_bitwise,
	output out_or_logical,
	output [5:0] out_not
);
	
	assign out_or_bitwise = a | b;
	assign out_or_logical = a || b;

	assign out_not[2:0] = ~a;	// Part-select on left side is o.
	assign out_not[5:3] = ~b;	//Assigning to [5:3] does not conflict with [2:0]
	
endmodule

4. Four-input gates

Build a combinational circuit with four inputs, in[3:0].

There are 3 outputs:

out_and: output of a 4-input AND gate.
out_or: output of a 4-input OR gate.
out_xor: output of a 4-input XOR gate.

module top_module( 
    input [3:0] in,
    output out_and,
    output out_or,
    output out_xor
);
    assign out_and = &in;
    assign out_or  = |in;`在这里插入代码片`
    assign out_xor = ^in;
endmodule

5. vector concatenate operator

{3'b111, 3'b000} => 6'b111000
{1'b1, 1'b0, 3'b101} => 5'b10101
{4'ha, 4'd10} => 8'b10101010     // 4'ha and 4'd10 are both 4'b1010 in binary
input [15:0] in;
output [23:0] out;
assign {out[7:0], out[15:8]} = in;         // Swap two bytes. Right side and left side are both 16-bit vectors.
assign out[15:0] = {in[7:0], in[15:8]};    // This is the same thing.
assign out = {in[7:0], in[15:8]};       // This is different. The 16-bit vector on the right is extended to
                                        // match the 24-bit vector on the left, so out[23:16] are zero.
                                        // In the first two examples, out[23:16] are not assigned.

在这里插入图片描述

module top_module (
    input [4:0] a, b, c, d, e, f,
    output [7:0] w, x, y, z );
    assign {w,x,y,z} = {a, b, c, d, e, f,2'b11};
endmodule

6. Vector reversal 1

Given an 8-bit input vector [7:0], reverse its bit ordering.

module top_module (
	input [7:0] in,
	output [7:0] out
);
	
	assign {out[0],out[1],out[2],out[3],out[4],out[5],out[6],out[7]} = in;
	
	/*
	// I know you're dying to know how to use a loop to do this:

	// Create a combinational always block. This creates combinational logic that computes the same result
	// as sequential code. for-loops describe circuit *behaviour*, not *structure*, so they can only be used 
	// inside procedural blocks (e.g., always block).
	// The circuit created (wires and gates) does NOT do any iteration: It only produces the same result
	// AS IF the iteration occurred. In reality, a logic synthesizer will do the iteration at compile time to
	// figure out what circuit to produce. (In contrast, a Verilog simulator will execute the loop sequentially
	// during simulation.)
	always @(*) begin	
		for (int i=0; i<8; i++)	// int is a SystemVerilog type. Use integer for pure Verilog.
			out[i] = in[8-i-1];
	end


	// It is also possible to do this with a generate-for loop. Generate loops look like procedural for loops,
	// but are quite different in concept, and not easy to understand. Generate loops are used to make instantiations
	// of "things" (Unlike procedural loops, it doesn't describe actions). These "things" are assign statements,
	// module instantiations, net/variable declarations, and procedural blocks (things you can create when NOT inside 
	// a procedure). Generate loops (and genvars) are evaluated entirely at compile time. You can think of generate
	// blocks as a form of preprocessing to generate more code, which is then run though the logic synthesizer.
	// In the example below, the generate-for loop first creates 8 assign statements at compile time, which is then
	// synthesized.
	// Note that because of its intended usage (generating code at compile time), there are some restrictions
	// on how you use them. Examples: 1. Quartus requires a generate-for loop to have a named begin-end block
	// attached (in this example, named "my_block_name"). 2. Inside the loop body, genvars are read only.
	generate
		genvar i;
		for (i=0; i<8; i = i+1) begin: my_block_name
			assign out[i] = in[8-i-1]; 这样不行
		end
	endgenerate
	*/
	
endmodule

7. replication

{num{vector}} 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.
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

在这里插入图片描述

module top_module (
    input a, b, c, d, e,
    output [24:0] out );
    // The output is XNOR of two vectors created by 
    // concatenating and replicating the five inputs.
    // assign out = ~{ ... } ^ { ... };
    assign out = ~{{5{a}},{5{b}},{5{c}},{5{d}},{5{e}}} ^ {{5{a,b,c,d,e}}};
endmodule

3. Modules: Hierarchy

1. Modules

在这里插入图片描述

module mod_a ( input in1, input in2, output out );
    // Module body
endmodule
1. By position
mod_a instance1 ( wa, wb, wc );
connects signal wa (outside the new module) to the first port (in1) of the new module, wb to the second port (in2), and wc to the third port (out).
2. By name
mod_a instance2 ( .out(wc), .in1(wa), .in2(wb) );

在这里插入图片描述

module top_module ( input a, input b, output out );
    //mod_a instance1( .out(out), .in1(a), .in2(b));
    mod_a instance2(a,b,out);
endmodule

2. Three Modules

module my_dff ( input clk, input d, output q );

在这里插入图片描述

module top_module ( input clk, input d, output q );
    wire q1, q2;

    my_dff inst1(clk, d,  q1);
    my_dff inst2(clk, q1, q2);
    my_dff inst3(clk, q2, q );
endmodule

3. Module shift8

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

在这里插入图片描述

module top_module ( 
    input clk, 
    input [7:0] d, 
    input [1:0] sel, 
    output [7:0] q 
);
    logic [7:0] q1, q2, q3;

    
    my_dff8 fifo1(clk, d,  q1);
    my_dff8 fifo2(clk, q1, q2);
    my_dff8 fifo3(clk, q2, q3);
    
    always @(*) begin
        case(sel) 
          2'b00: begin  q = d;  end // 注意这里不能用 assign q = d; 编译不通过
          2'b01: begin  q = q1; end
          2'b10: begin  q = q2; end
          2'b11: begin  q = q3; end
        endcase
    end
endmodule

4. Adder1

16-bit a + b + cin
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 cout;
    reg [15:0] sum1,sum2;
    add16 low_bit (a[15:0],  b[15:0], 0,   sum1[15:0], cout);
    add16 high_bit(a[31:16], b[31:16],cout,sum2[15:0], 0);
    assign sum = {sum2[15:0],sum1[15:0]};
endmodule

5. Adder2***

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

在这里插入图片描述

module top_module (
    input [31:0] a,
    input [31:0] b,
    output [31:0] sum
);
   wire cout;
   reg [15:0] sum1,sum2;
    add16 low_bit   (a[15:0], b[15:0], 0, sum1,cout);
   add16 high_bit (a[31:16],b[31:16],cout,sum2,0);
   assign sum = {sum2,sum1};   
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;
    assign {cout,sum} = a+b+cin;
endmodule

6. carry-select addr

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 cout;
    reg [15:0] sum1,sum2,sum3; //wire [15:0] sum1,sum2,sum3;
    add16 low_bit(a[15:0],  b[15:0],  0, sum1, cout); 
    add16 hi1_bit(a[31:16], b[31:16], 0, sum2, 0); //cout 一定要为0,或者不写,否则编译不通过
    add16 hi2_bit(a[31:16], b[31:16], 1, sum3, 0);
    always@(*) begin
        case(cout)
            0: begin  sum = {sum2,sum1}; end
            1: begin  sum = {sum3,sum1}; end
        endcase
    end   
endmodule

7. Addr-subtractor

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

在这里插入图片描述
在这里插入图片描述

`default_nettype none
module top_module(
    input [31:0] a,
    input [31:0] b,
    input sub,
    output [31:0] sum
);
    wire cout;
    wire [31:0] c;
    wire [15:0] sum1, sum2;
    assign c = b^{32{sub}}; 
    假如是assign c = b^sub; 会dismatch,因为sub是1bit    
    //if sub=1,c=~b; if sub = 0,c=b;
    add16 low (a[15:0],  c[15:0],  sub,  sum1, cout);
    add16 high(a[31:16], c[31:16], cout, sum2, 0);
    assign sum = {sum2,sum1};   

endmodule

Procedures

1. always blocks(combinational, clocked)

For synthesizing hardware, two types of always blocks are relevant:

  • Combinational: always @(*)
  • Clocked: always @(posedge clk)
    程序块中的连续赋值不要写,虽然可以写,但是不能合成电路;

两者都将在任何输入(右侧)改变值时重新计算输出:
assign out1 = a & b | c ^ d;
always @(*) out2 = a & b | c ^ d;

赋值语句的左手边必须是网络类型(例如,wire),而过程赋值语句的左手边(在always块中)必须是变量类型(例如,reg)。
在有时钟的always块中,使用非阻塞赋值。
在这里插入图片描述

// synthesis verilog_input_version verilog_2001
module top_module(
    input clk,
    input a,
    input b,
    output wire out_assign,
    output reg out_always_comb,
    output reg out_always_ff   );

    assign out_assign = a^b;
    always @(*) begin
        out_always_comb = a^b;
    end
    always @(posedge clk) begin
        out_always_ff <= a^b;
    end
endmodule

在这里插入图片描述

2. if statement

1. assign out = (condition) ? x : y;
2. always @(*) begin
    if (condition) begin
        out = x;
    end
    else begin
        out = y;
    end
end

在这里插入图片描述
学习如何避免产生 latch, 比如在 always 块中所列举的情况没有完全,会出现你没有列举的情况时,那输出会是什么呢?Verilog的答案是:保持输出不变。这种“保持输出不变”的行为意味着需要记住当前状态,从而产生latch。组合逻辑不能保存任何状态。组合电路必须在所有条件下为所有输出分配一个值。 这通常意味着始终需要为输出分配 else 子句或默认值。

// synthesis verilog_input_version verilog_2001
module top_module (
    input      cpu_overheated,
    output reg shut_off_computer,
    input      arrived,
    input      gas_tank_empty,
    output reg keep_driving  ); //

    always @(*) begin
        if (cpu_overheated)
           shut_off_computer = 1;
        else
           shut_off_computer = 0;  
    end

    always @(*) begin
        if (~arrived)
           keep_driving = ~gas_tank_empty;
        else 
           keep_driving =  0;            
    end

endmodule

3. case statement

always @(*) begin     // This is a combinational circuit
    case (in)
      1'b1: begin 
               out = 1'b1;  // begin-end if >1 statement
            end
      1'b0: out = 1'b0;
      default: out = 1'bx;
    endcase
end
// synthesis verilog_input_version verilog_2001
module top_module ( 
    input [2:0] sel, 
    input [3:0] data0,
    input [3:0] data1,
    input [3:0] data2,
    input [3:0] data3,
    input [3:0] data4,
    input [3:0] data5,
    output reg [3:0] out   );//

    always@(*) begin  // This is a combinational circuit
        case(sel)
          3'b000: out = data0;
          3'b001: out = data1;
          3'b010: out = data2;
          3'b011: out = data3;
          3'b100: out = data4;
          3'b101: out = data5;
            default: out = 0;
        endcase
    end
endmodule

4. priority encoder 优先编码器

优先级编码器是一种组合电路,当给定输入位矢量时,输出矢量中第一个1位的位置。 例如,给定输入 8’b100 1 0000 的 8 位优先级编码器将输出 3’d4,因为 bit[4] 是第一个高位。构建 4 位优先级编码器。对于此问题,如果输入位均为零,则输出为零。请注意,4 位数字有 16 种可能的组合。

// synthesis verilog_input_version verilog_2001
module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
always @(*) begin
	case(in)
		4'b0000: pos = 0;
		4'b0001: pos = 0;
		4'b0010: pos = 1;
		4'b0100: pos = 2;
		4'b1000: pos = 3;
		4'b0011: pos = 0;
		4'b0110: pos = 1;
		4'b1100: pos = 2;
		4'b0101: pos = 0;
		4'b1010: pos = 1;
		4'b1001: pos = 0;
		4'b0111: pos = 0;
		4'b1110: pos = 1;
		4'b1011: pos = 0;
		4'b1101: pos = 0;
		4'b1111: pos = 0;
	endcase
end
endmodule

4. casez

It treats bits that have the value z as don’t-care in the comparison.

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

case语句的行为就好像每个项都是按顺序检查的(实际上,这是一个大的组合逻辑函数)。注意某些输入(例如,4’b1111)如何匹配多个case项。选择第一个匹配项(因此4’b1111匹配第一个项,out = 0,但不匹配后面的任何项)。

// synthesis verilog_input_version verilog_2001
module top_module (
    input [7:0] in,
    output reg [2:0] pos );
    always @(*) begin
        casez (in[7:0])
            8'bzzzz_zzz1: pos = 0;
            8'bzzzz_zz10: pos = 1;
            8'bzzzz_z100: pos = 2;
            8'bzzzz_1000: pos = 3;
            8'bzzz1_0000: pos = 4;
            8'bzz10_0000: pos = 5;
            8'bz100_0000: pos = 6;
            8'b1000_0000: pos = 7;
        endcase
    end
endmodule

5. avoid latches

假设你正在构建一个电路来处理来自PS/2键盘的游戏扫描码。给定接收到的扫描码的最后两个字节,您需要指示键盘上的一个方向键是否被按下。这涉及到一个相当简单的映射,它可以实现为带有四个case的case语句(或if-elseif)。
你的电路有一个16位输入和四个输出。构建识别这四种扫描码并断言正确输出的电路。
为了避免产生锁存, 所有输出都必须在所有可能的条件下赋值(参见always_if2)。仅仅有一个违约情况是不够的。您必须为所有四种情况和默认情况下的所有四个输出分配一个值。这可能涉及许多不必要的输入。一个简单的方法是在case语句之前给输出赋一个“默认值”:

always @(*) begin
    up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
    case (scancode)
        ... // Set to 1 as necessary.
    endcase
end

这种代码风格确保输出在所有可能的情况下都被赋值(0),除非case语句重写了赋值。这也意味着default: case项不再需要。
在这里插入图片描述
提醒:逻辑合成器生成一个组合电路,其行为等价于代码所描述的。硬件不会按顺序“执行”代码行。

module top_module (
    input [15:0] scancode,
    output reg left,
    output reg down,
    output reg right,
    output reg up  ); 
    always @(*) begin
      left = 1'b0;
      down = 1'b0;
      right= 1'b0;
      up   = 1'b0;
      case(scancode)
        16'he06b: left = 1'b1;
        16'he072: down = 1'b1;
        16'he074: right= 1'b1;
        16'he075: up   = 1'b1;
      endcase
    end
endmodule

more verilog Features

1. conditional ternary operator 三元条件运算符

(condition ? if_true : if_false)

(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 )

比较大小

module top_module (
    input [7:0] a, b, c, d,
    output [7:0] min);//   
    wire [7:0] result1, result2;
    assign result1 = (a>b)? b:a;
    assign result2 = (c>d)? d:c;
    assign min = (result1>result2)? result2:result1;
    // assign intermediate_result1 = compare? true: false;
endmodule

2. reduction operators

单目运算符

& 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)通常用作通过不完善通道传输数据时检测错误的一种简单方法。
Create a circuit that will compute a parity bit for a 8-bit byte (which will add a 9th bit to the byte).
将使用“偶数”奇偶校验,奇偶校验位只是所有8个数据位的XOR。

module top_module (
    input [7:0] in,
    output parity); 
    assign parity = ^in;
endmodule

3. vector100r

Given a 100-bit input vector [99:0], reverse its bit ordering.

module top_module( 
    input [99:0] in,
    output [99:0] out
);
    always @(*) begin
        for(int i = 0; i<100; i++) begin
            out[i] = in[99-i];
        end
    end
endmodule

A for loop (in a combinational always block or generate block) would be useful here. I would prefer a combinational always block in this case because module instantiations (which require generate blocks) aren’t needed.

4. Popcount 255 总体计数

数in中1的个数

module top_module( 
    input  [254:0]  in,
    output [7:0]    out 
);
 
reg [7:0] cnt;
integer i;
always @(*) begin
	cnt = 'd0;
	for (i=0;i<255;i=i+1) begin
		cnt = (in[i])? (cnt+1'b1):cnt;
	end
end
assign out = cnt;
endmodule

5. Adder100i **

通过实例化 100 个全加器来创建一个 100 位二进制行波进位加法器。加法器将两个 100 位数字和一个随身数字相加,以产生 100 位总和并执行。实际实例化全加器,还要从行波进位加法器中的每个全加器输出执行。cout[99]是最后一个全加器的最终执行。

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

    always @(*) begin
        cout = 0;
        sum  = 0;
        for(int i = 0; i<100; i++)begin
            if(i == 0)
              {cout[i],sum[i]} = a[i] + b[i] + cin;
            else
              {cout[i],sum[i]} = a[i] + b[i] + cout[i-1]; // 注意cout[i-1] 而不是cout[i]
        end
    end
endmodule

6. Bcdadd100**

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

以一个四位的全加器模块,计算两个输入数据的相加,其位宽为400。

module top_module( 
    input  [399:0]  a,b,
    input           cin,
    output          cout,
    output [399:0]  sum 
);
 
wire [99:0]  cin_cnt;
genvar i;
generate
	for (i=0;i<100;i=i+1) begin:test
		if (i == 0) begin
			bcd_fadd bcd_fadd_inst(a[3:0],b[3:0],cin,cin_cnt[0],sum[3:0]);
		end
		else begin
			bcd_fadd bcd_fadd_inst(a[4*(i+1)-1:4*i],b[4*(i+1)-1:4*i],cin_cnt[i-1],cin_cnt[i],sum[4*(i+1)-1:4*i]);
		end
		
	end
	assign cout = cin_cnt[99];
endgenerate
 
endmodule

二、circuits

Combinational logic

basic Gates

1.truth tables

在这里插入图片描述

module top_module( 
    input x3,
    input x2,
    input x1,  // three inputs
    output f   // one output
);
    assign f = x3 ? x1 : x2;
endmodule
2. combine circuits A and B

在这里插入图片描述

module top_module (input x, input y, output z);
    wire z_a1,z_a2,z_b1,z_b2;    
    assign z_a1 = (x ^ y) & x;
    assign z_a2 = (x ^ y) & x;
    assign z_b1 = ~(x ^ y);
    assign z_b2 = ~(x ^ y); 
    assign z = (z_a1 | z_b1) ^ (z_a2 & z_b2);    
endmodule
3. ring or vibrate

在这里插入图片描述

module top_module (
    input ring,
    input vibrate_mode,
    output ringer,       // Make sound
    output motor         // Vibrate
);
    assign ringer = ((ring == 1'b1) && (vibrate_mode == 1'b0)) ? 1:0;
    assign motor  = ((ring == 1'b1) & (vibrate_mode == 1'b1)) ? 1:0;  // & 会有warning,要用 &&

endmodule
4. Thermostat 恒温器**

恒温器有两种模式:

  1. 加热模式(mode = 1)和冷却模式(mode = 0),在加热模式下,温度过低(too_cold = 1)时打开加热器,但不使用空调。
  2. 在制冷模式下,当温度过高(too_hot = 1)时,请打开空调,但不要打开暖气。
  3. 当加热器或空调打开时,也要打开风扇,让空气流通。
  4. 此外,用户还可以要求打开风扇(fan_on = 1),即使加热器和空调关闭。
module top_module (
    input too_cold,
    input too_hot,
    input mode,
    input fan_on,
    output heater,
    output aircon,
    output fan
); 
    assign heater = too_cold & mode;
    assign aircon = too_hot & (~mode);
    assign fan = fan_on | aircon | heater; 
endmodule
5. Gates and Vectors

给你一个4位的输入向量[3:0]。我们想知道每个比特和它的邻居之间的关系:

  • out_both: 这个输出向量的每一位都应该表明对应的输入位和它左边的邻居(更高的下标)是否都是“1”。例如,out_both[2]应该表示[2]和[3]中是否都是1。因为在[3]中左边没有邻居,所以答案很明显,所以我们不需要知道out_both[3]。
  • out_any: 这个输出向量的每一位都应该表明是否有任何对应的输入位和它右边的邻居是“1”。例如,out_any[2]应该指示[2]或[1]中的任何一个为1。因为在[0]中右边没有邻居,所以答案很明显,所以我们不需要知道out_any[0]。
  • out_different: 这个输出向量的每一位都应该表明对应的输入位与它左边的邻居是否不同。例如,out_different[2]应该表示[2]中的内容与[3]中的内容是否不同。对于这一部分,将向量视为环绕,因此[3]中左边的邻居在[0]中。
module top_module( 
    input [3:0] in,
    output [2:0] out_both,
    output [3:1] out_any,
    output [3:0] out_different );
    assign out_both[2] = in[3] & in[2];
    assign out_both[1] = in[1] & in[2];
    assign out_both[0] = in[1] & in[0];
    
    assign out_any[3] = in[3] | in[2];
    assign out_any[2] = in[1] | in[2];
    assign out_any[1] = in[1] | in[0];
    
    assign out_different[3] = (in[3] != in[0]);
    assign out_different[2] = (in[3] != in[2]);
    assign out_different[1] = (in[1] != in[2]);
    assign out_different[0] = (in[1] != in[0]);
endmodule

在[99:0]中给你一个100位的输入向量。我们想知道每个比特和它的邻居之间的关系:

out_both: 这个输出向量的每一位都应该表明对应的输入位和它左边的邻居是否都是“1”。例如,out_both[98]应该表示[98]和[99]中是否都是1。因为in[99]左边没有邻居,所以答案很明显,所以我们不需要知道out_both[99]。
out_any: 这个输出向量的每一位都应该表明是否有任何对应的输入位和它右边的邻居是“1”。例如,out_any[2]应该指示[2]或[1]中的任何一个为1。因为在[0]中右边没有邻居,所以答案很明显,所以我们不需要知道out_any[0]。
out_different: 这个输出向量的每一位都应该表明对应的输入位与它左边的邻居是否不同。例如,out_different[98]应该表示[98]中是否与[99]中不同。对于这一部分,将向量视为环绕,因此在[99]中左侧的邻居在[0]中。

module top_module( 
    input [99:0] in,
    output [98:0] out_both,
    output [99:1] out_any,
    output [99:0] out_different );
    
    assign out_both[98:0] = in[99:1] & in[98:0];
    assign out_any[99:1]  = in[99:1] | in[98:0];
    assign out_different[98:0] = (in[98:0] ^ in[99:1]);
    assign out_different[99] = (in[99] ^ in[0]);  // 用 != 不行,因为!= 不是位比较符, ^ 是位比较符
endmodule

Multiplexers

2 to 1 multiplexer, 2 to 1 bus multiplexer
module top_module( 
    input   a, b, sel,
    output  out 
); 
    assign out = sel?b:a;
endmodule
module top_module( 
    input  [99:0]  a, b,
    input          sel,
    output [99:0]  out 
);
    assign out = sel?b:a; 
endmodule
9 to 1 multiplexer

创建 16 位宽、9 对 1 多路复用器。sel=0 选择 a,sel=1 选择 b,依此类推。对于未使用的情况(sel=9 到 15),请将所有输出位设置为“ffff”。

module top_module( 
    input [15:0] a, b, c, d, e, f, g, h, i,
    input [3:0] sel,
    output [15:0] out );
    always @(*) begin    
      case (sel)
        4'b0000: out = a;
        4'b0001: out = b;
        4'b0010: out = c;
        4'b0011: out = d;
        4'b0100: out = e;
        4'b0101: out = f;
        4'b0110: out = g;
        4'b0111: out = h;
        4'b1000: out = i;
        default: out = 16'hffff;
      endcase
    end
endmodule
256 to 1 multiplexer**

创建一个1位宽256对1的多路复用器。256个输入都被打包成一个256位的输入向量。
Sel =0选择[0]中的位,Sel =1选择[1]中的位,Sel =2选择[2]中的位,以此类推。

module top_module( 
    input [255:0] in,
    input [7:0] sel,
    output out );
    assign out = in[sel];
endmodule
256 to 1 4bit multiplexer***

创建一个4位宽256对1的多路复用器。256个4位输入都被打包成一个1024位输入向量。
Sel =0应该选择[3:0]中的位,Sel =1选择[7:4]中的位,Sel =2选择[11:8]中的位,等等。.

module top_module( 
    input [1023:0] in,
    input [7:0] sel,
    output [3:0] out );
    assign out = in[(sel+1)*4-1 -: 4];
    //assign out = in[(sel+1)*4-1 -: 4*sel]; 这样不通过编译,不能两端是变量
endmodule

Arithmetic circuits 运算电路

half adder
module top_module( 
    input a, b,
    output cout, sum );
    assign {cout,sum} = a + b;
endmodule
full adder
module top_module( 
    input a, b, cin,
    output cout, sum );
    assign {cout,sum} = a + b + cin;
endmodule
100bit binary adder ***
module top_module( 
    input [99:0] a, b,
    input cin,
    output cout,
    output [99:0] sum );
    assign {cout,sum} = a + b + cin;
endmodule
3-bit binary adder

创建3个实例来创建一个3位二进制波纹进位加法器。
加法器将两个3位数字和一个进位相加以产生3位和并执行。
为了鼓励您实际实例化完整加法器,还需要在波纹进位加法器中输出每个完整加法器的进位。
Cout[2]是最后一个完整加法器的最后一个执行结果,是您通常看到的执行结果。

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

    assign {cout[0],sum[0]} = a[0] + b[0] + cin;
    assign {cout[1],sum[1]} = a[1] + b[1] + cout[0];
    assign {cout[2],sum[2]} = a[2] + b[2] + cout[1];
endmodule
adder ***

在这里插入图片描述

module top_module (
    input [3:0] x,
    input [3:0] y, 
    output [4:0] sum);
    wire cout0,cout1,cout2;
    assign {cout0,sum[0]} = x[0] + y[0];
    assign {cout1,sum[1]} = x[1] + y[1] + cout0;
    assign {cout2,sum[2]} = x[2] + y[2] + cout1;
    assign {sum[4],sum[3]} = x[3] + y[3] + cout2;
 endmodule
signed addition overflow***

假设你有两个8位2的补码数,a[7:0]和b[7:0]。这些数字相加得到s[7:0]。还要计算是否发生了(带符号的)溢出。
当两个正数相加得到负数,或者两个负数相加得到正数时,就会发生有符号溢出。
有几种方法可以检测溢出: 可以通过比较输入和输出数字的符号来计算溢出,也可以通过执行位n和n-1来计算溢出。
两个正数相加符号位变成了1表示溢出,两个负数相加符号位变成了0表示溢出。

module top_module (
    input [7:0] a,
    input [7:0] b,
    output [7:0] s,
    output overflow
); 
   assign s = a + b;
   assign overflow = (a[7] & b[7] & ~s[7]) | (~a[7] & ~b[7] & s[7]);
endmodule
4 digit BCD adder***
module bcd_fadd (
    input [3:0] a,
    input [3:0] b,
    input     cin,
    output   cout,
    output [3:0] sum );

实例化 4 个bcd_fadd模块以创建 4 位 BCD 纹波携带加法器。加法器应添加两个 4 位 BCD 数字(打包成 16 位向量)和进位值,以生成 4 位总和并执行。

module top_module ( 
    input [15:0] a, b,
    input cin,
    output cout,
    output [15:0] sum );
    
    wire cout1, cout2, cout3;
    bcd_fadd inst1(a[3:0], b[3:0], cin, cout1, sum[3:0]);
    bcd_fadd inst2(a[7:4], b[7:4], cout1, cout2, sum[7:4]);
    bcd_fadd inst3(a[11:8], b[11:8], cout2, cout3, sum[11:8]);
    bcd_fadd inst4(a[15:12], b[15:12], cout3, cout, sum[15:12]);

endmodule

karnaugh map 卡诺图 to circuit

3-variable

在这里插入图片描述

module top_module(
    input a,
    input b,
    input c,
    output out  ); 
    assign  out = b | c | a;
endmodule
4-variable

在这里插入图片描述

module top_module(
    input a,
    input b,
    input c,
    input d,
    output out  );
    assign out = (~b & ~c) | (~a & ~d) | (a&c&d) | (b&c&d);
endmodule

在这里插入图片描述
对d不care,就成功了?

module top_module(
    input a,
    input b,
    input c,
    input d,
    output out  ); 
    assign out = (~b&c) | (a&c) | (a&~d);
    or assign out = (a&~c&~d)|(~b&c)|(a&b&c); ???
endmodule

在这里插入图片描述

module top_module(
    input a,
    input b,
    input c,
    input d,
    output out  );
    wire a1, a2, a3, a4;
    assign a1 = (a&b) | (~a & ~b);
    assign a2 = (~c&d) | (c&~d);
    assign a3 = (c&d) | (~c & ~d);
    assign a4 = (~a&b) | (a&~b);
    assign out = a1&a2 | a3&a4;
endmodule
karnaugh map

d is don’t-care,
在这里插入图片描述

module top_module (
    input [4:1] x, 
    output f );
    assign f = (x[1]&x[2]&~x[3]&x[4]) | (~x[1] & x[3]);
endmodule
k-map implemented with a multiplexer

在这里插入图片描述
在这里插入图片描述

module top_module (
    input c,
    input d,
    output [3:0] mux_in
); 
    assign mux_in[0] = c | d;
    assign mux_in[1] = 'd0;
    assign mux_in[2] = ~d;
    assign mux_in[3] = c & d;
endmodule
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值