Aw shucks, at LAST you've told us what you're really trying to do!
So the lookup value doesn't really control what your code should
DO, but only a VALUE... you have some unknown or unpredictable
function that can only be expressed as a lookup table.
Here's an idea that may make it less clumsy. Your incoming
frequency (ordinate) is 8 bits, you say. OK, so split it
into two pieces - top 4 bits and lower 4 bits. Create a
16-entry lookup table, indexed by the top 4 bits, with TWO
columns: the first "column" (group of bits in each element
of the table) is the correct function value for that value
of the top 4 bits, if the lower 4 bits were stuck at zero.
The second "column" is the first derivative of the function
at that point, suitably scaled. Now you multiply that
derivative by the lower 4 bits of the input, and add it
to the first-approximation value. Bingo: cut-price
first-order linear interpolation. Works nicely for
any reasonably smooth function. If the function happens
to be exponential, you're in even better shape - the first
derivative is obtained from the value by multiplying by
a scale factor, no table required!!! - but that's too
lucky to be true.
This little example uses constants for the LUT - yes,
I know you need it to be variables - but it illustrates
the idea; it generates a pretty good sine-function
approximation from just 32 numbers. Note also that
the first-differences table has pretty small numbers
in it, and doesn't need much space. I've registered
the LUT outputs so that they could go into blockRAM if
need be.
There are tricks for making the approximation better,
at the cost of a little more logic.
entity pipelined_lookup is
port (
clk : in std_logic;
freq: in unsigned(7 downto 0);
result: out unsigned(11 downto 0) --- as an example
);
end;
architecture linear_interpolator of pipelined_lookup is
subtype uint_12bit is integer range 0 to 4095;
type lookup_table is array(0 to 15) of uint_12bit;
--- y0 (approximation) lookup table, sine scaled by 4000
constant y0: lookup_table :=
( 0 => 0
, 1 => 392
, 2 => 780
, 3 => 1161
, 4 => 1531
, 5 => 1886
, 6 => 2222
, 7 => 2538
, 8 => 2828
, 9 => 3092
,10 => 3326
,11 => 3528
,12 => 3696
,13 => 3828
,14 => 3923
,15 => 3981
);
--- dy (first derivative) lookup table, cosine suitably scaled
constant dy: lookup_table :=
( 0 => 25
, 1 => 24
, 2 => 24
, 3 => 23
, 4 => 23
, 5 => 22
, 6 => 20
, 7 => 19
, 8 => 17
, 9 => 16
,10 => 14
,11 => 11
,12 => 9
,13 => 6
,14 => 4
,15 => 2
);
signal reg_y0, reg_dy: uint_12bit;
signal delta: integer range 0 to 15;
begin
process (clk)
variable index: integer range 0 to 15;
begin
if rising_edge(clk) then
-- first pipeline stage: lookup table
index := to_integer(freq(7 downto 4));
reg_y0 <= y0(index);
reg_dy <= dy(index);
delta <= to_integer(freq(3 downto 0));
-- second pipeline stage: interpolation
result <= to_unsigned(reg_y0 + reg_dy * delta, result'length);
end if;
end process;
end;
--
Jonathan Bromley, Consultant
DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services
Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
(e-mail address removed)://
www.MYCOMPANY.com
The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.