224 lines
7.0 KiB
VHDL
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;
|