当前位置:   article > 正文

HDLBits_Verilog学习笔记(to be continued)_hdlbits显示error (297009)

hdlbits显示error (297009)

HDLBits_Verilog学习笔记(to be continued)



There are some HDLBits practices.


Verilog Language

Procedures

Alwaysblock1

由于数字电路由导线连接的逻辑门组成,任何电路都可以表示为一些模块的组合和赋值语句。然而,有时这并不是描述电路最方便的方式。过程(always块就是一个例子)提供了描述电路的另一种语法。
对于硬件综合,两种类型的always块是相关的:

  • 组合电路:always @(*)
  • 时序电路:always @(posedge clk)

组合always块等价于赋值语句,因此总有一种方法可以用这两种方式来表示组合电路。选择使用哪一种主要是哪一种语法更方便的问题。注意:过程块内部的代码语法与外部的代码不同 。过程块有更丰富的语句集(例如,if-then, case),不能包含连续赋值,但也引入了许多新的非直观的出错方式。(程序性连续作业确实存在,但与连续作业有所不同)。
例如,赋值和组合always块描述同一电路。两者都创造了相同的组合逻辑。当任何一个输入(右边)改变值时,两者都会重新计算输出。

	assgin out1 = a & b | c^ d;
	always @(*)
		out2 = a & b | c ^ d;
  • 1
  • 2
  • 3

对于组合的always块,始终使用(*)的敏感信号列表。显式地列出信号很容易出错(如果漏掉一个),并且在硬件综合时被忽略。如果你显式地指定了灵敏度列表,但漏了一个信号,综合硬件仍然会像(*)被指定一样工作,但是仿真模拟将不会也不匹配硬件的行为。(在SystemVerilog中,使用always_comb)。
关于wire和reg的注释: assign语句的左侧必须是net类型(例如wire),而过程赋值语句(在always块中)的左侧必须是变量类型(例如reg)。这些类型(wire vs. reg)与所综合的硬件没有任何关系,只是Verilog作为硬件模拟语言使用时留下的语法。

练习

使用赋值语句和组合的always块构建AND门。(由于赋值语句和组合块总是相同的功能,没有办法强制你使用这两个方法。但你是来练习的,对吧?(让你都是实现一遍))。

// synthesis verilog_input_version verilog_2001
module top_module(
    input a, 
    input b,
    output wire out_assign,
    output reg out_alwaysblock
);
		assign out_assign = a & b;
    always @(*)
        begin
            out_alwaysblock = a & b;
        end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

assign,连续赋值,就是无条件全等,对象为wire类型;alyways 就是敏感赋值,有条件相等,对象为reg,敏感信号列表,电平触发时,综合为组合电路,边沿触发时,才综合为时序电路。

Alwaysblock2

对于综合电路,两种类型always模块总是相关联的:


  • 组合电路:always @(*)
  • 时序电路:always @(posedge clk)

时序always块创建一团组合逻辑,就像组合always块一样,但也在一团组合逻辑的输出上创建一组触发器(或“寄存器”)。一团逻辑块的输出不能立即可见,而是只在下一个(posedge clk)之后的输出可见。(a blob of :一系列,团,块;不能详细定义形容的整体)。

阻塞 VS 非阻塞 赋值语句

Verilog中存在的三种赋值语句:


  • 连续赋值(assign x = y;):只能用在always块外
  • 阻塞性赋值(x = y;):用于(initial or always)程序语句内部,在赋值时,先计算等号右手部分的值,再赋值给左边变量,直到该语句赋值完成,后面的语句才能执行,会阻塞后面的语句。(顺序执行)
  • 非阻塞性赋值(x <= y;): 用于(initial or always)程序语句内部,执行赋值语句右边,然后将begin-end之间的所有赋值语句同时赋值到赋值语句的左边,但是左边的变量的值不会立即更新,直到always块所有语句执行完,才将左边变量的值更新。

注意


  • 在描述组合逻辑的always 块中用阻塞赋值,则综合成组合逻辑的电路结构。
  • 在描述时序逻辑的always 块中用非阻塞赋值,则综合成时序逻辑的电路结构。

