Files
AD7766_fw/tb/tb_top.vhd
T

224 lines
7.0 KiB
VHDL

----------------------------------------------------------------------------------
-- Module Name: tb_top
-- Project Name: AD7766_prj
-- Description:
-- Сквозной тест: модель AD7766 -> top -> UART -> разбор кадра в тестбенче.
-- Модель выдаёт группами по DECIM одинаковых слов, поэтому усреднённый
-- отсчёт обязан в точности совпасть со значением группы. Проверяются
-- разрядность, знак, порядок байт, CRC и счётчик кадров.
----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.env.all;
entity tb_top is
generic (
FRAMES : integer := 2 -- сколько кадров проверяем, переопределяется -gFRAMES=N
);
end entity tb_top;
architecture sim of tb_top is
constant CLK_T : time := 20 ns;
constant BAUD : integer := 921600;
constant BIT_T : time := 1 sec / BAUD;
constant DECIM : integer := 10;
constant SPF : integer := 50; -- отсчётов в кадре
constant PAYLOAD_LEN : integer := 2 + 1 + SPF * 3; -- CNT + STATUS + DATA
signal clk : std_logic := '0';
signal run : boolean := true;
signal adc_sdo : std_logic;
signal adc_drdy : std_logic;
signal adc_sclk : std_logic;
signal adc_mclk : std_logic;
signal adc_sdi : std_logic;
signal adc_cs_n : std_logic;
signal adc_sync_pd : std_logic;
signal uart_tx : std_logic;
signal led : std_logic;
signal next_word : std_logic_vector(23 downto 0);
signal word_tick : std_logic;
signal word_idx : integer := 0;
type byte_arr_t is array (natural range <>) of std_logic_vector(7 downto 0);
-- Значения групп: крайние точки шкалы, единицы младшего разряда и оба знака
function grp_value(g : integer) return signed is
variable v : integer;
begin
case g mod 8 is
when 0 => v := 0;
when 1 => v := 8388607; -- +полная шкала
when 2 => v := - 8388608; -- -полная шкала
when 3 => v := 1;
when 4 => v := - 1;
when 5 => v := 5592405; -- 0x555555
when 6 => v := - 5592406; -- 0xAAAAAA как знаковое
when others => v := 1193046; -- 0x123456
end case;
return to_signed(v, 24);
end function;
function crc16_upd(crc : std_logic_vector(15 downto 0);
d : std_logic_vector(7 downto 0))
return std_logic_vector is
variable c : std_logic_vector(15 downto 0) := crc;
variable fb : std_logic;
begin
for i in 7 downto 0 loop
fb := c(15) xor d(i);
c := c(14 downto 0) & '0';
if fb = '1' then
c := c xor x"1021";
end if;
end loop;
return c;
end function;
procedure get_byte(signal rx : in std_logic;
b : out std_logic_vector(7 downto 0)) is
variable v : std_logic_vector(7 downto 0);
begin
wait until rx = '0'; -- фронт старт-бита
wait for BIT_T / 2;
assert rx = '0' report "start bit not confirmed" severity error;
for i in 0 to 7 loop
wait for BIT_T;
v(i) := rx;
end loop;
wait for BIT_T;
assert rx = '1' report "stop bit not at expected position" severity error;
b := v;
end procedure;
begin
clk <= not clk after CLK_T / 2 when run else '0';
next_word <= std_logic_vector(grp_value(word_idx / DECIM));
word_cnt_proc : process
begin
wait until rising_edge(word_tick);
word_idx <= word_idx + 1;
end process word_cnt_proc;
dut : entity work.Top(Behavioral)
generic map(
SYS_CLK_HZ => 50_000_000,
BAUD_RATE => BAUD
)
port map
(
clk => clk,
ADC_SDO => adc_sdo,
ADC_DRDY => adc_drdy,
ADC_SCLK => adc_sclk,
ADC_MCLK => adc_mclk,
ADC_SDI => adc_sdi,
ADC_CS_N => adc_cs_n,
ADC_SYNC_PD => adc_sync_pd,
UART_TX => uart_tx,
LED => led
);
adc : entity work.ad7766_model(model)
port map
(
mclk => adc_mclk,
sync_pd_n => adc_sync_pd,
cs_n => adc_cs_n,
sclk => adc_sclk,
next_word => next_word,
sdo => adc_sdo,
drdy => adc_drdy,
word_tick => word_tick
);
check_proc : process
variable b : std_logic_vector(7 downto 0);
variable prev : std_logic_vector(7 downto 0) := (others => '0');
variable pl : byte_arr_t(0 to PAYLOAD_LEN - 1);
variable crc : std_logic_vector(15 downto 0);
variable crc_rx : std_logic_vector(15 downto 0);
variable cnt_rx : integer;
variable got : signed(23 downto 0);
variable want : signed(23 downto 0);
variable errors : integer := 0;
variable frame_no : integer := 0;
begin
report "start: waiting for first frame";
while frame_no < FRAMES loop
-- Ищем SYNC A5 5A, как это будет делать приёмник на ПК
loop
get_byte(uart_tx, b);
exit when prev = x"A5" and b = x"5A";
prev := b;
end loop;
prev := (others => '0');
for i in 0 to PAYLOAD_LEN - 1 loop
get_byte(uart_tx, b);
pl(i) := b;
end loop;
get_byte(uart_tx, b);
crc_rx(15 downto 8) := b;
get_byte(uart_tx, b);
crc_rx(7 downto 0) := b;
crc := x"FFFF";
for i in 0 to PAYLOAD_LEN - 1 loop
crc := crc16_upd(crc, pl(i));
end loop;
if crc /= crc_rx then
report "frame " & integer'image(frame_no) & ": CRC mismatch" severity error;
errors := errors + 1;
end if;
cnt_rx := to_integer(unsigned(std_logic_vector'(pl(0) & pl(1))));
if cnt_rx /= frame_no then
report "frame " & integer'image(frame_no) & ": FRAME_CNT = " &
integer'image(cnt_rx) severity error;
errors := errors + 1;
end if;
if pl(2) /= x"00" then
report "frame " & integer'image(frame_no) & ": STATUS not zero" severity error;
errors := errors + 1;
end if;
for i in 0 to SPF - 1 loop
got := signed(std_logic_vector'(pl(3 + i * 3) & pl(4 + i * 3) & pl(5 + i * 3)));
want := grp_value(frame_no * SPF + i);
if got /= want then
report "frame " & integer'image(frame_no) & " sample " & integer'image(i) &
": got " & integer'image(to_integer(got)) &
", want " & integer'image(to_integer(want)) severity error;
errors := errors + 1;
end if;
end loop;
report "frame " & integer'image(frame_no) & " parsed OK";
frame_no := frame_no + 1;
end loop;
if errors = 0 then
report "TEST PASSED: frames = " & integer'image(FRAMES) & "";
else
report "TEST FAILED: errors = " & integer'image(errors) severity error;
end if;
run <= false;
stop;
end process check_proc;
end architecture sim;