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, generates
15+ -- the corresponding sines, and compares it to the module's output.
16+ -- The gc_iq_modulator.vhd core has two outputs that are 90°
17+ -- dephased and 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 ;
62+ constant c_in_freq : real := real (c_clk_freq)/ 4.0 ;
63+ constant c_N : positive := 16 ; -- Data size
64+
65+ -------- Type Declaration --------
66+ type t_IQ_STATE is (S_0, S_PI2, S_PI, S_3PI2);
67+
68+ -------- Signal Declaration --------
69+ signal clk : std_logic := '0' ;
70+ signal rst : std_logic := '1' ;
71+ signal s_i_mod, s_i_mod_d0 : std_logic_vector (c_N- 1 downto 0 ) := (others => '0' );
72+ signal s_q_mod, s_q_mod_d0 : std_logic_vector (c_N- 1 downto 0 ) := (others => '0' );
73+ signal s_i_out, s_q_out : std_logic_vector (c_N- 1 downto 0 ) := (others => '0' );
74+ signal s_i_in, s_q_in : integer := 0 ;
75+ signal s_sync : std_logic := '0' ;
76+ signal s_en : std_logic := '1' ;
77+ signal s_state : t_IQ_STATE := S_0;
78+
79+ begin
80+ -------- Clock generation --------
81+ f_gen_clk(c_clk_freq, clk);
82+
83+ -------- Test Processes --------
84+ p_gen_stimulus: process
85+ begin
86+ s_sync <= '1' ;
87+ rst <= '1' ;
88+ f_wait_cycles(clk, 1 );
89+ rst <= '0' ;
90+ f_wait_cycles(clk, 1 );
91+ for i in 0 to c_N- 2 loop -- Loop through I values
92+ s_i_in <= 2 ** i;
93+ for j in 0 to c_N- 2 loop -- Loop through Q values
94+ s_q_in <= 2 ** j;
95+ s_sync <= '0' ;
96+ f_wait_cycles(clk, 1 );
97+ f_wait_cycles(clk, 50 ); -- Wait 50 cycles in each value
98+ end loop ;
99+ end loop ;
100+ report " Finished!" ;
101+ std.env.finish ;
102+ end process ;
103+
104+ p_modulator : process (clk) -- Generate the expected outputs
105+ begin
106+ if rising_edge (clk) then
107+ if rst = '1' then
108+ s_state <= S_0;
109+ s_i_mod <= (others => '0' );
110+ s_q_mod <= (others => '0' );
111+ elsif s_en = '0' then
112+ s_state <= S_0;
113+ s_i_mod <= std_logic_vector (to_signed (s_i_in, c_N));
114+ s_q_mod <= std_logic_vector (to_signed (s_q_in, c_N));
115+ elsif s_sync = '1' or s_state = S_3PI2 then
116+ s_state <= S_0;
117+ s_i_mod <= std_logic_vector (to_signed (s_i_in, c_N));
118+ s_q_mod <= std_logic_vector (to_signed (s_q_in, c_N));
119+ elsif s_state = S_0 then
120+ s_state <= S_PI2;
121+ s_i_mod <= std_logic_vector (to_signed (- s_q_in, c_N));
122+ s_q_mod <= std_logic_vector (to_signed (s_i_in, c_N));
123+ elsif s_state = S_PI2 then
124+ s_state <= S_PI;
125+ s_i_mod <= std_logic_vector (to_signed (- s_i_in, c_N));
126+ s_q_mod <= std_logic_vector (to_signed (- s_q_in, c_N));
127+ elsif s_state = S_PI then
128+ s_state <= S_3PI2;
129+ s_i_mod <= std_logic_vector (to_signed (s_q_in, c_N));
130+ s_q_mod <= std_logic_vector (to_signed (- s_i_in, c_N));
131+ end if ;
132+ end if ;
133+ end process ;
134+
135+ p_assert: process (clk)
136+ begin
137+ if rising_edge (clk) then
138+ -- Delay the outputs to match core delay
139+ s_i_mod_d0 <= s_i_mod;
140+ s_q_mod_d0 <= s_q_mod;
141+ if s_sync = '0' then -- Skip first clocks where output is undefined
142+ assert signed (s_i_mod_d0) = signed (s_i_out)
143+ report " Error in I output value " &
144+ to_string(s_i_mod_d0) & " | " &
145+ to_string(s_i_out)
146+ severity failure ;
147+ assert signed (s_q_mod_d0) = signed (s_q_out)
148+ report " Error in Q output value " &
149+ to_string(s_q_mod_d0) & " | " &
150+ to_string(s_q_out)
151+ severity failure ;
152+ end if ;
153+ end if ;
154+ end process ;
155+
156+ -------- Entity instantiation --------
157+ UUT: entity work.gc_iq_modulator
158+ generic map (
159+ g_N => c_N
160+ )
161+ port map (
162+ clk_i => clk,
163+ en_i => s_en,
164+ rst_i => rst,
165+ sync_p1_i => s_sync,
166+ i_i => std_logic_vector (to_signed (s_i_in, c_N)),
167+ q_i => std_logic_vector (to_signed (s_q_in, c_N)),
168+ i_o => s_i_out,
169+ q_o => s_q_out
170+ );
171+
172+ end architecture tb;
0 commit comments