在一个组合always块中,使用阻塞赋值。在时序always块中,使用非阻塞赋值。充分理解Verilog模拟器如何跟踪事件对硬件设计是特别有用的。如果不遵循这一规则,将很难找到仿真和合成硬件之间的不确定性和不同的错误。

练习

用三种方法构建异或门,使用赋值语句、组合always块和时序always块。请注意,时钟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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
Always if

if条件语句相当于一个二选一选择器,eg:

always @(*) begin
    if (condition) begin
        out = x;
    end
    else begin
        out = y;
    end
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果条件为真输出if下的,为假输出其他的;这相当于条件预算符下的连续赋值:

	assign out = (condition) ? x : y;
  • 1

然而,过程赋值if条件语句中有新的一种错误,只有输出有赋值的时候才能综合成组合电路。

练习

构建一个2-to-1多路选择器,在a和b之间进行选择。如果sel_b1和sel_b2都为true,则选择b。否则,选择a。重复同样的操作两次,一次使用assign语句,一次使用过程性if语句。

module top_module(
    input a,
    input b,
    input sel_b1,
    input sel_b2,
    output wire out_assign,
    output reg out_always   ); 
    
    assign out_assign = (sel_b1 & sel_b2)? b : a;
    
    always @(*)
        begin
            if (sel_b1 == 1'b1 & sel_b2 == 1'b1)
            begin 
                out_always = b;
            end
    	else
            begin
                out_always = a;
            end
        end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
Always if2

普遍性错误:怎么避免锁存器?

在设计电路时,你必须首先从电路的角度考虑:

  • 我想设计一个逻辑门
  • 我想设计一系列组合逻辑的输入输出
  • 我想设计一系列通过许多触发器的组合逻辑输入输出

你不能做的是先写代码,然后希望它生成一个合适的电路。

  • If (cpu_overheated) then shut_off_computer = 1;
  • If (~arrived) then keep_driving = ~gas_tank_empty;

语法正确的代码不一定会产生合理的电路(组合逻辑+触发器)。通常的理由是:“在你指定的那些情况之外会发生什么?”Verilog的回答是:保持输出不变。(???问号脸)这种“保持输出不变”的行为意味着需要记住当前的状态,从而产生一个锁存器。组合逻辑(例如,逻辑门)不能记住任何状态。小心警告(10240):除非锁存器是故意的,否则它几乎总是表明有故障。组合电路必须为所有条件下的所有输出分配一个值。这通常意味着您总是需要为输出分配可选择子句或默认值。

演示

以下代码包含创建锁存器的不正确行为。修复bug,只有当电脑过热时你才会关掉它,当你到达目的地或需要加油时就停止开车。

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)
            begin
           shut_off_computer = 1;
            end //give every selection the begin ~ end ,that nice coding style
        else
            begin
                shut_off_computer = 0;
                shut_off_computer = shut_off_computer;
            end
        
    end

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

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
Always case

Verilog中的Case语句几乎等价于一个if-elseif-else序列,它将一个表达式与其他表达式的列表进行比较。它的语法和功能与C语言中的switch语句不同。

  • 没有关键字:switch ,以case 开始,冒号结束
  • 每个case只能执行一个语句,如需要多个,请以begin-end包含
  • 可以有两个完全一样的case标签,但是使用第一个,C语言不允许这样做
  • 多个case用逗号隔开,执行最后一个冒号后的语句

练习

如果选择项多,case语句比if语句更方便。因此,在这个练习中,创建一个6:1的多路选择器。当sel在0到5之间时,选择相应的数据输入。否则,输出0。数据输入和输出都是4位宽。

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 = 4'b0000;
        endcase
    end

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
ALways case2

优先编码器是一种组合电路,当给定一个输入位向量时,输出该位向量的前1位的位置。例如,给定输入8’b10010000的8位优先级编码器将输出3’d4,因为位[4]是第一个高的位。
构建一个4位优先编码器。对于这个问题,如果没有一个输入位是高的(即,输入为零),输出为零。注意,4位数字有16种可能的组合。

