问题33: Priority encoder(Always case2)
优先级编码器是一种组合电路,当给定输入位向量时,输出向量中第一个 1
位的位置。例如,给定输入 8'b10010000
的 8
位优先级编码器将输出 3'd4
,因为 bit[4]
是第一个高位。
构建一个 4
位优先级编码器。对于这个问题,如果没有输入位为高(即输入为零),则输出零。请注意,一个 4
位数字有 16
种可能的组合
// synthesis verilog_input_version verilog_2001 module top_module ( input [3:0] in, output reg [1:0] pos ); always@(*)begin casez(in) 4'bzzz1: begin pos = 2'b00; end 4'bzz1z: begin pos = 2'b01; end 4'bz1zz: begin pos = 2'b10; end 4'b1zzz: begin pos = 2'b11; end default: begin pos = 2'b00; end *斜体样式* endcase end endmodule
问题34: Priority encoder with casez(Always casez)
为 8 位输入构建优先级编码器。给定一个 8 位向量,输出应报告向量中的第一位为 1。如果输入向量没有高位,则报告零。例如,输入 8'b10010000 应该输出 3'd4,因为 bit[4] 是第一个高位
从之前的练习 (always_case2) 来看,case 语句中有 256 个案例。如果 case 语句中的 case 项支持 don’t-care 位,我们可以减少这个(减少到 9 个 case)
例如,这将实现上一个练习中的 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
case 语句的行为就好像每个项目都是按顺序检查的(实际上是一个很大的组合逻辑函数)。请注意某些输入(例如 4'b1111)如何匹配多个案例项目。选择第一个匹配项(因此 4’b1111 匹配第一项,out = 0,但不匹配后面的任何一项)。
明确指定优先级行为而不是依赖于案例项目的顺序可能不太容易出错。例如,如果某些 case 项被重新排序,以下内容的行为仍然相同,因为任何位模式最多只能匹配一个 case 项:
// synthesis verilog_input_version verilog_2001 module top_module ( input [7:0] in, output reg [2:0] pos ); always@(*) begin casez (in) 8'b zzzzzzz1:begin pos = 3'b 000; end 8'b zzzz_zz1z: begin pos = 3'b 001; end 8'b zzzz_z1zz: begin pos = 3'b 010; end 8'b zzzz_1zzz: begin pos = 3'b 011; end 8'b zzz1_zzzz: begin pos = 3'b 100; end 8'b zz1z_zzzz: begin pos = 3'b 101; end 8'b z1zz_zzzz: begin pos = 3'b 110; end 8'b 1zzz_zzzz: begin pos = 3'b 111; end default: begin pos = 3'b 000; end endcase end endmodule
问题35: Avoiding latches(Always nolatches)
假设您正在构建一个电路来处理来自游戏的 PS/2 键盘的扫描码。鉴于收到的扫描码的最后两个字节,您需要指出是否已按下键盘上的箭头键之一。这涉及到一个相当简单的映射,它可以实现为具有四个案例的案例语句(或 if-elseif)。
您的电路有一个 16 位输入和四个输出。构建识别这四个扫描码并断言正确输出的电路。
为避免创建锁存器,必须在所有可能的条件下为所有输出分配一个值(另请参见 always_if2)。仅仅有一个默认情况是不够的。您必须为所有四种情况和默认情况下的所有四个输出分配一个值。这可能涉及大量不必要的输入。解决此问题的一种简单方法是在 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 ); always@(*) begin up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0; case(scancode) 16'he06b:begin left = 1'b1; end 16'he072:begin down = 1'b1; end 16'he074:begin right = 1'b1; end 16'he075:begin up = 1'b1; end endcase end endmodule
此种方法,首先进行了赋值,这样是不会产生锁存,是一种较好的思维的方式,笔者可以尝试采用此方法进行对上面的问题进行实验验证。