我们可以使用case语句可扩展的语法吗? 让我用一个例子来解释:Mux
如果只有2条选择线
always @(A[1:0]) begin
case (A[1:0])
2'b00 : select = 4'b1110;
2'b01 : select = 4'b1101;
2'b10 : select = 4'b1011;
2'b11 : select = 4'b0111;
endcase
end
3条选择线
always @(A[2:0]) begin
case (A[2:0])
3'b000 : select = 8'b1111_1110;
3'b001 : select = 8'b1111_1101;
3'b010 : select = 8'b1111_1011;
3'b011 : select = 8'b1111_0111;
3'b100 : select = 8'b1110_1111;
3'b101 : select = 8'b1101_1111;
3'b110 : select = 8'b1011_1111;
3'b111 : select = 8'b0111_1111;
endcase
end
我的问题:
是否有一种编写代码的通用方法可以解决具有任意数量选择线的多路复用器? 2,3,4 ...
除了case语句之外,还有其他方法可以实现这个吗?
欢迎任何反馈。 问候
答案 0 :(得分:2)
如果是步行0的模式,你的后续如何:
localparam SHIFT_W = 3;
localparam OUT_W = 2**SHIFT_W;
reg [SHIFT_W-1:0] shift;
reg [OUT_W-1:0] out;
always_comb begin
out = ~(OUT_W'(1'b1 << shift));
end
根据nguthrie 的建议。移动以创建步行1,然后反转以创建步行0。
我的原始建议(有点冗长)使用SystemVerilog直接创建一个步行0:
localparam SHIFT_W = 3;
localparam OUT_W = 2**SHIFT_W;
reg [SHIFT_W-1:0] shift;
reg [OUT_W-1:0] out;
always_comb begin
out = OUT_W'( $signed{ 1'b1, 1'b0, {OUT_W{1'b1}} }) >>> (OUT_W-shift) );
end
WIDTH`()
投射到正确的宽度以停止LHS RHS宽度不匹配警告。
$signed()
投射到已签名的号码,以允许>>>
按符号扩展进行转换。这也可以写成:
out = OUT_W'( { {OUT_W{1'b1}}, 1'b0, {OUT_W{1'b1}} } >> (OUT_W-shift) );
对于Verilog-2001,您将获得LHS RHS宽度不匹配警告:
out = { {OUT_W{1'b1}}, 1'b0, {OUT_W{1'b1}} } >> (OUT_W-shift);
这已经消除了在轮班期间签名扩展的需要。
答案 1 :(得分:2)
由于给定的标准是二进制到一冷解码器,因此可以使用for循环。与位移位器相比,它的典型性为合成提供了更好的时序和面积;从我的经验来看。您应该进行自己的比较,因为它取决于您的标准单元库以及合成器的优化程度。
module bin2cold #(parameter WIDTH=4) (
output reg [2**WIDTH-1:0] cold,
input [ WIDTH-1:0] bin );
integer idx;
always @* begin
for(idx = 0; idx < 2**WIDTH; idx=idx+1) begin
cold[idx] = (bin != idx);
end
end
endmodule
答案 2 :(得分:1)
这将为您提供一个简洁的通用多路复用器,其中所有输入都聚合在一个名为in的向量中,然后它们在input_array中分开:
module mux #(parameter DW = 32,
parameter N = 2)
(
input [(DW*N)-1:0] in,
input [$clog2(N)-1:0] sel,
output logic [DW-1:0] out
);
genvar ig;
logic [DW-1:0] input_array [0:N-1];
assign out = input_array[sel];
//separating inputs
generate
for(ig=0; ig<N; ig=ig+1) begin: array_assignments
assign input_array[ig] = in[(ig*DW)+:DW];
end
endgenerate
endmodule
你想要的是有点不同,in的值已经知道并且可以在内部生成。因此,我的代码中的generate / endgenerate块可以被其他人描述的方法之一替换。
module mux #(parameter DW = 32,
parameter N = 2)
(
input [(DW*N)-1:0] in, //not used anymore
input [$clog2(N)-1:0] sel,
output logic [DW-1:0] out
);
genvar ig;
logic [DW-1:0] input_array [0:N-1];
assign out = input_array[sel];
generate
for(ig=0; ig<N; ig=ig+1) begin: array_assignments
assign input_array[ig] = ~( 2**ig );
end
endgenerate
endmodule
(不确定这是纯粹的Verilog还是SystemVerilog)