module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
    always @(*)
        begin
    case (in)
        	4'b0011, //3
            4'b0101, //6
            4'b0111, //7
            4'b1001, //9
            4'b1011, //11
            4'b1101, //13
            4'b1111, //15
            4'b0001: //1
            pos = 2'd0;
               // pos = 2'd1;
        	4'b0010, //2
            4'b0110, //6
            4'b1010, //10
            4'b1110: //14
                 pos = 2'd1;
                4'b1100, //12
                4'b0100: //4
                    pos = 2'd2;
                    4'b1000: //8
                    	pos = 2'd3;
        default:
            pos = 2'd0;
    endcase
        end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

Always cacez

对于八位的case,将会有256种可能,但如果case语句支持忽略位,将能减少到九种。什么是casez:字节比对时,对于Z的位忽略:

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

case语句时逐项循序检查,但存在一项对应多个输出,但第一项case项会有输出,后面项目不执行


  • casex和casez类似
  • 巴拉巴拉·····

练习
module top_module (
    input [7:0] in,
    output reg [2:0] pos  );
    always @(*)
        begin
            casez(in)
                8'bzzzzzzz1:
                    pos = 0;
                8'bzzzzzz1z:
                    pos = 1;
                8'bzzzzz1zz:
                    pos = 2;
                8'bzzzz1zzz:
                    pos = 3;
                8'bzzz1zzzz:
                    pos = 4;
                8'bzz1zzzzz:
                    pos = 5;
                8'bz1zzzzzz:
                    pos = 6;
                8'b1zzzzzzz:
                    pos = 7;
                default:
                    pos = 0;
            endcase
        end

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

Always nolactches

假设你正在为一款游戏构建一个处理PS/2键盘扫描代码的电路。给定接收到的扫描码的最后两个字节,您需要指出是否按了键盘上的一个箭头键。这涉及到一个相当简单的映射,可以用一个case语句(或if-elseif)实现,有四种情况。

Scancode[16:0]arrow key
16’he06bleft arrow
16’he072down arrow
16’he074right arrow
16’he075up arrow
anything elsenone

你的电路有一个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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这种代码风格确保输出在所有可能的情况下都被赋值(0),除非case语句覆盖了赋值。这也意味着默认的: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;right = 1'b0;up = 1'b0;down = 1'b0;
    case(scancode)
            16'he06b:
            	left = 1'b1;
            16'he072:
            	down = 1'b1;
            16'he074:
            	right = 1'b1;
            16'he075:
            	up = 1'b1;
            default:
            	;//can without case ouput satement
            endcase
        end
            	
        
endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

Conditonal ternary operator

verilog也有和C语言类似的条件操作符:?

练习

给定四个无符号数,求最小值。无符号数可以与标准的比较运算符(a < b)进行比较。使用条件运算符构造两路最小电路,然后再组合成四路最小电路。你可能需要一些线向量来得到中间结果。

module top_module (
    input [7:0] a, b, c, d,
    output [7:0] min);//

    // assign intermediate_result1 = compare? true: false;
    assign min = (((a<b)?a:b)<((c<d)?c:d))?((a<b)?a:b):((c<d)?c:d);

endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
Reduction

你已经熟悉了两个值之间的位运算,例如,a & b或a ^ b。有时,你想创建一个宽的门来操作一个向量的所有位,比如(a[0] & a[1] & a[2] & a[3]…),如果向量很长,这就很乏味了。
归约运算符可以对向量的位进行与运算、或运算和异或运算,产生1位输出:

& 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]
  • 1
  • 2
  • 3

这些是只有一个操作数的一元操作符(类似于NOT操作符!和~)。你也可以反转这些输出来创建NAND, NOR和XNOR门,例如(~& d[7:0])。

练习

奇偶校验经常被用来作为一种简单的检测错误的方法,当通过一个不完美的通道传输数据。创建一个电路,将计算一个8位字节的奇偶校验位(这将为字节添加第9位)。我们将使用“偶”奇偶校验,其中奇偶校验位就是所有8个数据位的异或

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
Reduction :Even wider gates

整一个有以下三种输出的,100种输入的组合逻辑:


  • out_and:100输入的与门
  • out_or:100输入的或门
  • out_xor:100输入的异或门

