Skip to content

Commit 763e8ce

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 856cb74 commit 763e8ce

File tree

5 files changed

+191
-5
lines changed

5 files changed

+191
-5
lines changed
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,2 @@
11
files = ["gc_iq_demodulator_tb.vhd",
2-
"../../../modules/dsp/gc_iq_demodulator.vhd"]
3-
# modules = {"local" : [
4-
# "../../../modules/dsp/gc_iq_demodulator.vhd"
5-
# ]
6-
# }
2+
"../../../modules/dsp/gc_iq_demodulator.vhd"]
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: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
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;
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)