问题
I have a wire called input and I want to detect the number of leading I am trying to create a module which uses the case statement below to change the output data depending on the number of leading zeros. However the size of the input is parameterizable.
If X was a fixed value of 4, I would just create a case statement,
case (input)
4'b0001 : o_data = {i_data[0]};
4'b001x : o_data = {i_data[1],1'b0};
4'b01xx : o_data = {i_data[2],2'b0};
4'b1xxx : o_data = {i_data[3],3'b0};
default : o_data = 4'b0000;
endcase
But with variable X, how do I define all cases?
This question is similar to this one: How to define a parameterized multiplexer using SystemVerilog
回答1:
You can't really parameterize a case
statement like that, but you can use a for
loop instead:
module lead_detector #(parameter int WIDTH = 4) (
input logic[WIDTH - 1:0] in,
output logic[WIDTH - 1:0] out
);
always_comb begin
out = '0;
for (int i = WIDTH - 1; i >= 0; i--)
if (in[i] == 1'b1) begin
out[i] = 1;
break;
end
end
endmodule
This is the kind of code I see my designers write all the time (albeit in VHDL), but it should be synthesizable.
回答2:
The OP is trying to design some sort of parametrized priority encoder, if I have understood well. I've come with this design that synthesizes well
module priority_encoder #(parameter WIDTH=4) (
input wire [WIDTH-1:0] i, // input data
input wire [WIDTH-1:0] c, // input control
output reg [WIDTH-1:0] o // output data
);
// Deal with the most significant bit case apart
always @* begin
if (c[WIDTH-1]==1'b1)
o[WIDTH-1] = i[WIDTH-1];
else
o[WIDTH-1] = 1'b0;
end
// Deal with the rest of bits
genvar idx;
generate
for (idx = WIDTH-2; idx >=0; idx = idx-1) begin :gen_cases
always @* begin
if (c[idx]==1'b1 && c[WIDTH-1:idx+1]=='b0)
o[idx] = i[idx];
else
o[idx] = 1'b0;
end
end
endgenerate
endmodule
The testbench module I've created for this design is as follows:
module tb_prioencoder;
parameter WIDTH=3;
// Inputs
reg [WIDTH-1:0] i;
reg [WIDTH-1:0] c;
// Outputs
wire [WIDTH-1:0] o;
// Instantiate the Unit Under Test (UUT)
priority_encoder #(WIDTH) uut (
.i(i),
.c(c[WIDTH-1:0]),
.o(o)
);
initial begin
i = {WIDTH{1'b1}};
c = {WIDTH{1'b0}};
repeat (2**WIDTH) begin
#10;
c = c + 1;
end
end
endmodule
Which leads me to this chronogram (for WIDTH
= 3):

回答3:
The case statement cannot be parameterized like that. A for loop as others mentioned is a good solution for your problem.
Here is a different solution: if you were looking to solve the reverse problem, i.e., finding the leading 1 from the right side, you could just bitwise-and in
with its two's complement. Therefore, for finding the leading 1 from left, you can first bit-reverse in
, bitwise-and it with its two's complement, and then bit-reverse the result:
logic [X - 1:0] reverse_in, reverse_out;
always_comb
begin
reverse_in = { << {in} }; //Bit-reverse of input (using stream operator)
reverse_out = (~(reverse_in) + 1) & reverse_in; //And with two's complement
out = { << {reverse_out} }; //Bit-reverse of output
end
In synthesis, bit reversing does not have any cost since it is just rewiring.
来源:https://stackoverflow.com/questions/29313913/how-to-parameterize-a-case-statement-with-dont-cares