归约操作符包括:归约与(&),归约与非(&),归约或(|),归约或非(|),归约异或(),归约同或(~)。归约操作符是单目操作符号,它对这个向量操作数逐位操作,最终产生一个 1bit 结果。逻辑操作符、按位操作符和归约操作符都使用相同的符号表示,因此有时候容易混淆。区分这些操作符的关键是分清操作数的数目,和计算结果的规则。

练习
	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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
Combinational for-loop:Vector reversal 2

给出一个100bit的向量,然后翻转以下(用for循环解决)

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

endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
Combinational for-loop 255-bit population count

搞一个输入信号向量中为1的计数器,就是在循环中带条件判断

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

    always @(*)
        begin
          out = 0;
            for(integer i = 0 ; i < 255 ; i = i + 1)
                begin 
                    if(in[i] == 1'b1)
                        begin 
                            out = out + in[i];
                        end
                    else
                        begin
                            out = out + in[i];
                        end
                end
  
        end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
Generate for-loop: 100-bit binary adder 2

通过实例化100个全加法器来创建一个100位二进制循环进位加法器。加法器将两个100位的数和一个进位数相加,得到一个100位的和并进位。为了鼓励您实际实例化全加法器,还输出循环进位加法器中每个全加法器的输出。Cout[99]是最后一个完整的加法器的最后一个执行量,也是你经常看到的执行量。

练习
module top_module( 
    input [99:0] a, b,
    input cin,
    output [99:0] cout,
    output [99:0] sum );
    
    assign cout[0] = a[0] & b[0] | a[0] & cin | b[0] & cin; //luo ji dai shu shi zui jian
    
    assign sum[0]  = a[0] ^ b[0] ^ cin;
    
     integer i;
    
     always @ (*)
         begin
             for (i=1; i<100; i = i + 1)
             begin
                 cout[i] = a[i] & b[i] | a[i] & cout[i-1] | b[i] & cout[i-1];
                 sum[i]  = a[i] ^ b[i] ^ cout[i-1];
         end
     end

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

Generate for-loop:100-digit BCD adder

提供一个bcd_fadd 的一位BCD码加法器,做两个BCD码和进位的加法,最后输出总和以及进位:

module bcd_fadd (
    input [3:0] a,
    input [3:0] b,
    input     cin,
    output   cout,
    output [3:0] sum );
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

实例化100个bcd_fadd,创建100位BCD循环进位加法器。你的加法器应该将两个100位的BCD数字被压缩成400位的向量)和一个进位相加,得到一个100位的和并进位。


  1. 若两个BCD码之和小于等于1001,不需要修正
  2. 若在10-15间,需要向高位进位,同时进行加6修正,进位是在加6时修正产生
  3. 若之和在16-18间,向高位进位会在相加过程中产生,对本位还要加6修正

练习
module top_module( 
    input [399:0] a, b,
    input cin,
    output cout,
    output [399:0] sum );
    
    wire [399: 0] cout_t;
    
    bcd_fadd fadd(.a(a[3:0]),.b(b[3:0]),.cin(cin),.cout(cout_t[0]),.sum(sum[3:0]));
    
    //all cout_t assign to cout,but inimadtied first,so have 396
    
    assign cout = cout_t[396];
    //generate one time, Instantiate one 
    generate
        genvar i;
        for(i = 4; i < 400; i=i+4) 
            begin : add
              bcd_fadd fadd(.a(a[i+3:i]), .b(b[i+3:i]), .cin(cout_t[i-4]), .cout(cout_t[i]),.sum(sum[i+3:i]));
             end
    endgenerate
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

Circuits

Combiantional Logic

Basic Gates
Wire

实现以下电路:


in ———— out


练习
module top_module (
    input in,
    output out);
		assign out = in; //combinational logic use blocking assignment
endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
GND

