0
\$\begingroup\$

I have a LUT in I need to assign values. They are in the range of 0 to 3.3. This is the code:

case(address)

8'b00000000: new <= 16'bXX00111111111111;

8'b00000001: new <= 16'bXX00011111111111;

8'b00000010: new <= 16'bXX00000000010000;

8'b00000011: new <= 16'bXX00000000000000;

8'b00000100: new <= 16'bXX00111111111111;

8'b00000101: new <= 16'bXX00111111111111;

8'b00000110: new <= 16'bXX00000000010000;

8'b00000111: new <= 16'bXX00000000010000;

default: new <= 16'b0; // Default case if address is not matched

endcase

Now according to what I need, the last 12 bits should be the values that I want to enter into the variable, which are 0.4125, 0.825, etc. all upto 3.3. I am supposed to access this module from another top level module.

How do I convert these values into floating/fixed point representation? I am at a loss. I can't find any reliable converters on Google.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ I would not use the word 'new' as a variable in Verilog. New is a keyword in SyntemVerilog. \$\endgroup\$
    – Mikef
    Jan 31 at 16:10

1 Answer 1

2
\$\begingroup\$

The method depends on the number of fractional bits and total bits in the fixed point representation.

How to convert a floating point number to fixed point representation
B = Number of total bits (integer + fractional)
f = Number of fractional bits
n = Floating point number
a = n * 2^f
b = fix(a) or round(a)

I think B is 12 for your problem, I don't know what f is for your problem. (follow up, I recommend using f=10 based on experiments to determine the highest possible precision which fits in 12 total bits, see below)

Example:
Let:
B = 8
f = 4
n = .4125
a = .4125 * 2^4
a = 6.6
b = fix(a) # use a better rounding scheme get better precision, fix() rounds toward 0
b = 6

For a binary representation of 8 bits total (4 integer, 4 fractional) the number is 0000_0110

This represents the value 2^-2 + 2^-3 = .375

The error of this representation is the difference between .4125 and .375.
You can decrease the average error by increasing the number of fractional bits in your representation and by using a more more meaningful rounding instead of fix(). Fix chops off the bits that would have been rounded. I use fix for this example for simplicity and clarity. Convergent rounding minimizes the average error compared to many rounding schemes.

Another example
Let:
B = 8
f = 4
n = .825 a = .825 * 2^4
a = 13.2
b = fix(a) # use a better rounding scheme get better precision, fix() rounds toward 0
b = 13

For a binary representation of 8 bits total (4 integer, 4 fractional) the number is 0000_1101
This represents the value 2^-1 + 2^-2 + 2^-4 = .8125
and the error is .825-.8125

To create a table with many entries, write a script (or use some other tool) to convert each float to fixed for as many floats as you need using the method shown above.

The script will have a for style loop which starts out at the smallest value you want to represent and adds the smallest increment that will give you the number of entries needed in the table. The for loop will loop the number of times required to reach the max floating point value you wish to convert. It might start out at .0001, and add .0001 each time, so the floats to convert will look like .0000, .0001, .0002, .0003, ... 3.3. This table would be about 3300 entries long.

I might even skip the full scripting approach and do this in Excel or Google sheets. That would be faster for me.

I think the lsb in your loop corresponds to the lsb into the table (the address) for the Verilog case/look up table. If that is the case then the increment on each loop could be 3.3/256 = .0129. The table would have 256 entries starting at 0 and ending at 3.3, incrementing by .0129 each iteration.

10 fractional bits, 2 integer bits with an increment of .01295, covers the range 0 to 3.3 using a 256 entry table (you have a 8 bit address). Excel is using 'round to the nearest integer' rounding strategy. I tweaked the initial value of .0129 a little to reduce the error and get a little closer to exact 3.3 (address 255). You could play with the increment a little more and get closer to exactly 3.3 if it matters to you. 12 bits is not going to represent 3.3 perfectly.

enter image description here

High part of table
enter image description here

Excel dec2bin() does not work with binary numbers >512; I used dec2hex instead, so the table data values in are in hex. Hex is fine for Verilog literals, use 16'h instead of 16'b as the specifier for the literal.

I will let you create the table or write the script to get all the values as needed.

Using your template, the Verilog table with fixed point data entries looks like this:

case(address)

8'b00000000: table_data <= 16'h0000;
8'b00000001: table_data <= 16'h000d;// .01295 in 12.10 fixed point fmt
8'b00000010: table_data <= 16'h001b;// .0259  in 12.10 fixed point fmt
8'b00000011: table_data <= 16'h0028;// .03885 in 12.10 fixed point fmt
...
8'b11111111: table_data <= 16'h0d36;//3.30225 in 12.10 fixed point fmt


default: new            <= 16'b0;  // Default case, address not matched

endcase
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.