Skip to content

Commit a1310e6

Browse files
Added iq modulator testbench
Added testbench for the gc_iq_modulator.vhd core. This loops through some I and Q values, generate the expected output sine and asserts the output.
1 parent c93b159 commit a1310e6

File tree

4 files changed

+191
-0
lines changed

4 files changed

+191
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
files = ["gc_iq_modulator_tb.vhd",
2+
"../../../modules/dsp/gc_iq_modulator.vhd",
3+
"../../../modules/dsp/gc_iq_demodulator.vhd"
4+
]
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
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;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
gc_iq_modulator_tb
2+
gc_iq_modulator_tb.ghw
3+
*.cf
4+
*.o
5+
Makefile
6+
work/
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
action = "simulation"
2+
sim_tool = "ghdl"
3+
top_module = "gc_iq_modulator_tb"
4+
5+
modules = {"local" : ["../"]}
6+
7+
ghdl_opt = "--std=08 -fsynopsys -g"
8+
9+
sim_post_cmd = "ghdl -r --std=08 %s --wave=%s.ghw --assert-level=error" % (top_module, top_module)

0 commit comments

Comments
 (0)