1.4.8避免生成锁存器
假设你正在为一个游戏构建一个电路,用于处理来自PS/2键盘的扫描码。根据接收到的最后两个字节的扫描码,你需要判断键盘上的某个箭头键是否已被按下。这涉及到一个相当简单的映射,可以通过带有四个情况的case语句(或if-elseif)来实现。
Scancode [15:0] | Arrow key |
---|---|
16'he06b | left arrow |
16'he072 | down arrow |
16'he074 | right arrow |
16'he075 | up arrow |
Anything else | none |
你的电路有一个16位输入,以及四个输出。构建这个电路,以识别这四个扫描码并正确地触发相应的输出。
为了避免产生锁存器,所有输出在所有可能的条件下都必须被赋予一个值(参见1.4.4 always_if2)。仅仅有一个default case是不够的。你必须在这四个case和default case中为所有四个输出分配一个值。这可能涉及大量的冗余输入。解决这个问题的一个简单方法是在case语句之前为输出分配一个"默认值":
always @(*) begin
up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
case (scancode)
... // Set to 1 as necessary.
endcase
end
这种编码风格确保了在所有可能的情况下输出都被赋予了一个值(0),除非case语句覆盖了这个赋值。这也意味着default: 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 );