• HDL-Bits 刷题记录 01


    Always块

    Procedures (比如always) 为描述电路提供另一种语法:
    always@(*)
    always@(posedge clock)
    always 块内部代码的语法与外部的不懂,有更丰富的语句集,如 if-then,case 不能包含连续赋值

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

    对于组合的 always 块,始终使用( * )的敏感度列表。明确列出信号很容易出错(如果你错过了一个),并且在硬件综合时会被忽略。如果您明确指定灵敏度列表并错过了一个信号,则合成硬件的行为仍将与指定( * )一样,但模拟不会也不匹配硬件的行为。(在 SystemVerilog 中,使用always_comb。)
    关于 wire 与 reg 的注意事项:assign 语句的左侧必须是net类型(例如,wire),而过程赋值(在 always 块中)的左侧必须是变量类型(例如,reg)。这些类型(wire vs. reg)与合成的硬件无关,只是 Verilog 用作硬件模拟语言时留下的语法。

    alwaysblock1

    两个方式写 AND 与门

    Verilog 中有三种类型的赋值:

    • 连续赋值(assign x = y;)。只能在不在过程中使用(“总是阻塞”)。
    • 程序块分配:( x = y; )。只能在程序内部使用。
    • 程序非阻塞赋值:( x <= y; )。只能在程序内部使用。

    在组合的always 块中,使用块分配。在时钟控制的always 块中,使用非阻塞分配。

    alwaysblock2

    //使用三种方式实现XOR

    Always if

    两种方式实现二选一数字选择器

    Always if2

    避免产生锁存器

    Always case

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

    Always case2

    4位优先级编码器,从低位开始,先是1的位置被输出

    Always casez

    如果 case 语句中的 case 项支持“忽略”位,这就是z的情况:它在比较中将具有值z的位视为不关心。
    可以这样实现上一个练习中的 4 输入优先级编码器:

    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 语句的行为就好像每个项目都是按顺序检查的(实际上是一个很大的组合逻辑函数)。多个项都符合时候,会优先匹配第一个匹配项。
    还有一个类似的casex将x和z都视为无关。
    符号?是z的同义词。所以2’bz0和2’b?0一样
    明确指定优先级行为而不是依赖于案例项目的顺序可能不太容易出错。如下:

    casez  ( in [ 3 : 0 ]) 
      4'bzzz1:  ... 
      4'bzz10:  ... 
      4'bz100:  ... 
      4'b1000 :  ...
      default:  ... 
    endcase
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    本题为实现一个8位的优先编码器

    Always nolatches

    下面的代码风格可以确保在所有可能的情况下为输出分配一个值(0),除非 case 语句覆盖了分配。这可以在没有default: 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

    conditional

    Verilog 有一个三元条件运算符 ( ? : )
    eg:
    (0 ? 3 : 5) // 这是 5,因为条件为假。
    (sel ? b : a) // 由 sel 选择的 a 和 b 之间的 2 对 1 多路复用器。

    always @(posedge clk) // 一个 T 型触发器
    q <= toggle ? ~q : q;
    assign out = ena ? q : 1’bz; // 一个三态缓冲区
    ((sel[1:0] == 2’h0) ? a : // 3 对 1 多路复用器
    (sel[1:0] == 2’h1) ? b :
    c )

    四个数求最小值

    Reduction

    创建一个对一个向量的所有位进行操作的逻辑
    归约运算符可以对向量的位进行 AND、OR 和 XOR,产生一位输出:

    & a[3:0] // 与:a[3]&a[2]&a[1]&a[0]。相当于 (a[3:0] == 4'hf)
    | b[3:0] // 或:b[3]|b[2]|b[1]|b[0]。相当于 (b[3:0] != 4'h0)
    ^ c[2:0] // 异或:c[2]^c[1]^c[0]
    
    • 1
    • 2
    • 3

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

    奇偶校验

    Gates100

    100个与 或 异或 门

    Vector100r

    100bit向量 反转顺序

    Popcount255

    255个人计数

    Adder100i

    例化100个全加器,generate for 语句 或者实例化数组

    //加法器级联 (实例化数组版本)
    module add(
        input                           a,
        input                           b,
        input                           cin,
        output                          cout,
        output                         sum
    );
    
    always @(*) begin
        sum  = a + b +cin;
        cout = ((a|b)&cin)||((cin|b)&a)||((a|cin)&b);
    end
    endmodule
    module top_module( 
        input [99:0] a, b,
        input cin,
        output [99:0] cout,
        output [99:0] sum );
        reg [99:0] cout1 = 99'd0;
    // assign cout = cout1[99];
    assign cout = cout1;
    add add1[99:0](
        .a(a[99:0]),
        .b(b[99:0]),
        .cin({cout1[98:0],cin}),
        .cout(cout1[99:0]),
        .sum(sum[99:0])
    );
    endmodule## Bcdadd100
    
    • 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

    利用例化100个bcd_fadd的 BCD 一位加法器
    生成100位的bcd

    Circuits

    Combinational 逻辑

    7420

    两个四通道与非门

    Truthtable1

    真值表画卡诺图写assign

    Mt2015 eq2

    A=B时候输出1否则输出0

    Mt2015 q4a

    模块 A 应该实现函数z = (x^y) & x。实现这个模块。

    module top_module (input x, input y, output z);
        assign z = (x^y) & x;
    endmodule
    
    • 1
    • 2
    • 3

    Mt2015 q4b

    模块实现异或非

    module top_module ( input x, input y, output z );
        assign z = ~(x^y);
    endmodule
    
    • 1
    • 2
    • 3

    Mt2015 q4

    使用Mt2015 q4a和Mt2015 q4b的模块生成如下逻辑
    Mt2015_q4.png

    Ringer

    当接到电话时。,您的电路必须打开振铃器 ( ) 或电机 ( ),但不能同时打开两者。如果手机处于振动模式 ( ),请打开电机。否则,打开铃声。

    module top_module (
        input ring,
        input vibrate_mode,
        output ringer,       // Make sound
        output motor         // Vibrate
    );
    	assign motor = ring&vibrate_mode;
      assign ringer = ring&(~vibrate_mode);    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Thermostat

    加热/冷却恒温器控制加热器(冬季)和空调(夏季)。实施一个可以根据需要打开和关闭加热器、空调和鼓风机的电路。

    恒温器可以处于以下两种模式之一:加热 ( mode = 1) 和冷却 ( mode = 0)。在制热模式下,当天气太冷时打开加热器(too_cold = 1),但不要使用空调。在制冷模式下,空调过热时打开空调(too_hot = 1),但不要打开加热器。当加热器或空调打开时,还要打开风扇以循环空气。此外,fan_on = 1即使加热器和空调已关闭,用户也可以请求打开风扇 (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 = mode&too_cold;
        assign aircon = (~mode)&(too_hot);
        assign fan =  mode&too_cold|(~mode)&(too_hot)|fan_on;
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Popcount3

    “人口计数”电路计算输入向量中“1”的数量。为 3 位输入向量构建人口计数电路。

    module top_module( 
        input [2:0] in,
        output [1:0] out );
        assign out = in[0]+in[1]+in[2];
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Gatesv

    在 [3:0] 中给定一个四位输入向量。我们想知道每个位与其相邻位的一些关系:

    out_both:此输出向量的每个位都应指示相应的输入位及其左侧的邻位(较高的索引)是否都是“1” 。例如,out_both[2]应该表明in[2]和in[3]是否都为 1。由于in[3]左边没有邻居,所以答案很明显,所以我们不需要知道out_both[3 ]。
    out_any:此输出向量的每个位应指示相应的输入位及其右侧的邻居是否为“1”。例如,out_any[2]应该指示in[2]或in[1]是否为 1。由于in[0]右侧没有邻居,因此答案很明显,因此我们不需要知道out_any[0 ]。
    out_different:此输出向量的每个位都应指示相应的输入位是否与其左侧的邻居不同。例如,out_diff[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_different [3] = in[3]^in[0];
    genvar i;
        generate for (i =0;i<3 ;i++) 
        begin: both       
            assign out_both[i] = in[i+1]&in[i];
            assign out_any[i+1] = in[i]|in[i+1];
            assign out_different [i] = in[i+1]^in[i];
        end
    endgenerate
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Gatesv100

    逻辑和Gatesv一致,门扩充成了100个 ,改下角标即可

    Mux2to1

    二选一数选,sel=0, a. sel=1, b.

    module top_module( 
        input a, b, sel,
        output out ); 
        assign out = (sel)?b:a;
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Mux9to1v

    sel=0 chooses a, sel=1 chooses b,9:15所有输出都置1

    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)
      16'h00: out = a;
      16'h01: out = b;
      16'h02: out = c;
      16'h03: out = d;
      16'h04: out = e;
      16'h05: out = f;
      16'h06: out = g;
      16'h07: out = h;
      16'h08: out = i;
      default: out = 16'hff;
      endcase
    end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Mux256to1

    256选一 数选

    //256选一数选
    module top_module( 
        input [255:0] in,
        input [7:0] sel,
        output out );
        assign out = in[sel];
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Mux256to1v

    256*4选4

    module top_module( 
        input [1023:0] in,
        input [7:0] sel,
        output [3:0] out );
        assign out[3:0] = in[sel*4+:8];// sel*4开始向上取8位,verilog不支持上下都是变量,所以要这么写
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Hadd

    半加器,没cin

    module top_module( 
        input a, b,
        output cout, sum );
        assign sum = a+b;
        assign cout = a&b;
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Fadd

    全加器

    module top_module( 
        input a, b, cin,
        output cout, sum );
        assign cout = (a&b)|(b&cin)|(a&cin);
        assign sum = a+b+cin;
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Adder3

    三位全加器

    module adder( 
        input a, b, cin,
        output cout, sum );
        assign cout = (a&b)|(b&cin)|(a&cin);
        assign sum = a+b+cin;
    endmodule
    module top_module( 
        input [2:0] a, b,
        input cin,
        output [2:0] cout,
        output [2:0] sum );
        // wire [2:0]cout1 ;
        adder add[2:0](
            .a(a[2:0]),
            .b(b[2:0]),
            .cout(cout[2:0]),
            .cin({cout[1:0],cin}),
            .sum(sum[2:0])
        );
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Adder

    实现加法器
    m2014_q4j.png

    module adder( 
        input a, b, cin,
        output cout, sum );
        assign cout = (a&b)|(b&cin)|(a&cin);
        assign sum = a+b+cin;
    endmodule
    module top_module (
        input [3:0] x,
        input [3:0] y, 
        output [4:0] sum);
        wire [3:0] cout;
        assign sum[4] = cout[3];
        adder add[3:0](
            .a(x[3:0]),
            .b(y[3:0]),
            .cout(cout[3:0]),
            .cin({cout[2:0],1'b0}),
            .sum(sum[3:0])
        );
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    ece241_2014_q1c

    s = a+b ,overflow是溢出位
    8位有符号位最高是符号位 ,所以需要确定什么时候算溢出
    两个正数相加,肯定是第9位为1时候溢出
    两个负数相加,也是第9位为1
    一正 一负,那就是,是不是不可能溢出

    module top_module (
        input [7:0] a,
        input [7:0] b,
        output [7:0] s,
        output overflow
    ); //
        wire signed [7:0] a1;// = a;
        wire signed [7:0] b1;// = b;
        wire signed [7:0] s1;
        assign a1 = a;
        assign b1 = b;
        assign s1 =  a+b;
        assign s =  a+b;
        assign overflow = (((a1>0)&&(b1>0)&&(s1<0))||((a1<0)&&(b1<0)&&(s1>0)))?1:0;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Adder100

    Bcdadd4

    4位bcd相加
    给了一个Bcd_fadd,写一个四位的
    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 );
        reg [3:0] cout1; 
        assign cout = cout1[3];
        bcd_fadd bcd[3:0](
            .a(a[15:0]),
            .b(b[15:0]),
            .cin({cout1[2:0],cin}),
            .cout(cout1[3:0]),
            .sum(sum[15:0])
        );
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    从这里开始说是要介绍卡诺图

    卡诺图化简

    我觉得他瞧不起我

    module top_module(
        input a,
        input b,
        input c,
        output out  ); 
        assign out = b |((~b)&c) |(a&(~b)&(~c));
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    卡诺图02
    module top_module(
        input a,
        input b,
        input c,
        input d,
        output out  ); 
        assign out = ((~a)&(~b)&(~c))|((~a)&(~d)&(c))|((d)&(b)&(c))|((a)&(~b)&(d))|((~a)&(b)&(~c)&(~d))|((a)&(~b)&(~c)&(~d));
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    卡诺图3
    module top_module(
        input a,
        input b,
        input c,
        input d,
        output out  ); 
        assign out = a|((~a)&(~b)&(c));
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    卡诺图4

    对角线卡诺图 如下
    Kmap4.png

    module top_module(
        input a,
        input b,
        input c,
        input d,
        output out  ); 
    	assign out = a^b^c^d;
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    卡诺图5 SOP POS

    SOP: 划1
    POS: 划0

    module top_module (
        input a,
        input b,
        input c,
        input d,
        output out_sop,
        output out_pos
    ); 
        assign out_sop = (c&d)|((~a)&(~b)&(c)&(~d));
        assign out_pos = ~((~c)|((a)&(c)&(~d))|((b)&(c)&(~d)));
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    卡诺图6 m2014 q3

    m2014_q3.png

    module top_module (
        input [4:1] x, 
        output f );
        assign f = ((~x[1])&x[3])|((x[2])&(~x[3])&x[4]);
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    卡诺图7 2012 q1g
    module top_module (
        input [4:1] x,
        output f
    ); 
        assign f = (~x[1])&x[3]|x[3]&(x[1])&(x[2]^~x[4])|(~x[2])&(~x[3])&(~x[4]);
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    卡诺图8

    ece241_2014_q3.png

    module top_module (
        input c,
        input d,
        output [3:0] mux_in
    ); 
        assign mux_in[0] = c|d;
        assign mux_in[1] = 1'b0;
        assign mux_in[2] = ~d;
        assign mux_in[3] = c&d;
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    时序逻辑

    latches and Flip-Flops

    latches:锁存器
    Flip-Flops:触发器
    二者区别:
    锁存器,是由电平触发,面积比ff小,速度比ff快,电平触发,非同步设计,受布线延迟影响较大,很难保证输出没有毛刺产生,latch将静态时序分析变得极为复杂
    触发器,是时钟边沿触发,可存储1bitdata,是register的基本组成单位,同步设计,不容易受毛刺的印象,时序分析简单,面积比latch大,消耗的门电路比latch多
    锁存器在ASIC设计中应该说比ff要简单,但是在FPGA的资源中,大部分器件没有锁存器这个东西,所以需要用一个逻辑门和ff来组成锁存器,这样就浪费了资源。
    锁存器比FF快,所以用在地址锁存是很合适的,不过一定要保证所有的latch信号源的质量,锁存器在CPU设计中很常见,正是由于它的应用使得CPU的速度比外部IO部件逻辑快许多。latch完成同一个功能所需要的门较触发器要少,所以在asic中用的较多。

    Dff

    写一个D 触

    module top_module (
        input clk,    // Clocks are used in sequential circuits
        input d,
        output reg q );//
    
        // Use a clocked always block
        //   copy d to q at every positive edge of clk
        //   Clocked always blocks should use non-blocking assignments
        always@(posedge clk) begin
        	q <= d;
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    Dff8

    写一个8D触,输入定义变化,always内代码同上。

    Dff8r
    module top_module (
        input clk,
        input reset,            // Synchronous reset
        input [7:0] d,
        output [7:0] q
    );
        always@(posedge clk ) begin
        	if(reset)
                q <= 8'b0;
            else 
                q <= d;
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    Dff8p

    下降沿触发的8d触 ,复位值为0x34

    module top_module (
        input clk,
        input reset,
        input [7:0] d,
        output [7:0] q
    );
        always@(negedge clk ) begin
        	if(reset)
                q <= 8'h34;
            else 
                q <= d;
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    Dff8ar

    8 D FF,High reset 异步复位 上升沿触发

    module top_module (
        input clk,
        input areset,   // active high asynchronous reset
        input [7:0] d,
        output [7:0] q
    );
        always@(posedge clk ,posedge areset) begin
        	if(areset)
                q <= 8'b0;
            else
                q <= d;
        end    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    React(react18)中组件通信03——简单使用 Context 深层传递参数
    Django模版层
    做好QA质量管理,4大注意事项和技巧。
    记一次 .NET某炉膛锅炉检测系统 崩溃分析
    使用three.js(webgl)搭建智慧楼宇、设备检测、数字孪生——第十三课
    Spring(SpringBoot)--解决拦截器中注入Bean失败的问题
    拓世法宝AI智能直播一体机,快速搭建品牌矩阵,开启扩张新里程
    如何使用Java反射机制运行类中指定方法呢?
    ActiveMq学习⑨__基于zookeeper和LevelDB搭建ActiveMQ集群
    java#5(数组)
  • 原文地址:https://blog.csdn.net/qq_31764341/article/details/126829322