Verilog基础学习三

一、基础门电路(Basic Gate)

1.gate

或非门

out = ~(in1 | in2)  //或非门

与门(in2取反)

out = in1 & (~in2);   //一个与门,但输入in2需要取反。

在这里插入图片描述

	wire temp;
    assign temp = in1 ^~ in2;
    assign out = temp ^ in3;  // 一个异或门,一个同或门
  • out_and: a and b
  • out_or: a or b
  • out_xor: a xor b
  • out_nand: a nand b
  • out_nor: a nor b
  • out_xnor: a xnor b
  • out_anotb: a and-not b
 assign out_and = a & b;
    assign out_or  = a | b;
    assign out_xor = a ^ b;
    assign out_nand = ~(a & b);
    assign out_nor = ~(a | b);
    assign out_xnor = ~(a ^ b);
    assign out_anotb = a & (~b);

2.真值表

​ 从真值表合成电路,且仅限使用一组标准逻辑门,将如何构建电路呢?
在这里插入图片描述
​ 本解析采用最小项之和的方法来构建电路图,最小项表达式为真值表中每一个对应函数值为1的输入变量,将上图真值表中函数值为1的最小项取出相加,便是函数最小项表达式。

上图最小项表达式为:
在这里插入图片描述
在这里插入图片描述

assign f = (!x3 & x2) | (x3 & x1);

3.关于电路设计思路

硬件电路的编程与软件的变成是存在差异的,一般进行软件编程时,我们是先关注输入( if (input are _)),再关注输出( then (output are ))。而在硬件编程时,我们需要转变思维方式,在确保输出是正确的情况下,再思考输入。( The (output should be _) when (inputs are __))。

能够思考和转换两种风格是硬件设计所需的最重要技能之一。
例:Ring or vibrate
在这里插入图片描述
本题所述的要求十分适合以软件编程的命令形式来编写程序( if ring then do this ),所以我们需要试着来转变思维,用硬件的设计思路来编写该程序( assign ringer = )。

 	assign motor = ring & vibrate_mode;
    assign ringer  = ring & (!vibrate_mode);

4.门电路与向量

