---------------------------------------------------------------------------------- -- 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;