实现以下电路:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tdbeq21Z-1651335732619)(https://hdlbits.01xz.net/mw/images/5/54/Exams_m2014q4i.png)]


练习
module top_module (
    output out);
	assign out = 1'b0;
endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
NOR

实现下图电路:



就是实现一个或非门

练习
module top_module (
    input in1,
    input in2,
    output out);
    assign out = !(in1 || in2); //output is 1bit
    assign out = ~(in1 | in2);//output is same as input width
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意逻辑运算符号与按位运算符号的区别

Another gate

实现下图电路:



对输入信号in2取反后的与门

练习
module top_module (
    input in1,
    input in2,
    output out);
    assign out = in1 && (!in2);
    //assign out = in1 & (~in2);

endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
Two gates

实现下图电路:


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QLV7s8Hs-1651335732622)(https://hdlbits.01xz.net/mw/images/e/e6/Exams_m2014q4g.png)]


in1/2信号先同或,结果再和in3异或,^~^,是互补运算,Verilog中只有按位的模式

练习
module top_module (
    input in1,
    input in2,
    input in3,
    output out);
    assign out = in3 ~^ (in1 ^ in2);
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
More logic gates

试着同时构建几个逻辑门。建立一个有两个输入a和b的组合电路。
有7个输出,每个输出都有一个逻辑门驱动:

  • out_and:a and b
  • out_or:a or b
  • out_xor:a or b
  • out_nand: a nand b
  • out_nor: a nor b
  • out_xnor: a xnor b
  • out_anotb: a and-nt b

练习
module top_module( 
    input a, b,
    output out_and,
    output out_or,
    output out_xor,
    output out_nand,
    output out_nor,
    output out_xnor,
    output out_anotb
);
	assign out_and = a && b;//a & b;
    assign out_or  = a || b;//a | b;
    assign out_xor = a ^ b;
    assign out_nand = !(a && b); //~(a & b);
    assign out_nor = !(a || b);//(~(a | b));
    assign out_xnor = a ~^ b;//~(a ^ b);
    assign out_anotb = a && !b;//a & (~b);
endmodule

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
7420 chip

7400系列集成电路是一系列数字芯片,每个芯片有几个门。7420是一个带有两个4输入NAND门的芯片。
创建一个功能与7420芯片相同的模块。它有8个输入和2个输出。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0AjK3a3a-1651335732622)(https://hdlbits.01xz.net/mw/images/4/48/7420.png)]


练习
module top_module ( 
    input p1a, p1b, p1c, p1d,
    output p1y,
    input p2a, p2b, p2c, p2d,
    output p2y );
    assign p1y = ~(p1a & p1b & p1c & p1d);
    assign p2y = !(p2a & p2b & p2c & p2d);

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
Truth tables

在前面的练习中,我们使用了简单的逻辑门和几个逻辑门的组合。这些电路是组合电路的例子。组合意味着电路的输出是其输入的函数(在数学意义上)。这意味着对于任何给定的输入值,只有一个可能的输出值。因此,描述组合函数行为的一种方法是显式列出输入的每个可能值的输出。这是真值表。
对于一个有N个输入的布尔函数,有2n 种可能的输入组合。真值表的每一行列出一个输入组合,所以总有2n行。输出列显示每个输入值的输出应该是什么。

rowinputsoutputs
numberx3x2x1f
00000
10010
20101
30111
41000
51012
61100
71111

上面的真值表适用于一个三输入一输出函数。对于8种可能的输入组合,每一种都有8行,还有一个输出列。有四种输出为1的输入组合,以及四种输出为0的输入组合。


根据真实表综合电路
假设我们想要构建上面的电路,但是我们被限制只能使用一组标准逻辑门。如何构建任意逻辑函数(表示为真值表)?
实现真值表功能的电路的一个简单方法是将真值表的功能表示为积和形式。乘积的和(意为或)意味着在真值表的每一行使用一个n输入与门(用来检测输入是否匹配每一行),然后是一个或门,它只选择那些输出为“1”的行。
对于上面的例子,如果输入匹配第2行或第3行或第5行或第7行,则输出为’1’(这是一个4输入or门)。如果x3=0, x2=1, x1=0,则输入匹配第2行(这是一个3输入and门)。因此,这个真值表可以通过使用4个或的与门来实现。(数字电路部分内容,不会的,单独补课吧的

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/802721?site
推荐阅读
相关标签