【HDLBits刷题】【Procedures】Always nolatches

这篇博客介绍了如何使用Verilog编写电路来处理PS/2键盘的扫描码,特别是识别箭头键的按下。通过一个16位输入和四个输出,实现了简单的状态映射,避免了锁存器的使用。代码中展示了两种方法,一种是为每个输出分配默认值,另一种是为每种情况明确指定输出值。这两种方法都确保了所有输出在所有条件下都有定义,且不需默认案例。
摘要由CSDN通过智能技术生成

Suppose you're building a circuit to process scancodes from a PS/2 keyboard for a game. Given the last two bytes of scancodes received, you need to indicate whether one of the arrow keys on the keyboard have been pressed. This involves a fairly simple mapping, which can be implemented as a case statement (or if-elseif) with four cases.

Scancode [15:0]Arrow key
16'he06bleft arrow
16'he072down arrow
16'he074right arrow
16'he075up arrow
Anything elsenone

Your circuit has one 16-bit input, and four outputs. Build this circuit that recognizes these four scancodes and asserts the correct output.

To avoid creating latches, all outputs must be assigned a value in all possible conditions (See also always_if2). Simply having a default case is not enough. You must assign a value to all four outputs in all four cases and the default case. This can involve a lot of unnecessary typing. One easy way around this is to assign a "default value" to the outputs before the case statement:

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

This style of code ensures the outputs are assigned a value (of 0) in all possible cases unless the case statement overrides the assignment. This also means that a default: case item becomes unnecessary.

Reminder: The logic synthesizer generates a combinational circuit that behaves equivalently to what the code describes. Hardware does not "execute" the lines of code in sequence.

 为避免创建锁存器,必须在所有可能的条件下为所有输出分配一个值。仅仅有一个默认情况是不够的。您必须为所有四种情况和默认情况下的所有四个输出分配一个值。这可能涉及大量不必要的输入。解决此问题的一种简单方法是在 case 语句 之前为输出分配一个“默认值” :

// synthesis verilog_input_version verilog_2001
module top_module (
    input [15:0] scancode,
    output reg left,
    output reg down,
    output reg right,
    output reg up  ); 
    always@(*)
        begin
            up = 1'b0;  // 在之前设置默认值,就不需要写那么多得情况
            down = 1'b0; 
            left = 1'b0; 
            right = 1'b0;
            case(scancode)
                16'he06b: left = 1;
                16'he072: down = 1;
                16'he074: right = 1;
                16'he075: up = 1;
                default: ;  // default必须写,但是后面的可以省略
            endcase
        end

endmodule

 不然就得这样写,相对于上面的写法就复杂了一些:

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

endmodule

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值