# modelsim wave picture
Tags: vhdl triangle wave generator compact code
How to add files? Just like adding an image. But an 'image' with extension .vhd or .txt is not accepted: "opencores.org - Failed to upload image"
# error message
The url of the svn repository is: https://opencores.org/websvn/listing/triangle_wave_generator/triangle_wave_generator
OK, no download of documents possible and no one has given any hint so far how to make that work, so here the vhdl code as plain text:
--! @filename triangle_generator.vhd
--! @brief File holds the triangle_generator VHDL code
--!
--! This is the triangle_generator VHDL code
--! Description: This generates triangle and square waves with 90 degree phase shifts
--!
--! @author Benjamin Perdeck
--! $Date: 2022-06-13 16:32:03 +0200 (Mon, 13 Jun 2022) $
--!
-- Description of the entity:
-- The triangle generator generates two triangle signals with 90 degree phase offset using only one adder
-- The frequency of the triangle is configurable using a rate multiplier
-- Also, a square wave and 90 degrees shifted square wave signal is made.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use ieee.std_logic_misc.all; -- e.g and_reduce or_reduce
entity triangle_generator is generic (
TRIANGLE_WIDTH : integer := 16; -- the width of the unsigned triangle
RATE_GENERATOR_WIDTH : integer := 20 -- bits in the rate generator; The top bits are used for the triangles
-- NOTE: RATE_GENERATOR_WIDTH > TRIANGLE_WIDTH !!
);
port ( CLK : in std_logic; --! module clock
-- inputs:
ENABLE : in std_logic; -- a step is made at each ENABLE
-- config:
TRIANGLE_RATE : in unsigned(RATE_GENERATOR_WIDTH-1 downto 0);
-- outputs:
TRIANGLE00_U : out unsigned(TRIANGLE_WIDTH-1 downto 0); -- 'sine' like
TRIANGLE90_U : out unsigned(TRIANGLE_WIDTH-1 downto 0); -- +90 degree pre-running triangle 'cosine' like
TRIANGLE00_S : out signed(TRIANGLE_WIDTH-1 downto 0); -- 'sine' like
TRIANGLE90_S : out signed(TRIANGLE_WIDTH-1 downto 0); -- +90 degree pre-running triangle 'cosine' like
--
SQUARE00_U : out unsigned(TRIANGLE_WIDTH-1 downto 0); -- 1/16 to 15/16 range
SQUARE90_U : out unsigned(TRIANGLE_WIDTH-1 downto 0); -- 1/16 to 15/16 range
SQUARE00_S : out signed(TRIANGLE_WIDTH-1 downto 0); -- 7/8 to 7/8 range
SQUARE90_S : out signed(TRIANGLE_WIDTH-1 downto 0) -- -7/8 to 7/8 range
);
constant TWIDTH1 : natural := TRIANGLE_WIDTH+1;
signal rate_gen00 : unsigned(RATE_GENERATOR_WIDTH-1 downto 0) := (others => '0');
signal rate_gen00_nofrac : unsigned(TWIDTH1-1 downto 0);
signal rate_gen00_N_ff : unsigned(TWIDTH1-1 downto 0);
signal rate_gen00_I_ff : unsigned(TWIDTH1-1 downto 0);
signal gen_Ntop_so : unsigned(2-1 downto 0);
signal gen_Itop_so : unsigned(2-1 downto 0);
signal gen_N_mintop_so : unsigned(TWIDTH1-2-1 downto 0);
signal triangle00 : unsigned(TRIANGLE_WIDTH-1 downto 0); -- 'sine' like
signal triangle90 : unsigned(TRIANGLE_WIDTH-1 downto 0); -- +90 degree pre-running triangle 'cosine' like
signal sqt00 : unsigned(4-1 downto 0); -- 'sine' like
signal sqt90 : unsigned(4-1 downto 0); -- +90 degree pre-running triangle 'cosine' like
signal sq00 : unsigned(TRIANGLE_WIDTH-1 downto 0); -- 'sine' like
signal sq90 : unsigned(TRIANGLE_WIDTH-1 downto 0); -- +90 degree pre-running triangle 'cosine' like
assert (RATE_GENERATOR_WIDTH > TRIANGLE_WIDTH) report "Triangle generator: not RATE_GENERATOR_WIDTH > TRIANGLE_WIDTH" severity failure;
--! the rate generator
rate_gen_proc: process(CLK)
begin
if rising_edge(CLK) then
if ENABLE='1' then
rate_gen00 <= rate_gen00 + TRIANGLE_RATE; -- intended wrap at ofl!
end if;
end if;
end process;
rate_gen00_nofrac <= rate_gen00(rate_gen00'high downto rate_gen00'length-TWIDTH1);
-- RANGE ERROR WHEN RATE_GENERATOR_WIDTH <= TRIANGLE_WIDTH : >>> .. downto (negative number)
-- NEW method: use most bits of gen00_FF or gen00_inv_ff and only top bits determined by case
-- in this way, number of adders/subtractors is minimal
table_tri_gen: process(CLK)
variable gen_N_mintop : unsigned(TWIDTH1-2-1 downto 0);
variable gen_I_mintop : unsigned(TWIDTH1-2-1 downto 0);
variable gen_Ntop_var : unsigned(2-1 downto 0);
variable gen_Itop_var : unsigned(2-1 downto 0);
begin
if rising_edge(CLK) then
--make 00 and 90 degree versions:
rate_gen00_I_ff <= unsigned(not std_logic_vector(rate_gen00_nofrac)); -- will give twice the values at extremes!
rate_gen00_N_ff <= rate_gen00_nofrac;
gen_N_mintop := rate_gen00_N_ff(TWIDTH1-2-1 downto 0);
gen_I_mintop := rate_gen00_I_ff(TWIDTH1-2-1 downto 0);
gen_N_mintop_so <= gen_N_mintop;
gen_Ntop_var := rate_gen00_N_ff(TWIDTH1-1 downto TWIDTH1-2);
gen_Itop_var := rate_gen00_I_ff(TWIDTH1-1 downto TWIDTH1-2);
gen_Ntop_so <= gen_Ntop_var;
gen_Itop_so <= gen_Itop_var;
case to_integer(gen_Ntop_var) is -- 0 to 3
when 0 => triangle00 <= "0" & gen_N_mintop; triangle90 <= "1" & gen_N_mintop; sqt00<="0001"; sqt90<="1111"; --rising rising
when 1 => triangle00 <= "1" & gen_N_mintop; triangle90 <= "1" & gen_I_mintop; sqt00<="1111"; sqt90<="1111"; --rising falling
when 2 => triangle00 <= "1" & gen_I_mintop; triangle90 <= "0" & gen_I_mintop; sqt00<="1111"; sqt90<="0001"; --falling falling
when others => triangle00 <= "0" & gen_I_mintop; triangle90 <= "0" & gen_N_mintop; sqt00<="0001"; sqt90<="0001"; --falling rising
end case;
end if;
end process;
sq00 <= sqt00 & to_unsigned(0, sq00'length-4);
sq90 <= sqt90 & to_unsigned(0, sq00'length-4);
TRIANGLE00_U <= triangle00;
TRIANGLE90_U <= triangle90;
-- convert unsigned to signed by inversion of top bit:
TRIANGLE00_S <= signed( not triangle00(TRIANGLE_WIDTH-1) & std_logic_vector(triangle00(TRIANGLE_WIDTH-1-1 downto 0)));
TRIANGLE90_S <= signed( not triangle90(TRIANGLE_WIDTH-1) & std_logic_vector(triangle90(TRIANGLE_WIDTH-1-1 downto 0)));
SQUARE00_U <= sq00;
SQUARE90_U <= sq90;
-- convert unsigned to signed by inversion of top bit:
SQUARE00_S <= signed( not sq00(TRIANGLE_WIDTH-1) & std_logic_vector(sq00(TRIANGLE_WIDTH-1-1 downto 0)));
SQUARE90_S <= signed( not sq90(TRIANGLE_WIDTH-1) & std_logic_vector(sq90(TRIANGLE_WIDTH-1-1 downto 0)));
end arch_imp;
-----------------------------END OF FILE triangle_generator.vhd
--! @file triangle_generator_tb.vhd
--! @brief File holds the testbench for triangle_generators
--!
--! This is a testbench to test triangle_generators
--! --! @author Benjamin Perdeck
--! $Date: 2022-06-13 16:32:03 +0200 (Mon, 13 Jun 2022) $
--!
--! The use of this file, whole or a part, is subjected to licensing terms.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_misc.all;
use ieee.numeric_std.all;
use ieee.std_logic_textio.all;
use std.textio.all;
use ieee.math_real.all;
--! @brief Testbench to test the triangle_generators
--!
--! Testbench is used to test triangle_generator signed/unsigned unit which is used to perform a
--! This is implemented as a separate testbench to ensure that the triangle_generators
--! are working as expected
entity triangle_generator_tb is
-- UUT configuration constants
-- Testbench constants
constant testbench_name : string := "triangle_generator_tb"; --! Testbench name
constant clk_100MHz_period : time := 10 ns; --! about 100MHz Clock
--for full range test:
constant TRIANGLE_WIDTH : integer := 8; -- the width of the signed triangle
constant RATE_GENERATOR_WIDTH : integer := 12; -- bits in the rate generator; The top bits are used for the triangles
component triangle_generator is
generic (
TRIANGLE_WIDTH : integer := 16; -- the width of the signed triangle
RATE_GENERATOR_WIDTH : integer := 20 -- bits in the rate generator; The top bits are used for the triangles
);
port (
CLK : in std_logic; --! module clock
-- inputs:
ENABLE : in std_logic; -- a step is made at each ENABLE
-- config:
TRIANGLE_RATE : in unsigned(RATE_GENERATOR_WIDTH-1 downto 0);
-- outputs:
TRIANGLE00_U : out unsigned(TRIANGLE_WIDTH-1 downto 0); -- 'sine' like
TRIANGLE90_U : out unsigned(TRIANGLE_WIDTH-1 downto 0); -- +90 degree pre-running triangle 'cosine' like
TRIANGLE00_S : out signed(TRIANGLE_WIDTH-1 downto 0); -- 'sine' like
TRIANGLE90_S : out signed(TRIANGLE_WIDTH-1 downto 0); -- +90 degree pre-running triangle 'cosine' like
--
SQUARE00_U : out unsigned(TRIANGLE_WIDTH-1 downto 0); -- 1/16 to 15/16 range
SQUARE90_U : out unsigned(TRIANGLE_WIDTH-1 downto 0); -- 1/16 to 15/16 range
SQUARE00_S : out signed(TRIANGLE_WIDTH-1 downto 0); -- 7/8 to 7/8 range
SQUARE90_S : out signed(TRIANGLE_WIDTH-1 downto 0) -- -7/8 to 7/8 range
);
end component;
-- UUT I/O signals:
signal clk : std_logic := '0'; --! expect to run at 100MHz
signal rst : std_logic := '1';
signal enable : std_logic;
signal triangle_rate : unsigned(RATE_GENERATOR_WIDTH-1 downto 0);
signal triangle00_s : signed(TRIANGLE_WIDTH-1 downto 0); -- 'sine' like
signal triangle90_s : signed(TRIANGLE_WIDTH-1 downto 0); -- +90 degree pre-running triangle 'cosine' like
signal triangle00_u : unsigned(TRIANGLE_WIDTH-1 downto 0); -- 'sine' like
signal triangle90_u : unsigned(TRIANGLE_WIDTH-1 downto 0); -- +90 degree pre-running triangle 'cosine' like
signal square00_u : unsigned(TRIANGLE_WIDTH-1 downto 0);
signal square90_u : unsigned(TRIANGLE_WIDTH-1 downto 0);
signal square00_s : signed(TRIANGLE_WIDTH-1 downto 0);
signal square90_s : signed(TRIANGLE_WIDTH-1 downto 0);
function stdlogic2int ( data: std_logic ) return integer is
begin
if data = '1' then return 1;
elsif data = '0' then return 0;
else return -1; -- cases 'x', 'z' ...
end if;
end stdlogic2int;
--! @brief Unit under test: triangle_generator
--!
--! triangle_generator is used as unit under test to test the complete functionality
--! using this testbench
uut: triangle_generator
generic map (
TRIANGLE_WIDTH => TRIANGLE_WIDTH,
RATE_GENERATOR_WIDTH => RATE_GENERATOR_WIDTH
)
port map (
CLK => clk,
-- inputs:
ENABLE => enable,
-- config:
TRIANGLE_RATE => triangle_rate,
-- outputs:
TRIANGLE00_U => triangle00_u,
TRIANGLE90_U => triangle90_u,
TRIANGLE00_S => triangle00_s,
TRIANGLE90_S => triangle90_s,
SQUARE00_U => square00_u,
SQUARE90_U => square90_u,
SQUARE00_S => square00_s,
SQUARE90_S => square90_s
);
-- Reset signals
rst <= '0' after clk_100MHz_period*20;
-- Clock signals
clk <= not(clk) after clk_100MHz_period/2;
--! @brief write_testbench_header_proc gives a message to the console output
--!
--! This process shows the user the simulation has started and what the name is
write_testbench_header_proc: process
variable s: line;
begin
-- Skip initial warnings
wait for 1 ps;
write(s, testbench_name);
writeline(output,s);
wait;
end process write_testbench_header_proc;
--triangle_rate <= to_unsigned((2**RATE_GENERATOR_WIDTH)/1000+1, RATE_GENERATOR_WIDTH); -- +1 to get different values out of it too
-- give an enable to teh generator every 10 clock cycles
enable_proc: process
begin
enable <= '0';
wait until rst='0';
while true loop
for i in 1 to 10-1 loop
wait until rising_edge(clk);
end loop;
enable <= '1';
wait until rising_edge(clk);
enable <= '0';
end loop;
end process;
-- vary the rate frequency between 1 and 30
rate_proc: process
begin
for rate in 1 to 30 loop
triangle_rate <= to_unsigned(rate, RATE_GENERATOR_WIDTH);
for i in 1 to 100000-rate*3000 loop -- wait shorter at higher frequency
wait until rising_edge(clk);
end loop;
end loop;
wait;
end process;
end testbench;
-----------------------------END OF FILE triangle_generator_tb.vhd