-1

I am a beginner in vhdl, I am trying to generate a sinus and square singal with a frequency of 50 Mhz, but first i'm trying to generate the sinus wave. I saw a lot of tutorials but it was quite complicated to understand. Here is the code I made. Thank you in advance for your help :)

Indications

    library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;

entity sinus is
    port(clk : in std_logic;
        clear : in std_logic;
        sel : in std_logic_vector(1 downto 0);
    Dataout : out std_logic_vector(7 downto 0));
end sinus;

architecture Behavioral of sinus is
        signal in_data : std_logic_vector(Dataout'range);
        signal i : integer range 0 to 77:=0;
      TYPE mem_data IS ARRAY (0 TO 255) OF integer range -128 to 127;       
      constant sin : mem_data := ( 
      (   0),(   3),(   6),(   9),(  12),(  15),(  18),(  21),(  24),(  28),(  31),(  34),(  37),(  40),(  43),(  46),  (  48),(  51),(  54),(  57),(  60),(  63),(  65),(  68),(  71),(  73),(  76),(  78),(  81),(  83),(  85),(  88),  (  90),(  92),(  94),(  96),(  98),( 100),( 102),( 104),( 106),( 108),( 109),( 111),( 112),( 114),( 115),( 117),  ( 118),( 119),( 120),( 121),( 122),( 123),( 124),( 124),( 125),( 126),( 126),( 127),( 127),( 127),( 127),( 127),  ( 127),( 127),( 127),( 127),( 127),( 127),( 126),( 126),( 125),( 124),( 124),( 123),( 122),( 121),( 120),( 119),  ( 118),( 117),( 115),( 114),( 112),( 111),( 109),( 108),( 106),( 104),( 102),( 100),(  98),(  96),(  94),(  92),  (  90),(  88),(  85),(  83),(  81),(  78),(  76),(  73),(  71),(  68),(  65),(  63),(  60),(  57),(  54),(  51),  (  48),(  46),(  43),(  40),(  37),(  34),(  31),(  28),(  24),(  21),(  18),(  15),(  12),(   9),(   6),(   3),  (   0),(  -3),(  -6),(  -9),( -12),( -15),( -18),( -21),( -24),( -28),( -31),( -34),( -37),( -40),( -43),( -46),  ( -48),( -51),( -54),( -57),( -60),( -63),( -65),( -68),( -71),( -73),( -76),( -78),( -81),( -83),( -85),( -88),  ( -90),( -92),( -94),( -96),( -98),(-100),(-102),(-104),(-106),(-108),(-109),(-111),(-112),(-114),(-115),(-117),  (-118),(-119),(-120),(-121),(-122),(-123),(-124),(-124),(-125),(-126),(-126),(-127),(-127),(-127),(-127),(-127),  (-127),(-127),(-127),(-127),(-127),(-127),(-126),(-126),(-125),(-124),(-124),(-123),(-122),(-121),(-120),(-119),  (-118),(-117),(-115),(-114),(-112),(-111),(-109),(-108),(-106),(-104),(-102),(-100),( -98),( -96),( -94),( -92),  ( -90),( -88),( -85),( -83),( -81),( -78),( -76),( -73),( -71),( -68),( -65),( -63),( -60),( -57),( -54),( -51),  ( -48),( -46),( -43),( -40),( -37),( -34),( -31),( -28),( -24),( -21),( -18),( -15),( -12),(  -9),(  -6),(  -3)); 
                                    
begin
    process(clk, clear) begin
        if (clear='1') then
            in_data <= (others => '0');
        elsif (clk'event and clk='1') then
                in_data <= in_data +1; 
        end if;     
        
end process;

    process (in_data(3))
        begin
            if (in_data(3)'event and in_data(3)='1') then
            in_data <=conv_std_logic_vector(sin(i).8);
            i<=i+1;
                if (i=77) then
                i<=0;
            end if;
        end if;
    end process;

    process(in_data, sel) begin
        case sel is
                when "00" =>Dataout<=in_data;
            
                when others =>Dataout<= "00000000";
        end case;
    end process;

end Behavioral;
Chuinul
  • 1
  • 1
  • 2

1 Answers1

-1

Thanks for the diagram. Because VHDL is hardware description language, the question you should ask yourself is : what do I want to implement ? where are the entity ports, the internal signals on this block diagram ?

The main issue you face is that you've no real correspondence between your design and your illustration. Moreover your VHDL coding style needs improvement both regarding the VHDL language itself and how you implement things.

Start by replacing

use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;

by

use IEEE.NUMERIC_STD.ALL;

This is the official vendor-agnostic VHDL package for signed and unsigned types. IEEE.STD_LOGIC_UNSIGNED and STD_LOGIC_ARITH.ALL are outdated vendor-dependent VHDL packages provided at a time where vendors couldn't agree on a common definition. This led to a lot of portability issues when having a design flow with tools from different vendors (Cadence, Mentor, Synopsys). The IEEE specification body solved once and for all this issue.

If you're designing real hardware, the following code can lead to implementation problems

process(clk, clear) begin
    if (clear='1') then
        in_data <= (others => '0');
    elsif (clk'event and clk='1') then
            in_data <= in_data +1; 
    end if;     
end process;

Your in_data signal is asynchronously cleared but synchronously set. As you don't control when the clear signal will be asserted relative to the clk rising edge, there is a risk of in_data metastability or even that some bits of the in_data remains in reset while the others capture a new value.

For a description of the various ways to implement the reset Xilinx has a well documented white paper (WP272) which provides some guidelines useful for any synchronous design be it ASIC or FPGA, Xilinx or Altera. By the way if you have a look, for example, to the widely popular AMBA specifications (AHB, AXI, AXI-Stream, ...), their reset is asserted asynchronously but deasserted synchronously.

Personnally, following Xilinx guidelines, I distribute an asynchronous reset through the entire design and generate locally a synchronous reset with the following piece of code (being locally avoid the fanout issue of a system-wide synchronous reset)

if (p_reset_n = '0') then
    s_reset_on_clock <= (others => '1');
else if rising_edge(p_clock) then
         s_reset_on_clock <= '0' & s_reset_on_clock(3 downto 1);
     end if;
end if;

s_reset_on_clock(0) is now your local synchronous reset signal that you can use like any other signal within the synchronous code block.

Please replace the old fashioned

 elsif (clk'event and clk='1') then

with

 elsif rising_edge(clk) then

it will be more obvious what's going on here.

You say that you want to generate a 50MHz signal but you don't say what the system frequency (or maybe I should understand it the other way around). The ratio system clock frequency / 50MHz will give you the sequence length.

Anyway, you will need to declare a free running counter as signal, let's call it counter (in your original code you have two signals, i and in_data, for this same purpose), and reset/increment it using your locally synchronous reset and your clock signal.

In case of a square signal (let's say sel = '0'), your output will be solely determined by the value of your counter. Below a given counter value, you'll have a predetermined dataout value (your 'low' state), while above this value, you'll have another predetermined dataout value (your 'high' state).

In case of a sine signal (let's say sel = '1'), the counter will represent the phase and will be used as input to your sine lookup table (that you, by the way, could initialize with a VHDL function calculating the lookup table content instead of providing precalculated literals). The output of the sine lookup table is your dataout output.

Let me know if you need more help.

EajksEajks
  • 11
  • 4
  • 4
    This isnt really an answer, but maybe comment worthy. When you you have more reputation you can post comments. Depending on technology then async clear is not a problem. For example, all Altera chips have no synchronous reset, only async reset. Xilinx also provide async clear via GSR. And while `rising_edge(clk)` may be prefered, in the majority of cases, `clk'event and clk='1'` will work exactly the same (and infer the same hardware). – Tricky Nov 20 '20 at 17:49
  • In Addition, while `std_logic_unsigned` may not be a standard, again it will compile just fine and work idenically for all all tools I know. `numeric_std_unsigned` was added to VHDL 2008 to work almost the same as this package. – Tricky Nov 20 '20 at 17:53
  • For the synchronous vs asynchronous please refer to the well documented white paper WP272 from Xilinx. If you have an asynchronous reset there is no way to know when you'll leave the reset state wrt the clock edges. Therefore Xilinx suggests a way to circumvene the issue. By the way if you have a look, for example, to the widely popular AMBA specifications, their reset is asserted asynchronously but deasserted synchronously. – EajksEajks Nov 20 '20 at 18:31
  • Regarding the use of clk'event and clk='1' and unsigned/signed types, for sure, you can still use the old-fashioned VHDL'93 way of writing VHDL code thanks to backward compatibility. It is no reason not to start writing proper code. – EajksEajks Nov 20 '20 at 18:33
  • @EaklsEakls Other vendors exist. And Altera would very much like you to use async reset, that is async asserted and synchronously de-asserted. But the technology has no sync reset. Hence the async reset template provided in the original post is very much encouraged. Any sync resets have to be emulated with a lut, and therefore make timing worse. Async reset can be routed in the chips using a clock net for very low skew (and will usually be put on one by the compiler) – Tricky Nov 20 '20 at 23:39
  • And `rising_edge(clk)` was introduced in VHDL 1993, hence `clk'event and clk = '1'` is more VHDL87 style. – Tricky Nov 20 '20 at 23:40
  • @Tricky Pure asynchronous reset can produce rare hard to find bugs on the target apps as it will be a bug impossible to reproduce from run to run. When it appears, it might appear in one place with big consequences, or next time on another place with hardly any noticeable consequences (many functions when designed properly can recover from an initialization error). All AHB or AXI peripherals require synchronous reset deassertion. – EajksEajks Nov 21 '20 at 10:37
  • @Tricky Xilinx WP272 gives you an example how to do it. In all my designs I distribute a global asynchronous reset and generate a locally (to avoid fanout issues) synchronous reset following Xilinx guidelines. Here is the VHDL code: if (p_reset_n = '0') then s_reset_on_clock <= (others => '1'); else if rising_edge(p_clock) then s_reset_on_clock <= '0' & s_reset_on_clock(3 downto 1); end if; end if; – EajksEajks Nov 21 '20 at 10:40
  • @EakjksEajks But this is just a Xilinx example. OP gave no indication of what technology was being used. Xilinx reset strategies do not necessarily apply to other vendors technology. – Tricky Nov 21 '20 at 11:32
  • @Tricky It's not because it's a Xilinx white paper that it doesn't apply to others. Laws of physics are the same for everyone. When Arm specifies its reset signal, it doesn't do so because of Xilinx. It does so because it's a real concern for any ASIC or FPGA designer. Of course there could be another approach : using a synchronous reset signal generated by the PLL such as the locked signal. You reset asynchronously the PLL and used the synchronous locked signal as reset signal. But by experience it is not always possible to do so. When designing an IP, I prefer to handle it locally... – EajksEajks Nov 21 '20 at 11:42
  • ... so my IP core is independent of the upper level reset strategy. – EajksEajks Nov 21 '20 at 11:43