1+ -------------------------------------------------------------------------------
2+ -- Title : gc_iq_modulator.vhd testbench
3+ -- Project :
4+ -------------------------------------------------------------------------------
5+ -- File : gc_iq_modulator_tb.vhd
6+ -- Author : David Daminelli <david.daminelli@lnls.br>
7+ -- Company : Brazilian Synchrotron Light Laboratory, LNLS/CNPEM
8+ -- Created : 2025-06-18
9+ -- Last update: 2025-06-18
10+ -- Platform :
11+ -- Standard : VHDL'08
12+ -------------------------------------------------------------------------------
13+ -- Description: A testbench for the gc_iq_modulator.vhd core.
14+ -- This testbench loops through a set of I and Q values, computes the expected
15+ -- generates the corresponding sines, and compares it to the module's output.
16+ -- The gc_iq_modulator.vhd core has two outputs that are 90° out of phase, and
17+ -- both are asserted.
18+ -------------------------------------------------------------------------------
19+ -- Copyright (c) 2025 Brazilian Synchrotron Light Laboratory, LNLS/CNPEM
20+ -------------------------------------------------------------------------------
21+ -- Revisions :
22+ -- Date Version Author Description
23+ -- 2025-06-18 1.0 david.daminelli Created
24+ -------------------------------------------------------------------------------
25+
26+ library ieee;
27+ use ieee.std_logic_1164.all ;
28+ use ieee.numeric_std.all ;
29+ use ieee.math_real.all ;
30+
31+ library std;
32+
33+ library work;
34+
35+ entity gc_iq_modulator_tb is
36+ end entity gc_iq_modulator_tb;
37+
38+ architecture tb of gc_iq_modulator_tb is
39+
40+ -----------------------Procedure Declaration----------------------------------
41+ -- Clock Generation
42+ procedure f_gen_clk(constant freq : in natural ;
43+ signal clk : inout std_logic ) is
44+ begin
45+ loop
46+ wait for (0.5 / real (freq)) * 1 sec ;
47+ clk <= not clk;
48+ end loop ;
49+ end procedure f_gen_clk;
50+
51+ -- Wait procedure
52+ procedure f_wait_cycles(signal clk : in std_logic ;
53+ constant cycles : natural ) is
54+ begin
55+ for i in 1 to cycles loop
56+ wait until rising_edge (clk);
57+ end loop ;
58+ end procedure f_wait_cycles;
59+
60+ --------------------------- Constants Declaration ---------------------------
61+ constant c_clk_freq : natural := 100e3 ; -- Clk Freq
62+ constant c_in_freq : real := real (c_clk_freq)/ 4.0 ;
63+ constant c_N : positive := 16 ; -- data size
64+
65+ ----------------------------- Signal Declaration -----------------------------
66+ signal clk : std_logic := '0' ;
67+ signal rst : std_logic := '1' ;
68+ signal s_i_data, s_i_data_d0 : std_logic_vector (c_N- 1 downto 0 ) := (others => '0' );
69+ signal s_q_data, s_q_data_d0 : std_logic_vector (c_N- 1 downto 0 ) := (others => '0' );
70+ signal s_i_out, s_q_out : std_logic_vector (c_N- 1 downto 0 ) := (others => '0' );
71+ signal s_i_in, s_q_in : integer := 0 ;
72+ signal s_sync : std_logic := '0' ;
73+ signal s_en_i : std_logic := '1' ;
74+
75+ type t_IQ_STATE is (S_0, S_PI2, S_PI, S_3PI2);
76+ signal s_state : t_IQ_STATE := S_0;
77+ begin
78+ -------- Clock generation --------
79+ f_gen_clk(c_clk_freq, clk);
80+
81+ -------- Test Processes --------
82+
83+ p_gen_stimulus: process
84+ begin
85+ s_sync <= '1' ;
86+ rst <= '1' ;
87+ f_wait_cycles(clk, 1 );
88+ rst <= '0' ;
89+ f_wait_cycles(clk, 1 );
90+ for i in 0 to c_N- 2 loop -- Loop through I values
91+ s_i_in <= 2 ** i;
92+ for j in 0 to c_N- 2 loop -- Loop through Q values
93+ s_q_in <= 2 ** j;
94+ s_sync <= '0' ;
95+ f_wait_cycles(clk, 1 );
96+ f_wait_cycles(clk, 50 ); -- wait 50 cycles in each value
97+ end loop ;
98+ end loop ;
99+ report " Finished!" ;
100+ std.env.finish ;
101+ end process ;
102+
103+ p_modulator : process (clk) -- Generate the expected outputs
104+ begin
105+ if rising_edge (clk) then
106+ if rst = '1' then
107+ s_state <= S_0;
108+ s_i_data <= (others => '0' );
109+ s_q_data <= (others => '0' );
110+ elsif s_en_i = '0' then
111+ s_state <= S_0;
112+ s_i_data <= std_logic_vector (to_signed (s_i_in, c_N));
113+ s_q_data <= std_logic_vector (to_signed (s_q_in, c_N));
114+ elsif s_sync = '1' or s_state = S_3PI2 then
115+ s_state <= S_0;
116+ s_i_data <= std_logic_vector (to_signed (s_i_in, c_N));
117+ s_q_data <= std_logic_vector (to_signed (s_q_in, c_N));
118+ elsif s_state = S_0 then
119+ s_state <= S_PI2;
120+ s_i_data <= std_logic_vector (to_signed (- s_q_in, c_N));
121+ s_q_data <= std_logic_vector (to_signed (s_i_in, c_N));
122+ elsif s_state = S_PI2 then
123+ s_state <= S_PI;
124+ s_i_data <= std_logic_vector (to_signed (- s_i_in, c_N));
125+ s_q_data <= std_logic_vector (to_signed (- s_q_in, c_N));
126+ elsif s_state = S_PI then
127+ s_state <= S_3PI2;
128+ s_i_data <= std_logic_vector (to_signed (s_q_in, c_N));
129+ s_q_data <= std_logic_vector (to_signed (- s_i_in, c_N));
130+ end if ;
131+ end if ;
132+ end process ;
133+
134+ p_assert: process (clk)
135+ begin
136+ if rising_edge (clk) then
137+ -- delay the outputs to match core delay
138+ s_i_data_d0 <= s_i_data;
139+ s_q_data_d0 <= s_q_data;
140+ if s_sync = '0' then -- skip first clocks where output is undefined
141+ assert signed (s_i_data_d0) = signed (s_i_out)
142+ report " Error in I output value " &
143+ to_string(s_i_data_d0) & " | " &
144+ to_string(s_i_out)
145+ severity failure ;
146+ assert signed (s_q_data_d0) = signed (s_q_out)
147+ report " Error in Q output value " &
148+ to_string(s_q_data_d0) & " | " &
149+ to_string(s_q_out)
150+ severity failure ;
151+ end if ;
152+ end if ;
153+ end process ;
154+
155+ ------ Entity instantiation ------
156+ UUT: entity work.gc_iq_modulator
157+ generic map (
158+ g_N => c_N
159+ )
160+ port map (
161+ clk_i => clk,
162+ en_i => s_en_i,
163+ rst_i => rst,
164+ sync_p1_i => s_sync,
165+ i_i => std_logic_vector (to_signed (s_i_in, c_N)),
166+ q_i => std_logic_vector (to_signed (s_q_in, c_N)),
167+ i_o => s_i_out,
168+ q_o => s_q_out
169+ );
170+
171+ end architecture tb;
0 commit comments