例:problem 58 有一个4bit输入的电路,我们需要了解4bit输入数据之间的关系。

  • out_both: 输入的每一个bit均需要检测该bit位与其左侧(即高比特位)是否全为 ‘ 1 ’ 。 示例: out_both[2]应检测in[2]in[3] 是否均为 ‘ 1 ’ 。因为in[3]为输入的最高位,故我们无需检测out_both[3]
  • out_any: 输入的每一个bit均需要检测该bit位与其右侧(即低比特位)两者其中一个为 ‘ 1 ’ 。 示例:out_any[2]应检测in[2]in[1] 两者其中一个为 ‘ 1 ’ 。因为in[0]为输入的最低位,故我们无需检测out_any[0]
  • out_different: 输入的每一个bit均需要检测该bit位与其左侧(即高比特位)两者是否不同。 示例:
    out_different[2]应检测in[2]in[3] 两者是否不同。在本节中,我们将输入变成一个环,所以in[3]的左侧为in[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      = {{in[3] & in[2]}, {in[2] & in[1]}, {in[1] & in[0]}};
    assign out_any       = {{in[3] | in[2]} , {in[2] | in[1]} , {in[1] | in[0]}};
    assign out_different = {{in[0] ^ in[3]}, {in[3] ^ in[2]}, {in[2] ^ in[1]}, {in[1] ^ in[0]}};

endmodule

例:problem 59 有一个100bit( input [99:0] )输入的电路,我们需要了解4bit输入数据之间的关系。

  • out_both输出是判断现有bit位与其左侧bit位是否均为 ‘1’,可以采用移位运算(片选)来实现
  • out_any输出是判断现有bit位与右侧bit位两者间是否有一个为‘1’,也采用移位运算
  • out_different输出同理,判断现有bit位与左侧bit位是否不同,唯一需要注意的是在此输出中题目要求将输入变为一个环,将in[0]与 in[99] 链接在一起了,此处可采用链接符 { in[0], in[99:1] }。该输出同样采用移位运算。
    assign out_both = in[98:0] & in[99:1];
    assign out_any  = in[99:1] | in[98:0];
    assign out_different = in ^ {in[0],in[99:1]};

二、多路选择器(multiplexer)

1. 2-to-1 multiplexer (Mux2to1)

在这里插入图片描述

module top_module( 
    input in1, in2, sel,
    output out );   
   		 assign out = (sel) ? in1 : in2;
endmodule

2. 9-to-1 multiplexer (Mux9to1v)

 always @(*)begin
        case(sel)
            4'd0:out = a;
            4'd1:out = b;
            4'd2:out = c;
            4'd3:out = d;
            4'd4:out = e;
            4'd5:out = f;
            4'd6:out = g;
            4'd7:out = h;
            4'd8:out = i;
            default:out=16'hffff;
        endcase
    end

3. 256-to-1 multiplexer (Mux256to1)

这里我们可以根据题目的要求,结合选择运算符的特性实现。根据提示:选择运算符的 index 可以为变量,只要变量的位宽和向量的长度匹配即可。
所以我们直接将 sel ,这个变量,作为片选向量 in 的 index。

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

	// Select one bit from vector in[]. The bit being selected can be variable.
	assign out = in[sel];
        //assign out = in >> sel;
	
endmodule

4. 256-to-1 4-bit multiplexer (Mux256to1v)

同上一题的区别在于,位宽从 1 位变到了 4 位。

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

本题如果延续上一题的思考方式: assign out = in[ sel*4+3 : sel*4 ]; 但这个表达式不符合 Verilog 片选操作符的语法。片选多个比特的正确语法有两种:

  • assign out = in[sel*4 +: 4];// 从 sel*4 开始,选择比特序号大于sel*4 的 4 位比特,相当于[sel*4+3:sel*4]

  • assign out = in[sel*4+3 -: 4]; // 从 sel4+3 开始,选择比特序号小于 sel4+3 的 4位比特,相当于[sel*4+3:sel*4]

  • 当然本身 in[ sel*4+3 : sel*4 ] 这样的语法是不能使用。

三、运算电路(Arithmatic Circuits)

1.半加器 Half adder (Hadd)

实现一个 2 进制 1bit 加法器,加法器将输入的两个 1bit 数相加,产生两数相加之和以及进位。

module top_module( 
    input a, b,
    output cout, sum );
    assign {cout,sum} = a + b;
endmodule

使用位连接符语法,省去显示的变量信号声明。
本题也可以先声明一个 2bit 宽度的变量用于接收相加的结果以及可能的进位,2 个 1bit 数相加可能产生一个 2bit 宽度的结果。将高位赋予 cout,低位赋予 sum。

2.全加器 Full adder (Fadd)

全加器与半加器的区别在于,除了将输入的两个 1bit 数相加之外,还累加来自前级的进位,产生相加之和以及进位。

module top_module( 
    input a, b, cin,
    output cout, sum );
    assign{cout,sum} = a + b + cin;
endmodule

一般全加器才是数字系统中广泛使用的加法器。这里的 1bit 全加器往往会并行构成更宽的全加器。

3.三位二进制加法器 3-bit binary adder(Adder3 )

本题中需要通过实例化 3 个全加器,并将它们级联起来实现一个位宽为 3 bit 的二进制加法器,加法器将输入的两个 3bit 数相加,产生相加之和以及进位。

module top_module( 
    input [2:0] a, b,
    input cin,
    output [2:0] cout,
    output [2:0] sum );
	
    adder U1(
        .a(a[0])
        ,.b(b[0])
        ,.cin(cin)
        ,.cout(cout[0])
        ,.sum(sum[0])
    );
    adder U2(
        .a(a[1])
        ,.b(b[1])
        ,.cin(cout[0])
        ,.cout(cout[1])
        ,.sum(sum[1])
    );
    adder U3(
        .a(a[2])
        ,.b(b[2])
        ,.cin(cout[1])
        ,.cout(cout[2])
        ,.sum(sum[2])
    );
endmodule

module adder( 
    input a, b, cin,
    output cout, sum );
    assign{cout,sum} = a + b + cin;
endmodule

4.有符号数相加溢出 Signed addition overflow

本题讨论的是有符号数相加的溢出问题中,需要实现一个 2 进制 8bit 有符号数加法器,加法器将输入的两个 8bit数补码相加,产生相加之和以及进位。

a[7] && b[7] && ~s[7]:
负数相减(补码相加)产生正数,判断溢出。
~a[7] && ~b[7] && s[7]:
正数相加产生一个负数,判断溢出。

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

5.100bit的二进制的加法器

题目要求我们创建一个100bit的二进制的加法器,该电路共包含两个100bit的输入和一个cin, 输出产生sum和cout。
本题和之前需要用generate语句的题目很类似

module top_module( 
    input [99:0] a, b,
    input cin,
    output cout,
    output [99:0] sum );
    
    //直接相加赋值也可以
    //assign {cout,sum} = a+b+cin;  
    
    wire [99:0] cout_temp;
    //初始化第一个实例
    full_adder fadd1(
        .a(a[0]),
        .b(b[0]),
        .cin(cin),
        .cout(cout_temp[0]),
        .sum(sum[0])
    );
    genvar i ;
    //循环生成99个实例
    generate 
        for(i=1;i<100;i=i+1)
            begin:genadder
              full_adder fadd(
                  .a(a[i]),
                  .b(b[i]),
                  .cin(cout_temp[i-1]),
                  .cout(cout_temp[i]),
                  .sum(sum[i])
              );  
            end
    endgenerate
    assign cout = cout_temp[99];

endmodule

module full_adder( 
    input a, b, cin,
    output cout, sum );
    assign {cout,sum} = a+b+cin;
endmodule

5.4-digit BCD adder

题目给我们提供了一个BCD加法器名字为bcd_fadd, 输入为两个4bitBCD码,一个cin,产生输出为sum和cout。
且题目也说明需要我们例化4次bcd_fadd来得到一个4-digit的BCD加法器(共16bit), 同样产生sum和cout。

module bcd_fadd {
    input [3:0] a,
    input [3:0] b,
    input     cin,
    output   cout,
    output [3:0] sum );
module top_module( 
    input [15:0] a, b,
    input cin,
    output cout,
    output [15:0] sum );
    
    wire [3:0] cout_temp;
    //实例化4个bcd_fadd
    bcd_fadd U1(
        .a(a[3:0]),
        .b(b[3:0]),
        .cin(cin),
        .cout(cout_temp[0]),
        .sum(sum[3:0])
    );
    
    bcd_fadd U2(
        .a(a[7:4]),
        .b(b[7:4]),
        .cin(cout_temp[0]),
        .cout(cout_temp[1]),
        .sum(sum[7:4])
    );
    
    bcd_fadd U3(
        .a(a[11:8]),
        .b(b[11:8]),
        .cin(cout_temp[1]),
        .cout(cout_temp[2]),
        .sum(sum[11:8])
    );
    
    bcd_fadd U4(
        .a(a[15:12]),
        .b(b[15:12]),
        .cin(cout_temp[2]),
        .cout(cout_temp[3]),
        .sum(sum[15:12])
    );
    
    assign cout = cout_temp[3];
endmodule

四、卡诺图转化电路(Karnaugh Map to Circuits)

1.卡诺图基础(Karnaugh Map)

最小项

最小项的定义:一个函数的某个乘积项包含了函数的全部变量,其中每个变量都以原变量或反变量的形式出现,且仅出现一次,则这个乘积项称为该函数的一个标准积项,通常称为最小项。

最小项的表示方法:通常mi用来表示最小项。

下标i的确定方式:把最小项中原变量记为1,反变量记为0,当变量顺序确定后,可以按顺序排列成一个二进制数,则与这个二进制数相对应的十进制数,就是这个最小项的下标i。

最小项的的相邻性:任何两个最小项如果他们只有一个因子不同,其余因子都相同,则称这两个最小项为相邻最小项相邻的两个最小项之和可以合并一项,消去一个变量。 如:
在这里插入图片描述

卡诺图

  1. 一种描述逻辑函数特殊方格图。
  2. 每格代表一个最小项,上下左右相邻就具备相邻性。
  3. 有n个变量,最小项就有2^n 且卡诺图也由 2^n个格子构成。

例:画出逻辑函数的卡诺图(四变量)
在这里插入图片描述
解:
在这里插入图片描述

化简卡诺图

卡诺图相邻性的特点保证了几何相邻两方格所代表的最小项只有一个变量不同。因此,若相邻的方格都为1(简称1格)时,则对应的最小项就可以合并。合并的结果是消去这个不同的变量,只保留相同的变量。这是图形化简法的依据。

综上所述,卡诺图具备以下特性:

卡诺图中两个相邻1格的最小项可以合并成一个与项,并消去一个变量。
卡诺图中四个相邻1格的最小项可以合并成一个与项,并消去两个变量。
卡诺图中八个相邻1格的最小项可以合并成一个与项,并消去三个变量。
————————————————
版权声明:本文为CSDN博主「Samplay」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/hahasusu/article/details/88244155
例子

选择圈很重要

  1. 列出逻辑函数的最小项表达式,由最小项表达式确定变量的个数(如果最小项中缺少变量,应补齐)。
  2. 画出最小项表达式对应的卡诺图。
  3. 将卡诺图中的1格画圈,一个也不能漏圈,否则最后得到的表达式就会与所给函数不等;1格允许被一个以上的圈所包围。
  4. 圈的个数应尽可能得少。即在保证1格一个也不漏圈的前提下,圈的个数越少越好。因为一个圈和一个与项相对应,圈数越少,与或表达式的与项就越少。
  5. 按照2k个方格来组合(即圈内的1格数必须为1,2,4,8等),圈的面积越大越好。因为圈越大,可消去的变量就越多,与项中的变量就越少。
  6. 每个圈应至少包含一个新的1格,否则这个圈是多余的。 用卡诺图化简所得到的最简与或式不是唯一的。

————————————————
版权声明:本文为CSDN博主「Samplay」的原创文章,遵循CC 4.0BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/hahasusu/article/details/88244155
更多示例点击以上链接学习

2.卡诺图电路(Karnaugh Map Circuits)

1) 3-variable

