CAD SART transmisja szeregowa z wykorzystaniem RS-232 rawski@tele.pw.edu.pl http://rawski.zpt.tele.pw.edu.pl/
Standard RS 232 (1) Standard RS-232 (Recommended Standard) został wprowadzony w 1962 roku przez Electronic Industries Association (EIA) w celu normalizacji interfejsu pomiędzy urządzeniem danych DTE (Data Terminal Equipment) a urządzeniem DCE (Data Commumication Equipment). Pomimo tego, że główny nacisk położono na zdefiniowanie interfejsu pomiędzy terminalem ( DTE) a modemem (DCE), to standard ten jest również bardzo często stosowany przy szeregowej transmisji danych pomiędzy różnymi typami urządzeń DTE. W sierpniu 1969 roku EIA wprowadziło zrewidowaną normę oznaczoną RS-232C, która prezentuje powszechnie akceptowany sposób transmisji danych na nieduże odległości (do 15 m), z niewielką szybkością (do 20 kbitów/s), przez niesymetryczne łącze.
Standard RS 232 (2)
Standard RS 232 (3) W standardzie RS-232 transmisja danych odbywa się szeregowo bit po bicie, przy czym istnieje możliwość asynchronicznej transmisji znakowej lub transmisji synchronicznej. Asynchroniczna transmisja znakowa polega na przesyłaniu pojedynczych znaków, które posiadają ściśle określony format. Początek znaku stanowi bit startu, jałowy z punktu widzenia przesyłanej informacji i służący jedynie celom synchronizacyjnym. Po nim następuje pole danych, na które wprowadza się kolejne bity stanowiące treść znaku. Bezpośrednio za polem danych przewidziano bit kontrolny, służący zabezpieczeniu informacji znajdującej się na polu danych. Transmitowany znak kończy jeden lub dwa bity stopu.
Standard RS 232 (4)
Standard RS 232 (5) Przedstawiony poniżej zespół bitów tworzy jednostkę informacyjną - ramkę Cisza Start Pole danych Bit(y) stopu Cisza d0 d1 d2 d3 d4 d5 d6 d7 lub bit kont rolny 1 bit 7 lub 8 bitów 1 lub 2 bity
Standard RS 232 (6) W ramach jednostki informacyjnej bity przesyłane są synchronicznie - zgodnie z taktem nadajnika. Natomiast poszczególne jednostki są przesyłane asynchronicznie - ich wyprowadzanie nie jest synchronizowane żadnym sygnałem, a więc odstęp pomiędzy nimi jest dowolny. Czas trwania bitu w jednostce informacyjnej nazywa się odstępem jednostkowym. Jego odwrotność określa szybkość transmisji w bodach (1 bd = 1 bit/s). Typowe wartości szybkości transmisji przy asynchronicznej transmisji znakowej wynoszą: 1200, 2400, 4800, 9600 bd, co przy założeniu 10-bitowej długości jednostki informacyjnej i przysłaniu znaków bezpośrednio jeden za drugim odpowiada 120, 240, 480, 960 znakom na sekundę.
Płytka laboratoryjna DE2-70 Education Board Wykorzystane układy programowalne: - Cyclone II EP2C70F896C6 Złącza: - wbudowany USB-Blaster - 10/100 Ethernet - RS232 - video out (potrójny VGA 10-bit DAC) - 2 wejścia video in (NTSC/PAL/multi-format) - USB 2.0 (typ A I typ B) - PS/2 - line in/out, mic in (24-bit audio CODEC) - 2 złącza rozszerzeń z zabezpieczeniem diodowym - port podczerwieni Pamięć: - 2 SDRAM 32 MBs, - SSRAM 2 MB, - flash 8 MB - slot dla kart pamięci SD Dodatkowe elementy interfejsu użytkownika: - wyświetlacz LCD 16 2-8 wyświetlaczy 7-segmentowych - 18 przełączników - 18 diod LEDs (czerwonych) - 9 diod LEDs (zielonych) - 4 przyciski z filtracją drgań Oscylatory kwarcowe: - 50 MHz dla FPGA - 28,63 MHz dla zastosowań video - wejście SMA dla zewnętrznego sygnału zegarowego
Płytka laboratoryjna DE2-70 Education Board
Moduł SART Simple Asynchronous Receiver Transmitter send sygnał do wysłania danych z portu BusIn[] BusIn[ ] dane do wysłania RxD linia odbiorcza dataready sygnał odebrania danych dane na szynie BusOut[] BusOut[ ] odebrane dane TxD linia nadawcza readytosend sygnał gotowości do wysłania send BusIn[7..0] RxD clock dataready BusOut[7..0] TxD readytosend
Testowanie modułu SART
Kontroler (1) library ieee; use ieee.std_logic_1164.all; entity kontroler is port( clock : in std_logic; reset : in std_logic; ischar : in std_logic; cleartosend : in std_logic; char : in std_logic_vector(7 downto 0); send : out std_logic; chartosend : out std_logic_vector(7 downto 0) ); end kontroler; architecture RTL of kontroler is signal storechar : std_logic; signal charbuffer : std_logic_vector(7 downto 0); type AUT_STATE_TYPE is ( idle, receiving, sending, sent ); signal aut_reg, aut_next : AUT_STATE_TYPE; signal send_next : std_logic; Bufor do przechowania znaku Automat odbierająco - nadający Synchronizacja wyjścia send -- Buffer process(reset, clock) if reset = '1' then charbuffer <= (others => '0'); elsif rising_edge(clock) then if storechar = '1' then charbuffer <= char; else charbuffer <= charbuffer; chartosend <= charbuffer; -- Output bufer for 'send' process(reset, clock) if reset = '1' then send <= '0'; elsif rising_edge(clock) then send <= send_next;
-- Automat process(reset, clock) if reset = '1' then aut_reg <= idle; elsif rising_edge(clock) then aut_reg <= aut_next; process(aut_reg, ischar, cleartosend) storechar <= '0'; send_next <= '0'; case aut_reg is when idle => if ischar = '1' then aut_next <= receiving; else aut_next <= idle; when receiving => storechar <= '1'; aut_next <= sending; Kontroler (2) Poczekaj na gotowość SART do wysyłania Wyślij Czekaj na sygnał, że jest znak Przechowaj znak when sending => send_next <= '1'; if cleartosend = '1' then aut_next <= sent; else aut_next <= sending; when sent => send_next <= '1'; if cleartosend = '1' then aut_next <= sent; else if ischar = '1' then aut_next <= receiving; else aut_next <= idle; when others => aut_next <= idle; end case; end RTL;
Moduł SART Schemat blokowy send Automat nadawczy readytosend BusIn[7..0] Rejestr VCC Data[7..0] Multiplekser TxD RxD GND Rejestr przesuwający odbiorczy BusOut[7..0] Automat odbiorczy dataready clock Generacja zegara 14
Automat odbiorczy Cisza Start d1 d2 d3 d4 d5 d6 d7 d8 Bit(y) stopu Cisza 1 r_data2 r_data1 0 r_start r_data3 r_data4 r_idle 1 0 Uaktywnij rejestr przesuwający r_stop2 Wystaw sygnał dataready r_stop1 r_data8 r_data7 r_data6 r_data5
Automat nadawczy 0 1 t_start t_data1 t_data2 t_data3 t_data4 t_idle 1 0 t_stop2 t_stop1 t_data8 t_data7 t_data6 t_data5 send Automat nadawczy readytosend BusIn[7..0] Rejestr VCC Data[7..0] Multiplekser TxD GND
SART realizacja (1) library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.mylib.all; entity simpleuart is generic( INCLK : natural := 25175000; BAUDRATE : natural := 9600 ); port( clock : in std_logic; reset : in std_logic; send : in std_logic; rxd : in std_logic; data_in : in std_logic_vector(7 downto 0); data_ready : out std_logic; clear_to_send : out std_logic; txd : out std_logic; data_out : out std_logic_vector(7 downto 0) ); end simpleuart; architecture RTL of simpleuart is constant CNT_WIDTH : natural := log2_ceil (INCLK / BAUDRATE); constant DIVVALUE : natural := INCLK /BAUDRATE; constant PULSVALUE : natural := DIVVALUE / 2; Parametry określające: częstotliwość zegara systemowego (INCLK) pożądaną szybkość transmisji (BAUDRATE) Parametry potrzebne do generacji zegara odpowiedniego dla uzyskania szybkości transmisji podanej jako parametr BAUDRATE
SART realizacja (2) signal oclkt : std_logic; signal oclkr : std_logic; signal cntt : unsigned(cnt_width-1 downto 0); signal cntr : unsigned(cnt_width-1 downto 0); -- Receiver FSM states type RCV_STATE_TYPE is ( r_idle, r_start, r_data1, r_data2,r_data3,r_data4,r_data5,r_data6,r_data7,r_data8, r_stop1, r_stop2 ); signal rcv_reg, rcv_next : RCV_STATE_TYPE; signal ReceivedData : std_logic_vector(7 downto 0); signal datainenable : std_logic; -- Transmiter FSM states type TRS_STATE_TYPE is ( t_idle, t_start, t_data1, t_data2,t_data3,t_data4,t_data5,t_data6,t_data7,t_data8, t_stop1, t_stop2 ); signal trs_reg, trs_next : TRS_STATE_TYPE; signal DataToSend : std_logic_vector(7 downto 0); signal dataoutload : std_logic; signal outbitctr : unsigned(3 downto 0); Sygnały zegarowe dla nadajnika (oclkt) i odbiornika (oclkr) Liczniki dzielników częstotliwości Bufor odebranych danych i sygnał enable dla tego bufora Bufor nadawanych danych i sygnał load dla tego bufora Sygnał select multipleksera wysyłającego dane
process(reset, clock) if reset = '1' then cntr <= (others => '0'); elsif rising_edge(clock) then if cntr = DIVVALUE then cntr <= (others => '0'); else cntr <= cntr + 1; process(reset, clock) if reset = '1' then oclkr <= '0'; elsif rising_edge(clock) then if cntr < PULSVALUE then oclkr <= '0'; else oclkr <= '1'; SART realizacja (2) Liczniki dzielnika częstotliwości dla INCLK = 10 MHz i BAUDRATE = 1Mbit DIVVALUE = 10 Generator zegara dla PULSVALUE = 5 process(reset, clock) if reset = '1' then cntt <= (others => '0'); oclkt <= '0'; elsif rising_edge(clock) then if cntt = DIVVALUE then cntt <= (others => '0'); else cntt <= cntt + 1; if cntt < PULSVALUE then oclkt <= '0'; else oclkt <= '1';
SART realizacja (3) process(reset, oclkr) if reset = '1' then ReceivedData <= (others => '0'); elsif rising_edge(oclkr) then if DataInEnable = '1' then ReceivedData(7) <= rxd; shift_reg: for i in 7 downto 1 loop ReceivedData(i-1) <= ReceivedData(i); end loop; else ReceivedData <= ReceivedData; data_out <= ReceivedData; reset rxd DataInEnable oclkr data_out
process(reset, oclkr) if reset = '1' then rcv_reg <= r_idle; elsif rising_edge(oclkr) then rcv_reg <= rcv_next; process(rcv_reg, rxd) datainenable <= '0'; data_ready <= '0'; case rcv_reg is when r_idle => if (rxd = '1') then rcv_next <= r_idle; else rcv_next <= r_start; when r_start => datainenable <= '1'; rcv_next <= r_data1; when r_data1 => datainenable <= '1'; rcv_next <= r_data2; when r_data2 => datainenable <= '1'; rcv_next <= r_data3; SART realizacja (4) Uaktywnij rejestr przesuwający Dane gotowe when r_data3 => datainenable <= '1'; rcv_next <= r_data4; when r_data4 => datainenable <= '1'; rcv_next <= r_data5; when r_data5 => datainenable <= '1'; rcv_next <= r_data6; when r_data6 => datainenable <= '1'; rcv_next <= r_data7; when r_data7 => datainenable <= '1'; rcv_next <= r_data8; when r_data8 => rcv_next <= r_stop1; when r_stop1 => data_ready <= '1'; rcv_next <= r_stop2; when r_stop2 => if (rxd = '1') then rcv_next <= r_idle; else rcv_next <= r_start; when others => rcv_next <= r_idle; end case;
SART realizacja (4) process(reset, oclkt) if reset = '1' then DataToSend <= (others => '0'); elsif rising_edge(oclkt) then if dataoutload = '1' then DataToSend <= data_in; else DataToSend <= DataToSend; process(reset, oclkt) if reset = '1' then trs_reg <= t_idle; elsif rising_edge(oclkt) then trs_reg <= trs_next; process(trs_reg, send) dataoutload <= '0'; outbitctr <= to_unsigned(0, 4); clear_to_send <= '0'; Bufor danych do wysłania Czekaj na sygnał rozpoczęcia wysyłania Zatrzaśnij dane do wysyłania Sygnał sterujący multiplekserem wysyłającym case trs_reg is when t_idle => if (send = '0') then clear_to_send <= '1'; trs_next <= t_idle; else clear_to_send <= '0'; dataoutload <= '1'; trs_next <= t_start; when t_start => outbitctr <= to_unsigned(1, 4); trs_next <= t_data1; when t_data1 => outbitctr <= to_unsigned(2, 4); trs_next <= t_data2; when t_data2 => outbitctr <= to_unsigned(3, 4); trs_next <= t_data3; when t_data3 => outbitctr <= to_unsigned(4, 4); trs_next <= t_data4; when t_data4 => outbitctr <= to_unsigned(5, 4); trs_next <= t_data5; when t_data5 => outbitctr <= to_unsigned(6, 4); trs_next <= t_data6;
SART realizacja (4) when t_data6 => outbitctr <= to_unsigned(7, 4); trs_next <= t_data7; when t_data7 => outbitctr <= to_unsigned(8, 4); trs_next <= t_data8; when t_data8 => outbitctr <= to_unsigned(9, 4); trs_next <= t_stop1; when t_stop1 => outbitctr <= to_unsigned(10, 4); trs_next <= t_stop2; when t_stop2 => outbitctr <= to_unsigned(10, 4); clear_to_send <= '1'; if (send = '0') then trs_next <= t_idle; else dataoutload <= '1'; trs_next <= t_start; when others => trs_next <= t_idle; end case; Multiplekser wysyłający Układ gotowy do kolejnego wysyłania process(reset, oclkt) if reset = '1' then txd <= '1'; elsif rising_edge(oclkt) then case outbitctr is when to_unsigned(0, 4) => txd <= '1'; when to_unsigned(1, 4) => txd <= '0'; when to_unsigned(2, 4) => txd <= DataToSend(0); when to_unsigned(3, 4) => txd <= DataToSend(1); when to_unsigned(4, 4) => txd <= DataToSend(2); when to_unsigned(5, 4) => txd <= DataToSend(3); when to_unsigned(6, 4) => txd <= DataToSend(4); when to_unsigned(7, 4) => txd <= DataToSend(5); when to_unsigned(8, 4) => txd <= DataToSend(6); when to_unsigned(9, 4) => txd <= DataToSend(7); when to_unsigned(10, 4) => txd <= '1'; when others => txd <= '1'; end case;
Układ realizujący echo SART Kontroler Licznik odebranych znaków Licznik nadanych znaków Konwertery bin -> bcd Sterownik wyświetlacznem 7-segmentowym
Realizacja SART wyniki Fitter Summary Top-level Entity Name echo_kontroler Family Cyclone II Device EP2C70F896C6 Total logic elements 213 / 68,416 ( < 1 % ) Total pins 42 / 622 ( 7 % ) Total virtual pins 0 Total memory bits 0 / 1,152,000 ( 0 % ) Embedded Multiplier 0 / 300( 0 % ) Total PLLs 0 / 4( 0 % ) Clock skew jest zjawiskiem występującym w układach synchronicznych, gdy zbocze sygnału zegarowego pojawia się na wejściach zegarowych poszczególnych komponentów w różnych chwilach czasowych. Jak to pojawiło się w naszym projekcie?
Ripple and/or gated clocks process(reset, clock) if reset = '1' then cntr <= (others => '0'); elsif rising_edge(clock) then if cntr = DIVVALUE then cntr <= (others => '0'); else cntr <= cntr + 1; process(reset, clock) if reset = '1' then oclkr <= '0'; elsif rising_edge(clock) then if cntr < PULSVALUE then oclkr <= '0'; else oclkr <= '1';
Clock skew d1 d1 d1 Dzielnik częstotliwości clk1 clk2 clk Generacja zegara Zmiana na sygnale danych dociera do przerzutnika przed zboczem zegara
Dystrybucja zegara Sieci dystrybucji sygnału zegarowego są tak projektowane tak, aby zminimalizować efekt clock skew Kompilator automatycznie uznał sygnały oclkt i oclkr za sygnały zegarowe i będzie dystrybuował je z wykorzystaniem globalnych linii dystrybucji zegara. Lepiej jednak unikać takich rozwiązań!
Clock enable d1 d1 d1 ena1 ena2 clk Generacja sygnału enable
Wykorzystanie clock enable signal clkenat : std_logic; signal clkenar : std_logic; signal cntt : unsigned(cnt_width-1 downto 0); signal cntr : unsigned(cnt_width-1 downto 0); process(reset, clock) if reset = '1' then clkenar <= '0'; elsif rising_edge(clock) then if cntr = PULSVALUE then clkenar <= '1'; else clkenar <= '0'; process(reset, clock) if reset = '1' then rcv_reg <= r_idle; elsif rising_edge(clock) then if clkenar = '1'then rcv_reg <= rcv_next; else rcv_reg <= rcv_reg; Sygnały enable, które będą wykorzystywane do kontrolowania działania elementów synchronicznych Liczniki będą wykorzystane do generowania sygnałów enable Sygnał enable generowany jest raz na DIVVALUE cykli zegara systemowego dokładnie po PULSVALUE cykli od rozpoczęcia liczenia Wszystkie elementy synchroniczne taktowane są zegarem systemowym Reagują jednak tylko w jedynym cyklu zegarowym Układ jest w pełni synchroniczny
Realizacja SART wyniki Fitter Summary Top-level Entity Name echo_kontroler Family Cyclone II Device EP2C70F896C6 Total logic elements 211 / 68,416 ( < 1 % ) Total pins 42 / 622 ( 7 % ) Total virtual pins 0 Total memory bits 0 / 1,152,000 ( 0 % ) Embedded Multiplier 0 / 300( 0 % ) Total PLLs 0 / 4( 0 % ) Te efekty są nam znane. Należy synchronizować sygnały wyjściowe.
Synchronizacja wyjść signal txd_reg, txd_next : std_logic; signal clear_to_send_reg, clear_to_send_next : std_logic; signal data_ready_reg, data_ready_next : std_logic; when to_unsigned(0, 4) => txd_next <= '1'; if (send = '0') then clear_to_send_next <= '1'; process(reset, clock) if reset = '1' then txd_reg <= '1'; data_ready_reg <= '0'; clear_to_send_reg <= '0'; elsif rising_edge(clock) then if clkenat = '1' then txd_reg <= txd_next; clear_to_send_reg<= clear_to_send_next; data_ready_reg <= data_ready_next; else txd_reg <= txd_reg; clear_to_send_reg <= clear_to_send_reg; data_ready_reg <= data_ready_reg; txd <= txd_reg; clear_to_send <= clear_to_send_reg; data_ready <= data_ready_reg; Deklaracja sygnałów nazwa_reg i nazwa_next wykorzystywanych do synchronizacji sygnału wyjściowego nazwa Ustalanie sygnałów nazwa_next wewnątrz układu o jeden cykl zegara wcześniej Zatrzaskiwanie sygnałów nazwa_next w rejestrach nazwa_reg Wyprowadzenie sygnałów nazwa_reg na wyjścia nazwa
Realizacja SART wyniki Fitter Summary Top-level Entity Name echo_kontroler Family Cyclone II Device EP2C70F896C6 Total logic elements 213 / 68,416 ( < 1 % ) Total pins 42 / 622 ( 7 % ) Total virtual pins 0 Total memory bits 0 / 1,152,000 ( 0 % ) Embedded Multiplier 0 / 300( 0 % ) Total PLLs 0 / 4( 0 % ) Wydaje się być w porządku
SART - Testowanie Układ gubi synchronizację
SART Brak synchronizacji Cisza Start d1 d2 d3 d4 d5 d6 d7 d8 Bit(y) stopu Cisza Generator kwarcowy Płytki DE2-70 = 50 MHz DIVALUE = 50000000 /9600 = 5208 (,3333) 50 MHz / 5208 = 9600,61 Hz Błąd w dopasowaniu częstotliwości zegarów powoduje zgubienie synchronizacji Cisza Start d1 d2 d3 d4 d5 d6 d7 d8 Bit(y) stopu Cisza Rozwiązaniem jest wykorzystanie bitu startu do zsynchronizowania układu
Synchronizacja wewnątrzramkowa process(reset, clock) if reset = '1' then cntr <= (others => '0'); elsif rising_edge(clock) then if rcv_reg = r_idle and rxd = '1' then cntr <= (others => '0'); else if cntr = DIVVALUE then cntr <= (others => '0'); else cntr <= cntr + 1; Licznik sterujący odbiornikiem jest zerowany, gdy odbiornik jest w stanie idle i na wejściu rxd jest stan wysoki Start zegara na początku ramki sprawia, że symbole w ramce są próbkowane prawie dokładnie w połowie ich trwania. Przez czas trwania jednej ramki zegar nie jest w stanie się rozsynchronizować
Realizacja SART wyniki Fitter Summary Top-level Entity Name echo_kontroler Family Cyclone II Device EP2C70F896C6 Total logic elements 207 / 68,416 ( < 1 % ) Total pins 42 / 622 ( 7 % ) Total virtual pins 0 Total memory bits 0 / 1,152,000 ( 0 % ) Embedded Multiplier 0 / 300( 0 % ) Total PLLs 0 / 4( 0 % ) Układ odbiorczy jest zatrzymywany ilekroć odbiornik jest w stanie idle i na linii rxd nic nie jest nadawane
SART - Testowanie Ciągle cos nie jest dobrze? Pojedyncze znaki przesyłane są bezbłędnie. Układ gubi synchronizację przy wysyłaniu ciągu znaków jeden za drugim
SART Brak synchronizacji Jeśli ramki są nadawane jedna za drugą, układ nie wchodzi do stanu idle, a więc się mechanizm synchronizacji nie działa
Synchronizacja międzyramkowa Cisza Start d1 d2 d3 d4 d5 d6 d7 d8 Bit(y) stopu Cisza 1 0 r_start r_data1 r_data2 r_data3 r_data4 r_idle 0 1 r_stop2 r_stop1 r_data8 r_data7 r_data6 r_data5 Należy zmienić automat tak, by po każdej ramce automat wchodził w stan idle
Synchronizacja międzyramkowa type RCV_STATE_TYPE is ( r_idle, r_start, r_data1, r_data2,r_data3,r_data4,r_data5,r_data6,r_data7,r_data8, r_stop1 ); signal rcv_reg, rcv_next : RCV_STATE_TYPE; when r_data8 => data_ready_next <= '1'; rcv_next <= r_stop1; when r_stop1 => rcv_next <= r_idle; when others => rcv_next <= r_idle; end case; Tylko jeden stan stop; Po pierwszym bicie stopu automat przechodzi do stanu idle
Realizacja SART wyniki Fitter Summary Top-level Entity Name echo_kontroler Family Cyclone II Device EP2C70F896C6 Total logic elements 207 / 68,416 ( < 1 % ) Total pins 42 / 622 ( 7 % ) Total virtual pins 0 Total memory bits 0 / 1,152,000 ( 0 % ) Embedded Multiplier 0 / 300( 0 % ) Total PLLs 0 / 4( 0 % )
Testowanie z wykorzystaniem testbench a (1) Emulacja nadawania znaków send BusIn[7..0] readytosend UUT dataready BusOut[7..0] Emulacja odbierania znaków Generacja zegara clock RxD TxD Emulacja linii transmisyjnej
Testowania z wykorzystaniem testbench a (2) library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.std_logic_textio.all; use std.textio.all; entity simpleuart_tb is end simpleuart_tb; architecture testbench of simpleuart_tb is constant T : time := 20 ns; component simpleuart is generic( INCLK : natural := 25175000; BAUDRATE : natural := 9600 ); port( clock : in std_logic; reset : in std_logic; send : in std_logic; rxd : in std_logic; data_in : in std_logic_vector(7 downto 0); data_ready : out std_logic; clear_to_send : out std_logic; txd : out std_logic; data_out : out std_logic_vector(7 downto 0) ); end component; Biblioteki komunikacji z plikami istniejącymi w danym systemie operacyjnym. Jednostka testbench a nie posiada portów Okres zegara 20 ns, czyli f = 50 MHz Deklaracja komponentu, który podlegał będzie testowaniu
Testowania z wykorzystaniem testbench a (3) signal clock_st : std_logic; signal reset_st : std_logic; signal send_st : std_logic; signal rxd_st : std_logic; signal data_in_st : std_logic_vector(7 downto 0); signal data_ready_rsp : std_logic; signal clear_to_send_rsp: std_logic; signal txd_rsp : std_logic; signal data_out_rsp : std_logic_vector(7 downto 0); signal transmission_line : std_logic; UUT : simpleuart generic map( INCLK => 50000000, BAUDRATE => 9600 ) port map( clock => clock_st, reset => reset_st, send => send_st, rxd => rxd_st, data_in => data_in_st, data_ready => data_ready_rsp, clear_to_send => clear_to_send_rsp, txd => txd_rsp, data_out => data_out_rsp ); Deklaracja sygnałów pobudzeń Deklaracja sygnałów odpowiedzi Deklaracja sygnału linii transmisyjnej Konkretyzacja komponentu, który będzie podlegał testowaniu i podłączenie sygnałów pobudzeń i odpowiedzi
Testowania z wykorzystaniem testbench a (4) clock : process clock_st <= '0'; clock_st <= '1'; wait for T/2; wait for T/2; Proces generacji zegara o częstotliwości f = 50 MHz init : process assert false report "Simulation Start" severity note; reset_st <= '0'; reset_st <= '1'; wait until falling_edge(clock_st); wait; tarnsmission_line : process(txd_rsp) transmission_line <= transport txd_rsp after 33 us; Proces inicjacyjny (reset systemu, komunikat o rozpoczęciu testu, itp.. Proces emulujący linie transmisyjną opóźniającą sygnał o 33 us rxd_st <= transmission_line;
Testowania z wykorzystaniem testbench a (5) generator : process variable c_str : line; send_st <= '0'; data_in_st <= (others => '0'); wait until clear_to_send_rsp = '1'; wait until falling_edge(clock_st); data_in_st <= "01101100"; send_st <= '1'; wait until clear_to_send_rsp = '0'; wait until falling_edge(clock_st); send_st <= '0'; write(c_str, data_in_st); assert false report time'image(now) & ": Wyslano : " & c_str.all severity note; deallocate(c_str); wait until clear_to_send_rsp = '1'; wait until falling_edge(clock_st); data_in_st <= "01101111"; send_st <= '1'; Proces emulujący nadawanie znaków poczekaj na clear_to_send = 1 wystaw dane i sygnał send poczekaj na clear_to_send = 0 ustaw send na 0 Wyświetl komunikat o wysłaniu danych Wyślij kolejny znak wait until clear_to_send_rsp = '0'; wait until falling_edge(clock_st); send_st <= '0'; write(c_str, data_in_st); assert false report time'image(now) & ": Wyslano : " & c_str.all severity note; wait;
Testowania z wykorzystaniem testbench a (6) monitor : process variable c_str : line; wait until data_ready_rsp = '1'; wait until falling_edge(clock_st); write(c_str, data_out_rsp); assert false report time'image(now) & ": Odebrano : " & c_str.all severity note; deallocate(c_str); Proces emulujący odbieranie znaków sim_stop : process wait for 3 ms; assert false report "Simulation stopped severity failure; Proces zatrzymujący symulację po zadanym czasie end;
Wykorzystanie testbench a w MedelSim