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'he06b | left arrow |
16'he072 | down arrow |
16'he074 | right arrow |
16'he075 | up arrow |
Anything else | none |
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