-- DDFSMART.vhd ------------------------------------- -- Direct Digital Freq. Synthesis -- ------------------------------------- -- (c) Bert Cuzeau - alse@compuserve.com -- May be reproduced provided that -- copyright above remains. -- Smart version : -- We use the double symetry in the sine function -- So the lookup table is re-used 3 times -- A 64 entries table is worth 256 samples -- modified by Paul Berube so that it will synthesize under Xilinx Foundation 3.1i. -- - VHDL roms not supported (had to use case instead) -- - NOT on subsection of std_logic_vector not supported, need AccumInv ------------------------------------- -- Has been tested successfully with : -- * Leonardo Spectrum & Altera Flex10k -- * Synplicity & Xilinx Xc4000XL -- The new Sine Table is built by a C program... ------------------------------------- -- Design IOs : -- Clk : Global clock input -- Freq_data : 8-bit frequency control vector -- from the DIP switches on the eval. board -- Dout : is a 6-bit sine output to the DAC -- ----------------------------------------------- LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.numeric_std.all; -- ----------------------------------------------- ENTITY ddfs IS -- ----------------------------------------------- PORT ( clk : IN std_logic; rst : IN std_logic; -- freq_data : IN std_logic_vector (7 DOWNTO 0); dout : OUT std_logic_vector (7 DOWNTO 0) ); END ddfs; -- ----------------------------------------------- ARCHITECTURE rtl OF ddfs IS -- ----------------------------------------------- constant ACCUMMAX: integer := 7; -- MINIMUN 7, STARTED 28 SIGNAL Address : unsigned (5 DOWNTO 0); SIGNAL Result : std_logic_vector (7 DOWNTO 0); SIGNAL Accum : unsigned (ACCUMMAX DOWNTO 0); SIGNAL AccumInv: unsigned (ACCUMMAX DOWNTO 0); -- to avoid sensitivity list to complete Address vector : SIGNAL Sign : std_logic; BEGIN -- Signed Adder / Accumulator -- -------------------------- acc: PROCESS(clk,rst) BEGIN IF rst='1' then Accum <= (others=>'0'); ELSIF RISING_EDGE(clk) THEN -- Accum <= Accum + unsigned(Freq_Data); Accum <= Accum + 1; END IF; END PROCESS acc; -- Note : Accum(28) = sign -- Accum(27) = AScending / Descending Index Sign <= Accum(ACCUMMAX); AccumInv <= not accum; -- Lookup Table Index calculation -- ------------------------------ process (Accum) begin if Accum(ACCUMMAX-1)='0' then Address <= unsigned(accum(ACCUMMAX-2 downto ACCUMMAX-7)); else Address <= unsigned(accumInv(ACCUMMAX-2 downto ACCUMMAX-7)); end if; end process; -- SINE Look-Up TABLE -- ------------------- -- Inference of an Asynchronous Rom. -- A synchronous one would be better -- Another solution would be to instanciate a synchronous -- Rom from the vendor's macrofunctions library. -- Anyway, this version works fine with most modern synthesizers. -- B.C. -- This table has been built by GENVEC.exe (C program) -- We use only positive values ! (sign comes from quadrant info) lookup: PROCESS (Address, Sign) -- subtype SLV8 is std_logic_vector (7 downto 0); -- type Rom64x8 is array (0 to 63) of SLV8; -- variable Sinus_Rom : Rom64x8 := ( -- x"00",x"03",x"06",x"09",x"0c",x"0f",x"12",x"15", -- x"18",x"1b",x"1e",x"21",x"24",x"27",x"2a",x"2d", -- x"30",x"33",x"36",x"39",x"3b",x"3e",x"41",x"43", -- x"46",x"49",x"4b",x"4e",x"50",x"52",x"55",x"57", -- x"59",x"5b",x"5e",x"60",x"62",x"64",x"66",x"67", -- x"69",x"6b",x"6c",x"6e",x"70",x"71",x"72",x"74", -- x"75",x"76",x"77",x"78",x"79",x"7a",x"7b",x"7b", -- x"7c",x"7d",x"7d",x"7e",x"7e",x"7e",x"7e",x"7e" ); BEGIN if Sign='1' then case Address is when "000000" => Result <= x"00"; when "000001" => Result <= x"03"; when "000010" => Result <= x"06"; when "000011" => Result <= x"09"; when "000100" => Result <= x"0c"; when "000101" => Result <= x"0f"; when "000110" => Result <= x"12"; when "000111" => Result <= x"15"; when "001000" => Result <= x"18"; when "001001" => Result <= x"1b"; when "001010" => Result <= x"1e"; when "001011" => Result <= x"21"; when "001100" => Result <= x"24"; when "001101" => Result <= x"27"; when "001110" => Result <= x"2a"; when "001111" => Result <= x"2d"; when "010000" => Result <= x"30"; when "010001" => Result <= x"33"; when "010010" => Result <= x"36"; when "010011" => Result <= x"39"; when "010100" => Result <= x"3b"; when "010101" => Result <= x"3e"; when "010110" => Result <= x"41"; when "010111" => Result <= x"43"; when "011000" => Result <= x"46"; when "011001" => Result <= x"49"; when "011010" => Result <= x"4b"; when "011011" => Result <= x"4e"; when "011100" => Result <= x"50"; when "011101" => Result <= x"52"; when "011110" => Result <= x"55"; when "011111" => Result <= x"57"; when "100000" => Result <= x"59"; when "100001" => Result <= x"5b"; when "100010" => Result <= x"5e"; when "100011" => Result <= x"60"; when "100100" => Result <= x"62"; when "100101" => Result <= x"64"; when "100110" => Result <= x"66"; when "100111" => Result <= x"67"; when "101000" => Result <= x"69"; when "101001" => Result <= x"6b"; when "101010" => Result <= x"6c"; when "101011" => Result <= x"6e"; when "101100" => Result <= x"70"; when "101101" => Result <= x"71"; when "101110" => Result <= x"72"; when "101111" => Result <= x"74"; when "110000" => Result <= x"75"; when "110001" => Result <= x"76"; when "110010" => Result <= x"77"; when "110011" => Result <= x"78"; when "110100" => Result <= x"79"; when "110101" => Result <= x"7a"; when "110110" => Result <= x"7b"; when "110111" => Result <= x"7b"; when "111000" => Result <= x"7c"; when "111001" => Result <= x"7d"; when "111010" => Result <= x"7d"; when "111011" => Result <= x"7e"; when "111100" => Result <= x"7e"; when "111101" => Result <= x"7e"; when "111110" => Result <= x"7e"; when "111111" => Result <= x"7e"; when others => Result <= x"7E"; end case; else -- Result <= -(Sinus_Rom(to_integer(Address)))); case Address is when "000000" => Result <= x"00"; when "000001" => Result <= x"FD"; when "000010" => Result <= x"FA"; when "000011" => Result <= x"F7"; when "000100" => Result <= x"F4"; when "000101" => Result <= x"F1"; when "000110" => Result <= x"EE"; when "000111" => Result <= x"EB"; when "001000" => Result <= x"E8"; when "001001" => Result <= x"E5"; when "001010" => Result <= x"E2"; when "001011" => Result <= x"DF"; when "001100" => Result <= x"DC"; when "001101" => Result <= x"D9"; when "001110" => Result <= x"D6"; when "001111" => Result <= x"D3"; when "010000" => Result <= x"D0"; when "010001" => Result <= x"CD"; when "010010" => Result <= x"CA"; when "010011" => Result <= x"C7"; when "010100" => Result <= x"C5"; when "010101" => Result <= x"C2"; when "010110" => Result <= x"BF"; when "010111" => Result <= x"BD"; when "011000" => Result <= x"BA"; when "011001" => Result <= x"B7"; when "011010" => Result <= x"B5"; when "011011" => Result <= x"B2"; when "011100" => Result <= x"B0"; when "011101" => Result <= x"AE"; when "011110" => Result <= x"AB"; when "011111" => Result <= x"A9"; when "100000" => Result <= x"A7"; when "100001" => Result <= x"A5"; when "100010" => Result <= x"A2"; when "100011" => Result <= x"A0"; when "100100" => Result <= x"9E"; when "100101" => Result <= x"9C"; when "100110" => Result <= x"9A"; when "100111" => Result <= x"99"; when "101000" => Result <= x"97"; when "101001" => Result <= x"95"; when "101010" => Result <= x"94"; when "101011" => Result <= x"92"; when "101100" => Result <= x"90"; when "101101" => Result <= x"8F"; when "101110" => Result <= x"8E"; when "101111" => Result <= x"8C"; when "110000" => Result <= x"8B"; when "110001" => Result <= x"8A"; when "110010" => Result <= x"89"; when "110011" => Result <= x"88"; when "110100" => Result <= x"87"; when "110101" => Result <= x"86"; when "110110" => Result <= x"85"; when "110111" => Result <= x"85"; when "111000" => Result <= x"84"; when "111001" => Result <= x"83"; when "111010" => Result <= x"83"; when "111011" => Result <= x"82"; when "111100" => Result <= x"82"; when "111101" => Result <= x"82"; when "111110" => Result <= x"82"; when others => Result <= x"82"; end case; end if; END PROCESS lookup; -- Output registers -- ---------------- outreg: PROCESS(clk,rst) BEGIN IF rst='1' then Dout <= (others=>'0'); ELSIF RISING_EDGE(clk) THEN Dout <= NOT Result; -- for a real ADC, we do not need logic inversion END IF; END PROCESS outreg; END rtl;