P
Przemek
Guest
I was musing what is a best simple, efficient and parametrizable
thermometer coder design pattern.
The simple but not easily parametrizable approach is to direct code
the logic using the case:
always @*
case(a)
0: x = 8'b0000_0001;
1: x = 8'b0000_0011;
2: x = 8'b0000_0111;
3: x = 8'b0000_1111;
4: x = 8'b0001_1111;
5: x = 8'b0011_1111;
6: x = 8'b0111_1111;
default: x = 8'b1111_1111;
endcase
The other approach suggested here:
http://groups.google.com/group/comp.arch/browse_thread/thread/158b5652984c77e5/8bd9ec4178c6bf74?hl=en&lnk=gst&q=thermometer#
Is to implement one-hot and convert to thermometer
1) Build n -> 2^n one-hot coder
always @*
begin
x= 0;
x[a] = 1'b1;
end
2) Convert one-hot to thermometer
x_therm = (x-1) | x;
I took challenge and coded for laughs a recursive thermometer scale
coder. (see below)
The design halves the input width on every call so it will converge
very fast.
I have done some synthesis tests to compare the area for some larger
output widths ((x width = 256)
The logic input and output are registered and synthesized at a
challenging 2ns clock period.
The recursive code synthesizes to a size slightly larger than one hot
coder.
The case statement code is about x2 bigger while the conversion method
resulted in more than x4 area of recursive code.
The conversion is not efficient because it results in subtractor of x
bits width.
In the case of case statement it seems that synthesis tool logic
optimizer gave up.
Any other ideas?
Cheers,
Przemek
Recursive generate thermometer coder:
module decoder_n_2n_therm_rec (
a,
x
);
parameter N=1;
// local params
parameter X_WIDTH = (1<<N);
parameter X0_WIDTH = (1<<(N>>1));
input [N-1:0] a;
output [X_WIDTH-1:0] x;
wire [X0_WIDTH-1:0] x_0;
wire [X0_WIDTH:0] x_1;
assign x_1[X0_WIDTH]=1'b0;
generate
genvar i0, i1;
if(N>1) begin : rec
decoder_n_2n_therm_rec
#(
..N(N>>1)
)
decoder_n_2n_therm_rec_0
(
..a(a[(N>>1)-1:0]),
..x(x_0)
);
decoder_n_2n_therm_rec
#(
..N(N>>1)
)
decoder_n_2n_therm_rec_1
(
..a(a[N-1N>>1)]),
..x(x_1[X0_WIDTH-1:0])
);
for(i0=0;i0<X0_WIDTH;i0=i0+1) begin : x0_loop
for(i1=0;i1<X0_WIDTH;i1=i1+1) begin : x1_loop
assign x[i1*X0_WIDTH + i0] = x_1[i1+1] | (~x_1[i1+1] & x_1[i1] & x_0
[i0]);
end
end
end
else begin : rec_end
assign x[0] = 1'b1;
assign x[1] = a[0];
end
endgenerate
endmodule
thermometer coder design pattern.
The simple but not easily parametrizable approach is to direct code
the logic using the case:
always @*
case(a)
0: x = 8'b0000_0001;
1: x = 8'b0000_0011;
2: x = 8'b0000_0111;
3: x = 8'b0000_1111;
4: x = 8'b0001_1111;
5: x = 8'b0011_1111;
6: x = 8'b0111_1111;
default: x = 8'b1111_1111;
endcase
The other approach suggested here:
http://groups.google.com/group/comp.arch/browse_thread/thread/158b5652984c77e5/8bd9ec4178c6bf74?hl=en&lnk=gst&q=thermometer#
Is to implement one-hot and convert to thermometer
1) Build n -> 2^n one-hot coder
always @*
begin
x= 0;
x[a] = 1'b1;
end
2) Convert one-hot to thermometer
x_therm = (x-1) | x;
I took challenge and coded for laughs a recursive thermometer scale
coder. (see below)
The design halves the input width on every call so it will converge
very fast.
I have done some synthesis tests to compare the area for some larger
output widths ((x width = 256)
The logic input and output are registered and synthesized at a
challenging 2ns clock period.
The recursive code synthesizes to a size slightly larger than one hot
coder.
The case statement code is about x2 bigger while the conversion method
resulted in more than x4 area of recursive code.
The conversion is not efficient because it results in subtractor of x
bits width.
In the case of case statement it seems that synthesis tool logic
optimizer gave up.
Any other ideas?
Cheers,
Przemek
Recursive generate thermometer coder:
module decoder_n_2n_therm_rec (
a,
x
);
parameter N=1;
// local params
parameter X_WIDTH = (1<<N);
parameter X0_WIDTH = (1<<(N>>1));
input [N-1:0] a;
output [X_WIDTH-1:0] x;
wire [X0_WIDTH-1:0] x_0;
wire [X0_WIDTH:0] x_1;
assign x_1[X0_WIDTH]=1'b0;
generate
genvar i0, i1;
if(N>1) begin : rec
decoder_n_2n_therm_rec
#(
..N(N>>1)
)
decoder_n_2n_therm_rec_0
(
..a(a[(N>>1)-1:0]),
..x(x_0)
);
decoder_n_2n_therm_rec
#(
..N(N>>1)
)
decoder_n_2n_therm_rec_1
(
..a(a[N-1N>>1)]),
..x(x_1[X0_WIDTH-1:0])
);
for(i0=0;i0<X0_WIDTH;i0=i0+1) begin : x0_loop
for(i1=0;i1<X0_WIDTH;i1=i1+1) begin : x1_loop
assign x[i1*X0_WIDTH + i0] = x_1[i1+1] | (~x_1[i1+1] & x_1[i1] & x_0
[i0]);
end
end
end
else begin : rec_end
assign x[0] = 1'b1;
assign x[1] = a[0];
end
endgenerate
endmodule