Saturday, May 31, 2014

ModelSim testbench with reals and floats

Trying to program BladeRF's FPGA with VHDL

Summary

I tried to implement the suggestions I got from Brian. And I was successful!

The first VHDL-program is possibly not synthesizable, but it works in the simulator. The next program more or less proves (I think) that I understood Brian's suggestions. The last program has the same behaviour and uses a table that is generated at compiletime. So, the synthesized program only has some precompiled data in a table. And that is synthesizable.

Testbed

library ieee ;
    use ieee.std_logic_1164.all ;
    use ieee.numeric_std.all ;


-- tdatasource.vhd
-- May-2014 Kees de Groot
-- test-program for the datasource to test my DC-remover
-- this device simply tests the datasource

entity test_datasource is
    PORT ( sdata : out     signed(11 downto 0));
end;

architecture mytest of test_datasource is

COMPONENT datasource
port (
       reset  : in   std_logic;
clk    : in   std_logic;
sdata  : out  signed(11 downto 0)
      ) ;
END COMPONENT ;

SIGNAL clk   : std_logic := '1';
SIGNAL reset : std_logic := '0';
constant FS : real := 38.4e6 ; -- sample frequency

begin

dut : datasource
   PORT MAP (
   sdata => sdata,
   clk => clk,
   reset => reset );

clock : PROCESS(clk)
   begin
   clk <= not clk after (1.0/FS)/2.0 * (1 sec) ;
end PROCESS clock;

stimulus : PROCESS
   begin
   wait for 5 ns; reset  <= '1';
   wait for 4 ns; reset  <= '0';
   wait;
end PROCESS stimulus;

end mytest;

a testbed is to be used with the simulator. So, does not have to be synthesizable, but should run correctly.

First floating/real program


library ieee ;
    use ieee.std_logic_1164.all ;
    use ieee.numeric_std.all ;
    use ieee.math_real.all;

-- datasource.vhd
-- May-2014 Kees de Groot
-- test-program for my DC-remover
-- this device outputs a 2s-complement sine of 32 points

entity datasource is
port (
       reset  : in   std_logic;
       clk    : in   std_logic;
       sdata  : out  signed(11 downto 0)
      ) ;
end datasource;

architecture mydatasource of datasource is
  signal indexx: integer range 0 to 31;
  signal tmpdata: signed(11 downto 0);
begin
 calcindex: process (clk, reset)
        begin 
          if (reset='1') then 
            indexx <= 0; 
          elsif (rising_edge(clk)) then 
            if (indexx = 31) then
              indexx <= 0;
            else indexx <= indexx +1;
            end if;
          end if; 
      end process calcindex;
       myproc: process (indexx)
       begin
         tmpdata <= to_signed(600 + integer(1400.0 * SIN(2.0 * MATH_PI * real(indexx) / 32.0)), 12);
       end process myproc;

       sdata <= tmpdata;

end mydatasource;

I am afraid this program is not synthesizable, but it runs correctly.

Synthesizable floating/real program


library ieee ;
    use ieee.std_logic_1164.all ;
    use ieee.numeric_std.all ;
    use ieee.math_real.all;

-- datasource2.vhd
-- May-2014 Kees de Groot
-- test-program for my DC-remover
-- this device outputs a 2s-complement sine of 32 points

entity datasource is
port (
       reset  : in   std_logic;
       clk    : in   std_logic;
       sdata  : out  signed(11 downto 0)
      ) ;
end datasource;

architecture mydatasource of datasource is
  signal indexx: integer range 0 to 31;
  signal tmpdata: signed(11 downto 0);
  type sintab is array(0 to 31) of signed(11 downto 0);
  signal sinrom: sintab;

 begin
  genrom: for idx in 0 to 31 generate
    constant x: real := SIN(2.0 * MATH_PI * real(idx) / 32.0);
    constant xn: signed(11 downto 0) := to_signed(600 + integer(1400.0 * x), 12);
    begin
      sinrom(idx) <= xn;
    end generate;
   
 calcindex: process (clk, reset)
        begin 
          if (reset='1') then 
            indexx <= 0; 
          elsif (rising_edge(clk)) then 
            if (indexx = 31) then
              indexx <= 0;
            else indexx <= indexx +1;
            end if;
          end if; 
      end process calcindex;
     
       myproc: process (indexx)
       begin
         tmpdata <= sinrom(indexx);
       end process myproc;

       sdata <= tmpdata;

end mydatasource;

What did I do? I created a table called sinrom with 32 entries. In the process calcindex I simply increment an index for every clk-pulse and use that to get the corresponding value, a 12 bit number.

Picture of the simulation



Yes, I know I can get rid off some numbers using written constants. 

By the way I got the idea from:



One possible way is to calculate the table in VHDL at compile time, as shown in the below example. (It's a 0..pi sine table, not the solution for your problem).

Code:
TYPE SINTAB IS ARRAY(0 TO ROMSIZE-1) OF STD_LOGIC_VECTOR (NNCO-2 DOWNTO 0);
SIGNAL SINROM: SINTAB;

BEGIN

GENROM:
FOR idx in 0 TO ROMSIZE-1 GENERATE
         CONSTANT x: REAL := SIN(real(idx)*MATH_PI/real(ROMSIZE));
         CONSTANT xn: UNSIGNED (NNCO-2 DOWNTO 0) := CONV_UNSIGNED(INTEGER(x*real(ROMMAX)),NNCO-1);
BEGIN
         SINROM(idx) <= STD_LOGIC_VECTOR(xn);       
END GENE



No comments:

Post a Comment