请添加图片描述

  assign out = a | b | c;

2) 4-variable

请添加图片描述

 assign out = ~b&~c | ~a&~d | a&c&d | ~a&b&c;

3) 4-variable2

请添加图片描述

  • 其中D为don’t care值。相当于X。可以一起圈。
assign out = a | (~b&c);  

4) Minimum SOP and POS

  • SOP(Sum of Product,最小项表达式(与或式):积之和) 最小项之和
  • POS(Product of Sum,最大项表达式(或与式):和之积) 最大项之积

一个4输入a, b, c, d和一输出的逻辑电路,当输入为2, 7或15时,输出为1, 当输入为0, 1, 4, 5, 6, 9, 10,13, 或 14 时,输出为0,当输入为3,8,11或12时输出为任意值。举例来说,7对应输入abcd为0,1,1,1.

注意: 该电路的SOP和POS必须均为化简后的最小值
在这里插入图片描述

SOP圈法如下:
请添加图片描述

assign out_sop = c&d | ~a&~b&c ;

SOP圈法如下:
在这里插入图片描述

pos:最大项之积选择0或者d圈,圈法规则与最小项之和一致。圈完后进行取反求和,最后不同的圈进行求积操作

assign out_pos = c & (~a | b) & (~b | d);

5) K-map implemented with a multiplexer

