• HDLbits exercises 3 (procedures节选题)


    目录

    1\  ALWAYS IF

    2\  ALWAYS IF2

    3\  ALWAYS CASE

    4\  ALWAYS CASE2

    5\  ALWAYS NOLATCHES


    1. 预备知识点:
    2. always块有两种形式,一种是括号里是*,另一种是有posedge和nagedge的,其中前者用于组合逻辑电路,后者用于时序逻辑电路。
    3. 【阻塞赋值 vs 非阻塞赋值】
    4. verilog中有三种赋值方式:
    5. 连续赋值(assign x=y;),只能在always块外使用。
    6. 阻塞赋值(x=y;),只能在always块内使用。
    7. 非阻塞赋值(x<=y;)只能在always块内使用。
    8. 在组合逻辑的always块中(always @(*))使用阻塞赋值语句;
    9. 在时序逻辑的always块中(always @(posedge clk))使用非阻塞赋值语句。

    1\  ALWAYS IF

    Build a 2-to-1 mux that chooses between a and b. Choose b if both sel_b1 and sel_b2 are true. Otherwise, choose a. Do the same twice, once using assign statements and once using a procedural if statement.

    CORRECT:
    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&sel_b2)
                    begin
                        out_always<=b;
                    end
                else
                    out_always<=a;
            end
        
    endmodule

    HINT:

    2\  ALWAYS IF2

    如何避免在使用if语句时生成锁存器?

    tip:锁存器与触发器的区别?

    锁存器是一种对脉冲电平(也就是0或者1)敏感的存储单元电路,而触发器是一种对脉冲边沿(即上升沿或者下降沿)敏感的存储电路。
    当我们在设计电路时,不能直接先写成代码然后期望它直接生成为合适的电路,如下典型错误所示:

    If (cpu_overheated) then shut_off_computer = 1;
    If (~arrived) then keep_driving = ~gas_tank_empty;
    语法上正确的代码并不意味着设计成的电路也是合理的。我们来思考这么一个问题,如上图的错误示例,如果if条件不满足,输出如何变化呢?Verilog给出的解决方法是:保持输出不变。因为组合逻辑电路不能记录当前的状态,所以就会综合出锁存器。

    所以当我们使用if语句或者case语句时,我们必须考虑到所有情况并给对应情况的输出进行赋值,就意味着我们要为else或者default中的输出赋值。

    CORRECT:

    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

    HINT:

    这个题有点意思,是让你纠正bug的题。题目的初衷就是让你用if或者case语句的时候一定要把所有情况都列出来,别写得跟“无头厉鬼”似的,让人摸不着头脑。

    3\  ALWAYS CASE

    Case statements are more convenient than if statements if there are a large number of cases. So, in this exercise, create a 6-to-1 multiplexer. When sel is between 0 and 5, choose the corresponding data input. Otherwise, output 0. The data inputs and outputs are all 4 bits wide.

    Be careful of inferring latches

    ERRO:

    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)
                    1'd0:out=data0;
                    1'd1:out=data1;
                    1'd2:out=data2;
                    1'd3:out=data3;
                    1'd4:out=data4;
                    1'd5:out=data5;
                    1'd6:out=0;
                    1'd7:out=0;
                    default:out=0;

            endcase
        end

    endmodule
     

    CORRECT:

    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

    HINT:

    既然前面都定义是4位的data信号了,就别非得用十进制秀了。。。。

    4\  ALWAYS CASE2

    Build a 4-bit priority encoder. For this problem, if none of the input bits are high (i.e., input is zero), output zero. Note that a 4-bit number has 16 possible combinations.

    CORRECT1:

    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'b0011:pos=0;
                    4'b0100:pos=2;
                    4'b0101:pos=0;
                    4'b0110:pos=1;
                    4'b0111:pos=0;
                    4'b1000:pos=3;
                    4'b1001:pos=0;
                    4'b1010:pos=1;
                    4'b1011:pos=0;
                    4'b1100:pos=2;
                    4'b1101:pos=0;
                    4'b1110:pos=1;
                    4'b1111:pos=0;
                    default:pos=0;
                endcase
            end
    endmodule 

    CORRECT2:

    module top_module (
        input [3:0] in,
        output reg [1:0] pos  );
        always @(*) begin
            case(1)
                in[0]:pos = 0;
                in[1]:pos = 1;
                in[2]:pos = 2;
                in[3]:pos = 3;
                default:pos = 0;

            endcase
        end
    endmodule

    CORRECT3:

    module top_module (
        input [3:0] in,
        output reg [1:0] pos  );
    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
    endmodule

    HINT:

    Using hexadecimal (4'hb) or decimal (4'd11) number literals would save typing vs. binary (4'b1011) literals.

    优先编码器是一种组合电路,当给定输入位向量时,输出该向量中第一个1的位置。 例如,给定输入8’b10010000的8位优先级编码器将输出3’d4,因为bit [4]是高的第一位。

    构建一个4位优先级编码器。 对于此问题,如果所有输入位都不为高(即输入为零),则输出零。 请注意,一个4位数字具有16种可能的组合。
    CORRECT1不好,因为它不适用情况多的项目;其他两种比较简洁方便。

    5\  ALWAYS NOLATCHES

    假设构建一个电路来处理游戏的PS/2键盘上的扫描代码。对于收到的最后两个字节的扫描码,我们需要指示是否按下了键盘上的一个方向键。这涉及到一个相当简单的映射,它可以实现为一个case语句(或if-elseif),包含四个case。

    电路有一个16位输入和四个输出。建立能识别这四种扫描码并正确输出的电路。

    ERRO:

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

                endcase
            end
    endmodule
     

    CORRECT:

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

    HINT:

    case语句中的default不能有多个只能有一个,但是为避免生成锁存器,所有的输入情况必须要被考虑到。但仅有一个简单的default是不够的,我们必须在case item和default中为4个输出进行赋值,这会导致很多不必要的代码编写。

    一种简单的方式就是对输出先进行赋初值的操作,这种类型的代码确保在所有可能的情况下输出都被赋值,除非case语句覆盖了赋值。这也意味着不再需要缺省的default项。

  • 相关阅读:
    一个用python PyQT写的背单词小程序
    Simulink电机控制代码生成-----关于PI控制器参数整定的一点总结
    杯子出口欧洲需要做哪些检测认证?
    【OpenCV学习】第5课:图像模糊(均值滤波,高斯滤波)
    OpenVPN安装部署详解
    进程间通信
    Numpy学习笔记
    相机镜头选择与机器视觉控制
    怎么制作流程图?介绍制作方法
    Leetcode刷题167. 两数之和 II - 输入有序数组
  • 原文地址:https://blog.csdn.net/weixin_48304306/article/details/126807677