根据题目给出的卡诺图,用一个4-1的多路选择器和尽可能多的2-1多路选择器来实现电路,不允许使用其他逻辑门,必须使用ab作为选择器的输入。

在这里插入图片描述
在这里插入图片描述
从图中所示,在ab为某一固定值的情况下,根据cd的输入不同,来选择输出。

例如当ab == 2’b00时, mux_in[0] 根据卡诺图所示应为 c | d,

当ab == 2’b01时, mux_in[1] 根据卡诺图所示为1’b0 ,

此处需注意mux_in[3:0], 一个高位低位的问题,不要搞反了。

module top_module (
    input c,
    input d,
    output [3:0] mux_in
); 

    assign mux_in = {(c&d),(~d),1'b0, (c|d)};

endmodule

总结

学习了基础门电路,掌握了基础门电路的用法。

学习了多路选择器,在位宽较小的多路选择器中,我们可以使用 assign 语句,三元表达式,case 语句等。在位宽较宽的多路选择器中,需要根据需求灵活地使用位选择符,如in[sel*4+3 -: 4]或者位连接符。

学习了运算电路,全加器是数字系统中广泛使用的加法器, 1bit 全加器往往会并行构成更宽的全加器。进一步掌握实例化模块和generate语句的使用。

学习了卡诺图,掌握了卡诺图的原理和化简卡诺图的方法(SOP和POS),但是运用不是很熟练,在今后使用中会加深学习。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值