logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Uzywanie zmiennych i malejaca czestotliwosc maksymalna

zlootawy 13 Paź 2007 16:19 3516 30
  • #1 4374985
    zlootawy
    Poziom 10  
    Posty: 54
    Witam,
    mam nastepujacy problem. Urzadzenie to: vp30-5ff1152

    W moim projekcie mam automat stanow. Automat w ostatnim stanie ma trwac tyle taktow ile uzytkownik zapisze w constants. Przynajmniej tak to rozwiazalem. Czy jedynym sposobem jest zastosowanie zmiennej i zliczanie taktow zegara?

    Kiedy automat wyjdzie z ostatniego stanu zalezy od funkcji IF, ktora kazdorazowo bada kilka warunkow. To sa warunki w stylu "jesli licznik modulo 7 rowna sie zero, w przeciwnym razie jesli licznik minus 1 modulo 5 rowna sie zero itd"

    Bardzo maleje przez to Maximum Frequency. Dlugo trwa "Optimizing unit".

    Bardzo zle na prace ukladu wplywa zapis

    licznik := licznik + 1;

    Z tym zapisem: Max freq 133.672MHz
    Bez tego zapisu: Max freq 30 MHz


    A moze nie uzywac zmiennych tylko inaczej to rozwiazac?

    Co oznacza "Found area constraint ratio of 100 (+ 5) on block"?

    Ktos mi doradzil, ze mozna uzyc Constraint Times, ale nie umiem tego zrobic.

    Moze ktos cos doradzi?

    Pozdrawiam
    Wojtek
  • Pomocny post
    #2 4375239
    J.A
    Poziom 28  
    Posty: 596
    Pomógł: 159
    Ocena: 12
    zlootawy napisał:

    W moim projekcie mam automat stanow. Automat w ostatnim stanie ma trwac tyle taktow,
    ile uzytkownik zapisze w constants. Przynajmniej tak to rozwiazalem. Czy jedynym sposobem
    jest zastosowanie zmiennej i zliczanie taktow zegara?


    zrob licznik ladowany liczba krokow do odmierzenia i licz w dol,
    dzieki temu do dekodowania bedzie tylko jeden bit tegoz licznika,
    a nie wszystkie;
    np. potrzebujesz odmierzyc 8 taktow zegara, do licznika ladujesz
    8-1 i po osmiu taktach stan licznika bedzie FF..FF, najstarszy bit jest
    potrzebnym ci sygnalem, ze odmierzanie skonczone;
    licznik musi byc odpowiednio duzy w stosunku do najwiekszej oczekiwanej zmiennej;

    zlootawy napisał:

    licznik := licznik + 1;
    Z tym zapisem: Max freq 133.672MHz
    Bez tego zapisu: Max freq 30 MHz


    pewnie mialo byc odwrotnie ?
    jak duzy jest ten licznik - 64 bity ?
    bo mniejszy nie spowodowalby takiej redukcji czestotliwosci;
    duze liczniki zreszta tez mozna zoptymalizowac tak, by dzialaly rownie
    szybko jak male;
    bez calego projektu i narzedzia ktorym sie poslugujesz trudno cos wiecej
    powiedziec;

    JA
  • #3 4375473
    mariusz102102
    Poziom 12  
    Posty: 67
    Pomógł: 2
    Szczerze mowiac do konca nie rozumiem......
    Mozesz wstawic kod zrodlowy?

    Pozdrawiam
    Mariusz
  • Pomocny post
    #4 4376607
    pndemon
    Poziom 19  
    Posty: 444
    Pomógł: 35
    Ocena: 18
    Cytat:
    Co oznacza "Found area constraint ratio of 100 (+ 5) on block"?


    po tym wnioskuję że używasz ISE Xilinxa, z tego co się orientuję to oznacza to że zużywasz 5% powierzchni układu, ale najlepiej pogmerać w helpie
    'software manulas' - 'constrains', tam to jest na pewno.
  • #5 4378342
    zlootawy
    Poziom 10  
    Posty: 54
    Witam,
    w zalaczniku dodalem moj projekt, wykonany w Xilinx ISE 9.2, skompresoany do pliku elektroda.rad. Oprocz tego dodalem wszystkie pliki vhd, ktore wchodza w jego sklad skompresowane w pliku pliki.rad. Plik gora.vhd jest plikiem najwyzszym. Interesujacy mnie kod znajduje sie w pliku kontroler.vhd. Gora.vhd to tylko opakowanie do testow itd.

    Jest to kontroler do pamieci SRAM. Okroilem kod tylko do zapisu.

    W pakiecie PKG_SRAM jest zbior constatntow, ktore decyduja o pracy ukladu.

    Dane podawane sa na port P_I_ADC. Stamtad sa odpowiednio porcjowane w rejestrze REG_ADC. Zas automat stanow podaje z REG_ADC na port wyjsciowy VMEMDQ_O paczki danych do zapisu w SRAM.

    Jesli danych do zapisu jest wiecej niz 4 (tryb BURST), wtedy co wielokrotnosc 4 taktow maszyna opuszcza stan zapisu, i wchodzi ponownie do stanu ADRES, gdzie adres sie automatycznie odpowiednio autoinkrementuje. I znowu do trybu ZAPIS, i tak az zostanie zapisane wszystko, po czym uklad wchodzi w IDLE.

    Zmiennych uzywam do odliczania taktow zegara. Zastosowalem odliczanie w dol, ale nie wiem o to chodzilo.

    Zastanawia mnie czy nie mozna by lepiej wymyslic opuszczania stanu ZAPIS. Otoz gdy odliczanie dojdzie do odpoiedniego momentu, wtedy ustawiam flage SIG_ADD_ADDRESS na '1', zas inny proces uruchamiany co takt zegara, bada te flage, i jesli wynosi 1, wtedy przechodzi do stanu ADRES.

    Czestotliwosc maksymalna zmienia mi sie dosyc losowo, od duzej do malej. Nie moge wyczuc momentu, ktory o tym decyduje.

    Moze Wasze wprane oczy podpoiwedza mi, jak to pisac, zeby ta czestotliwosc byla wysoka, a w kazdym razie nie skrajnie niska w stylu 18 MHz.

    Dzieki za wszelkie uwagi

    Pozdrawiam
    Wojtek
    Załączniki:
    • Pliki.rar (4.61 KB) Musisz być zalogowany, aby pobrać ten załącznik.
    • Elektroda.rar (2.1 MB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #6 4378576
    zlootawy
    Poziom 10  
    Posty: 54
    no naprawde, nie wiem od czego ta max freq zalezy...

    zmienilem inny licznik z odliczania w gore na odliczanie w dol. Synteza i radosc, freq wzrosla. Potem symulacja, ponowna synteza (bez zmian w kodzie) i znow maxfreq niska.

    Zauwazylem, ze w tym komunikacie:

    "Found area constraint ratio of 100 (+ 5) on block top1, actual ratio is 21"

    zmienia sie liczba ratio. Dla 21 jest zle. Czasem jest mniejsza, wtedy jest ok.
  • #7 4378730
    sepher
    Poziom 19  
    Posty: 301
    Pomógł: 21
    Ocena: 4
    Ten komunikat oznacza, że ustawiono "ograniczenie" dla powierzchni projektu na 100% układu (czyli ograniczenia nie ma). Actual ratio oznacza ile procent układu jest zajęte. Jeśli projekt działa źle przy wzroście tej wartości, to pewnie coś syntetyzowane jest nie do końca tak jak trzeba (i całość się niepotrzebnie rozbudowuje).
  • #8 4378936
    mariusz102102
    Poziom 12  
    Posty: 67
    Pomógł: 2
    Cytat:
    Interesujacy mnie kod znajduje sie w pliku kontroler.vhd.


    A ja w tych rar-ach nie znalazlem plik kontroler.vhd...... :)
    Moze go pokazesz? ;)

    Pozdrawiam
    Mariusz
  • Pomocny post
    #9 4378942
    pndemon
    Poziom 19  
    Posty: 444
    Pomógł: 35
    Ocena: 18
    
     process(P_I_CLK,P_I_RESET_N)
    variable licznik : integer range 0 to 25 := 0;
     begin						
      if P_I_RESET_N = '0' then
    	
    	REG_WR_N     <= '0';  
    	REG_BENA_N	 <= '0';	 	                          
    	REG_ADDR     <= ( others => '0' ) ;             
    	REG_DATA     <= ( others => '0' ) ; 
    	P_O_DATA 	 <= ( others => '0' ) ;
    	REG_STROBE_N <= '0';
    
    	FOR a IN 0 TO WORDS_NUMBER_TO_WRITE - 1 LOOP
    		REG_ADC(a) <= (others => '0');
    	END LOOP;
    
      elsif P_I_CLK'event and P_I_CLK = '1' then
    	REG_STROBE_N <= P_I_STROBE_N ;
    	REG_WR_N     <= P_I_WR_N  ; 
    	REG_DATA     <= P_I_DATA ;
    	P_O_DATA 	 <= REG_O_DATA ;
    	P_O_ACK 		 <= REG_ACK ;
    	REG_ADDR     <= P_I_ADDR  ; 
    
    	
    
    	if REG_STROBE_N = '0' and REG_LAST_STROBE_N = '1' then 
    			
    		FOR a IN 0 TO WORDS_NUMBER_TO_WRITE - 1 LOOP
    								
    			FOR i IN 0 TO MAX_ADC_WITHIN_WORD - 1 LOOP
    										
    						--tutaj otrzymuje w REG_ADC dane do zapisu upakowane w sramowe rozmiary
    									
    				IF licznik < ADC_NUMBER THEN
    					REG_ADC(a)(i*(DATA_SIZE_OF_ADC)+DATA_SIZE_OF_ADC-1 downto i*(DATA_SIZE_OF_ADC)) <= P_I_ADC(licznik);
    					licznik := licznik + 1; 
    				END IF;
    			END LOOP;
    									
    		END LOOP;
    	end if;
      END IF;
      
     end process ;
    

    1. nigdy nie robiłem licznika na liczbach całkowitych, w ogóle uważam że nie należy ich stosować, ale być może syntezer sobie z tym akurat radzi
    2. cała ta konstrukcja to trochę pomieszanie rejestrów z licznikiem, ogólnie nie chcę się spierać ale uważam że nie należy tworzyć takich kombajnów, bo tylko utrudniają proces analizy
    3. stosujesz asynchroniczny reset - jak nie musisz to unikaj go jak ognia
    4. może coś przeoczyłem, ale nie widzę abyś resetował tam licznik, to się wywali już podczas symulacji kiedy przekroczysz zakres liczby
    5. najlepiej (moim skromnym zdaniem) licznik powinien wyglądać tak:
    
    if rising_edge(clk) then
      if rst = 1 then
        licznik <= (others <= '0');
      elsif en = '1' then
        if load = '1' then
          licznik <= liczba;
        else
          licznik <= licznik - 1;
        end if;
      end if;
    end if;

    w zasadzie wszystkie dostępnie konstrukcje liczników są dostępne w Edit-> Language Templates, wszelkie inne są niemile widziane
    6. jak przebudujesz licznik to nie będziesz musiał stosować operatora '<', co tworzy rozbudowaną logikę, po prostu muszą być sprawdzane wszystkie warunki równości w danym zakresie
    7. poza tym całość wygląda jakby licznik sam siebie kontrolował :)
    8. na koniec te dwie pętle, przyznam że wprawiają mnie one trochę w zawrót głowy, pamiętaj że stosowanie pętli to bardzo niebezpieczna zabawa
    9. najlepiej jakbyś opisał co ten proces ma robić
  • #10 4379015
    zlootawy
    Poziom 10  
    Posty: 54
    mariusz102102 napisał:
    Cytat:
    Interesujacy mnie kod znajduje sie w pliku kontroler.vhd.


    A ja w tych rar-ach nie znalazlem plik kontroler.vhd...... :)
    Moze go pokazesz? ;)

    Pozdrawiam
    Mariusz



    :-)
    pamiec.vhd
  • #11 4379127
    pndemon
    Poziom 19  
    Posty: 444
    Pomógł: 35
    Ocena: 18
    Idąc dalej:
    1. proces z maszyna stany wygląda ok
    2. ostatni proces to kolejny kombajn (który też wchodzi w skład maszyny stanu), pamiętaj że tablica to nie jakaś tam tablica, tylko konkretny element pamięciowy i jako taki powinien być używany
    3. jak tworze tego rodzaju rejestry to zazwyczaj (jeśli stanowią coś więcej niż opóźnianie sygnału o 1 cykl) dodaje im linie rst, enable, ew. load jeśli jest potrzebny, do każdego elementu pamięciowego osobno. Dopiero wtedy poprzez automat stanu steruje działaniem każdego rejestru, poprzez sygnały rst, en i load. Wprowadza to dodatkowe pisanie, ale uwierz mi znacznie poprawia działanie - przyspiesza analizę, oraz gwarantuje że powstanie z tego coś co chciałeś. Jeśli powstaje jakiś nadmiar, w postaci dublujących się sygnałów - nie martw się tym, ISE automatycznie podczas optymalizacji scali je jeśli uzna że tak można.
    4. stosowanie takich sygnałów sterujących powoduje, że maszyna stanu jest skromna i szybka, należy unikać wprowadzania maszyny stanu do ścieżki przepływu danych, niech maszyna stanu ustawia tylko sygnały sterujące jakimiś blokami wykonawczymi (innymi procesami, a nawet komponentami)
    5. im dokładniej coś opiszesz tym lepiej dla ciebie, nie polegaj na narzędziach do syntezy, że mają się czegoś domyślać
  • #12 4379244
    mariusz102102
    Poziom 12  
    Posty: 67
    Pomógł: 2
    Wszystkie wskazowki pndemon w pelni celne :)

    Dorzuce jeszcze, ze zamiast zmiennej powinienes urzyc sygnalu. variable nie przechowuje poprzedniej wartosci
    Cytat:
    Unlike signals, variables have neither history nor future, because according to its definition, each variable has only current value. No checking for the last event, time elapsed since the last event, previous value, etc. can be performed on variables.


    Poniezej licznik
    library IEEE;
    use IEEE.std_logic_1164.all;
    use IEEE.std_logic_unsigned.all;
    
    entity counter is
    	port (
    		CLK : in std_logic;
    		SET : in std_logic;
    		Q : out std_logic_vector(3 downto 0)
    	);
    end entity;
    
    architecture counter_arch of counter is
    	signal TEMP_Q : std_logic_vector(3 downto 0);
    begin
    
    	process(CLK)
    	begin
    		if rising_edge(CLK) then
    			if SET = '1' then
    				TEMP_Q <= (others => '1');
    			else
    				TEMP_Q <= TEMP_Q + 1;
    			end if;
    		end if;
    	end process;
    	Q <= TEMP_Q;
    end architecture;
  • #13 4379698
    zlootawy
    Poziom 10  
    Posty: 54
    mariusz102102 napisał:
    Unlike signals, variables have neither history nor future, because according to its definition, each variable has only current value. No checking for the last event, time elapsed since the last event, previous value, etc. can be performed on variables.




    wg. przemyslanych przeze mnie zalozec, powinienem zliczac ile taktow zegara jestem w stanie ZAPIS.

    Czyli w momencie gdy wchodze w ZAPIS uruchamiam komponent z licznikiem i odliczam.Ale gdy musze opuscic stan ZAPIS aby pozniej do niego wrocic...? Przydaloby sie zatrzymac licznik na czas bycia w innym stanie..

    Dodano po 9 [minuty]:

    pndemon napisał:
    Idąc dalej:

    3. jak tworze tego rodzaju rejestry to zazwyczaj (jeśli stanowią coś więcej niż opóźnianie sygnału o 1 cykl) dodaje im linie rst, enable, ew. load jeśli jest potrzebny, do każdego elementu pamięciowego osobno. Dopiero wtedy poprzez automat stanu steruje działaniem każdego rejestru, poprzez sygnały rst, en i load. Wprowadza to dodatkowe pisanie, ale uwierz mi znacznie poprawia działanie - przyspiesza analizę, oraz gwarantuje że powstanie z tego coś co chciałeś. Jeśli powstaje jakiś nadmiar, w postaci dublujących się sygnałów - nie martw się tym, ISE automatycznie podczas optymalizacji scali je jeśli uzna że tak można.


    ciekawe uwagi. mniej wiecej zaczynam to widziec, ale diabel tkwi w szczgolach. tzn. jakbys mogl mniej wiecej opisowo cos wiecej powiedziec. Chodzi o to, zeby nie dawac np. do pierwszego elementu tablicy po prostu przypisania wartosci, tylko obudowac to w komponent, z enabled, load?

    Dodano po 13 [minuty]:

    pndemon napisał:
    
     	if REG_STROBE_N = '0' and REG_LAST_STROBE_N = '1' then 
    			
    		FOR a IN 0 TO WORDS_NUMBER_TO_WRITE - 1 LOOP
    								
    			FOR i IN 0 TO MAX_ADC_WITHIN_WORD - 1 LOOP
    										
    							
    				IF licznik < ADC_NUMBER THEN
    					REG_ADC(a)(i*(DATA_SIZE_OF_ADC)+DATA_SIZE_OF_ADC-1 downto i*(DATA_SIZE_OF_ADC)) <= P_I_ADC(licznik);
    					licznik := licznik + 1; 
    				END IF;
    			END LOOP;
    									
    		END LOOP;
    	end if;
      END IF;
      
     end process ;
    


    3. stosujesz asynchroniczny reset - jak nie musisz to unikaj go jak ognia


    hmmm... spotykalem sie z opiniami aby unikac asynchronicznych sygnalow, ale reseta raczej pozwalano mi zostawic :-)

    Cytat:

    6. jak przebudujesz licznik to nie będziesz musiał stosować operatora '<', co tworzy rozbudowaną logikę, po prostu muszą być sprawdzane wszystkie warunki równości w danym zakresie


    chodzi o porownanie '<' z odu powyzej? Chodzi o to, ze licznik bedzie uruchomiony tylko dla spelnionego warunku, wiec nie bedzie potrzeby go tutaj sprawdzac?

    Cytat:


    8. na koniec te dwie pętle, przyznam że wprawiają mnie one trochę w zawrót głowy, pamiętaj że stosowanie pętli to bardzo niebezpieczna zabawa



    w petlach chodzi o to, aby nadchodzace dane N-bitowe, porozdzielac na M-bitowe slowa, np. nadchodza dane 14-bitowe, chce je zapisac w slowach 36 bitowych. Zapisuje wiec do rejetru 2 razy po 14 czyli 28 bitow i do 36 dobijam zerami.
  • Pomocny post
    #14 4379825
    pndemon
    Poziom 19  
    Posty: 444
    Pomógł: 35
    Ocena: 18
    jak chcesz potrzymać automat przez jakiś czas to robisz tak:
    w automacie:
    
    when bleble =>
      counter_rst <= '1';
      next_state <= count;
    when count =>
      counter_rst <= '0';
      if count_stop = '1' then
        next_state <= dalej;
      else
        next_state <= count;
      end if;
    when dalej =>
    ...
    


    jako licznik dajesz:
    
    if rising_edge(clk) then
      if counter_rst = '1' then
        counter<= (others <= '1');
      else
        counter <= counter - 1;
      end if;
    end if;
    


    no jeszcze tylko count_stop (jako np. instrukcja współbierzna):
    
    count_stop <= '1' when counter = "00000" else '0';
    


    no coś w tym stylu, po prostu musisz składać swój program z takich małych elementów.

    Jeszcze kilka rad:
    1. domykaj if=>else, za wyjątkiem elementów pamiętających
    2. opisuj wszystkie sygnały wyjściowe z maszyny stanów w każdym stanie, inaczej będziesz mieć zatrzaski
    3. najlepiej rozdziel maszynę stanu na na dwa procesy kombinacyjne, w jednym ustalaj tylko przejścia między stanami, a w drugim dekoduj wartości wyjść na podstawie aktualnych stanów
    4. staraj się nie zagnieżdżać if'ów i case'ów w sobie (dotyczy tylko procesów kombinacyjnych)
    5. stosuj case zamiast if, chyba że są tylko 2 przypadki, albo gdy opisujesz elementy pamięciowe

    Cytat:
    ciekawe uwagi. mniej wiecej zaczynam to widziec, ale diabel tkwi w szczgolach. tzn. jakbys mogl mniej wiecej opisowo cos wiecej powiedziec. Chodzi o to, zeby nie dawac np. do pierwszego elementu tablicy po prostu przypisania wartosci, tylko obudowac to w komponent, z enabled, load?


    nie koniecznie jako osobne komponenty wystarczy że nie będziesz mieszać ze sobą elementów wewnątrz jakiś instrukcji, jak opisujesz przy pomocy konstrukcji if=>then=>else licznik to nie wrzucaj tam jeszcze innych rzeczy tylko dlatego że też potrzebują synchronizacji z zegarem. Generalnie jest to dosyć delikatna kwestia, nie mówię że syntezer sobie z tym nie poradzi (może ale nie musi), ale wprowadza to chaos, z drugiej strony ciężko oczekiwać żebyś dla jednego rejestru robił oddzielny komponent. Nie pisałeś tego programu (do syntezy), stąd nie wiesz jak działa, aby być pewnym tego co chcesz otrzymać musisz bazować na konstrukcjach językowych takich jak np. w Language Templates. Wtedy będziesz wiedział że jak napiszesz kod w określony sposób to otrzymasz np licznik.
    Co do tablic, to uważaj na nie, częstym błędem jest to, że jakieś dwa procesy adresują taką tablicę i nawet jeśli zadbasz, że robią to w różnej chwili, a symulacja będzie ok, to po syntezie otrzymasz jakąś kiche. Tablica to pamięć, pamięci mogą być jedno i dwuportowe, do tego o odczycie synchronicznym albo nie, wszelkie możliwości są też zaprezentowane w Language Templates. Najlepiej przejrzyj sobie co tam jest i poskładaj swoją pracę z takich elementów, jest tam dużo "dobrego" kodu - zaglądaj tam często a unikniesz kłopotów. Jeszcze tak rada na sam koniec, jak nie jesteś pewien co powstanie po syntezie z twojego kodu, to wrzuć zsyntezuj tylko dany element i wygeneruj schemat RTL, wtedy zobaczysz na jaki sprzęt został przetłumaczony twój opis (bezwzględnie doradzam sprawdzenie co powstało przy pomocy tych pętli co je używasz, nie jest to zbyt przyjazna konstrukcja dla programu do syntezy).

    Cytat:
    hmmm... spotykalem sie z opiniami aby unikac asynchronicznych sygnalow, ale reseta raczej pozwalano mi zostawic


    http://www.xilinx.com/xlnx/xweb/xil_tx_display.jsp?iLanguageID=1&category=&sGlobalNavPick=&sSecondaryNavPick=&multPartNum=1&sTechX_ID=rw_tim_closure#timing1

    Cytat:
    chodzi o porownanie '<' z odu powyzej? Chodzi o to, ze licznik bedzie uruchomiony tylko dla spelnionego warunku, wiec nie bedzie potrzeby go tutaj sprawdzac?

    jak dasz taki warunek, że np. ma się coś dziać dla n < 5, to syntezer wygeneruje oddzielną logikę dla każdej wartości z przedziału, czyli to tak jakbyś napisał n=0 and n=1 and n=2 and n=3 and n=4

    Cytat:
    w petlach chodzi o to, aby nadchodzace dane N-bitowe, porozdzielac na M-bitowe slowa, np. nadchodza dane 14-bitowe, chce je zapisac w slowach 36 bitowych. Zapisuje wiec do rejetru 2 razy po 14 czyli 28 bitow i do 36 dobijam zerami.

    hmm.. jakoś mi się to nie widzi, spróbuj sobie odpowiedzieć na pytanie jak ty byś to zrobił gdybyś był programem do syntezy, nie bardzo też wiem po co takie coś nie można tego np. zostawić w 2 oddzielnych pamięciach a dane łączyć dopiero na wyjściu:
    RAM_ALL <= RAM_1 & RAM_2;
  • Pomocny post
    #15 4380201
    [g.d.]
    Poziom 18  
    Posty: 174
    Pomógł: 31
    Przyznam że nie czytałem całego wątku, bo rozwlekl sie maksymalnie, ale przedewszystkim constraint PERIOD postawiony na sygnał zegarowy pozwoli Ci ustalić która ścieżka jest krytyczna, a nie szukać na pałę. Jeśli problemem jest szybkość logiki licznika to wstawia sie licznik johnsona, który w ogóle nie ma logiki, ewentualnie jakieś rozwiązanie kompromisowe.

    O tym jak się efektywnie pisze automaty stanów to napisano już kilka książek, a ten wątek powoli staje sie kolejną więc nie będę nic dokładał od siebie.

    http://toolbox.xilinx.com/docsan/xilinx7/books/data/docs/dev/dev0122_17.html
    http://toolbox.xilinx.com/docsan/xilinx82/books/docs/cgd/cgd.pdf
  • Pomocny post
    #16 4380299
    J.A
    Poziom 28  
    Posty: 596
    Pomógł: 159
    Ocena: 12
    zarowno vhdl jak i ise to nie moja bajka, ale moze przydadza ci sie
    takie ogolne uwagi:

    Cytat:
    hmmm... spotykalem sie z opiniami aby unikac asynchronicznych
    sygnalow, ale reseta raczej pozwalano mi zostawic

    taki globalny reset to jakis 'guzik', ktory ma ustawic cala
    logike w dobrze zdefiniowany stan poczatkowy;
    naciskasz reset, F-F sa zerowane, zwalniasz reset;
    jesli ten reset jest asynchroniczny, to ze wzgledu na drobne
    roznice propagacji w fpga wczesniej czy pozniej do czesci przerzutnikow
    przejscie sygnalu zerujacego z aktywnego na nieaktywny dotrze tuz po
    zboczu zegara, do czesci tuz przed i zamiast stanu poczatkowego
    dostaniesz stan zupelnie przypadkowy;
    dlatego reset, ktory ma ustawic elektronike np. po wlaczeniu zasilania
    musi byc synchroniczny;

    jesli dobrze rozumiem, to REG_ADC ma byc pamiecia;
    upewnij sie, ze ise stworzylo pamiec, a nie zestaw F-F
    z multiplekserem na koncu - co tlumaczyloby roznice w Fmax
    od syntezy do syntezy;

    moja uwaga o liczeniu w dol zamiast w gore byla dlatego,
    ze przy takim rozwiazaniu mozesz napisac:

    if (najstarszy_bit_licznika)
    zamiast:
    if (licznik < XXX)
    czyli sprawdzasz stan jednego drutu zamiast dekodowac
    wszystkie bity;

    J.A
  • #17 4385244
    zlootawy
    Poziom 10  
    Posty: 54
    Cytat:

    hmm.. jakoś mi się to nie widzi, spróbuj sobie odpowiedzieć na pytanie jak ty byś to zrobił gdybyś był programem do syntezy, nie bardzo też wiem po co takie coś nie można tego np. zostawić w 2 oddzielnych pamięciach a dane łączyć dopiero na wyjściu:
    RAM_ALL <= RAM_1 & RAM_2;




    Chodzi o to, ze na wejsciu mam sparametryzowana tablice, tzn. zarowno rozmiar jak i ilosc "komorek" ustala uzytkownik. Np. moze to byc 10 elementowa tablica, gdzie kazdy element ma 14 bitow.

    Uklad ma za zadanie upakowac jak najwecej czternastek w np. tzydziestki i te trzydziestki wystawic na zewnatrz. Nie moge na sztywno ustawic RAM_ALL <= RAM_1 & RAM_2. W slowie wyjsciowym moze sie zmiescic dowolna ilosc slow wejsciowych.

    Takie 2 petelki to ladnie robia. Ale rzeczywiscie po syntezie nie mam pamieci tylko f-f.

    Moge sobie wyobrazic, ze dodaje pamiec. Podaje adres, load itd.. ale gdzies tam w srodku taka petla i tak musi wystapic. Nie wiem jak inaczej moge w sposob dynamiczny zawsze otrzymywac poprawne "upakowanie".
  • #18 4385443
    pndemon
    Poziom 19  
    Posty: 444
    Pomógł: 35
    Ocena: 18
    No OK, ale wartości te i tak są statyczne, a ustalane jedynie podczas syntezy - w trakcie działanie na matrycy nie ulegają zmianie, stąd w zasadzie nie są one dynamiczne. Nie wiem jak syntezer reaguje na dwuwymiarowe tablice (nigdy nie były mi potrzebne), jeśli chcę wygodnie się odwoływać to do zwykłej pamięci jedonowymiarowej to dzielę jej adres na kilka części np:

    mam blok 1024 słowa po 16 bit, czyli 10 bitów na adres, jak chce tablicę dwu wymiarową 64x16 (wiersz x kolumna) to pierwsze 6 bitów w adresie to wiersz a następne 4 bity to kolumna.

    Wydaje mi się jednak, że jak rozpaćkasz tą pamięć, na słowa o dowolnej długości to i tak dostaniesz ff, z tej racji że na matrycach pamięć (tzw. distribiuted RAM w Xilinxie) jest uzyskiwana z bloków logicznych, które mogą służyć jako RAM 16x1, ale to tylko taki mój domysł.
  • #19 4386216
    J.A
    Poziom 28  
    Posty: 596
    Pomógł: 159
    Ocena: 12
    opisz jakos tak te zalozenia, by i mniej rozgarniety inzynier mogl to pojac;

    zlootawy napisał:
    Chodzi o to,/.../, tzn. zarowno rozmiar jak i ilosc "komorek" ustala uzytkownik

    zupelnie nie rozumiem, czemu uzytkownik fpga ma ustalac, jak sa trzymane dane w kostce;
    zlootawy napisał:
    Uklad ma za zadanie upakowac jak najwiecej czternastek w np. trzydziestki i te trzydziestki
    wystawic na zewnatrz.

    czemu w trzydziestki, a nie w 28-ki ?
    ok, jesli dobrze rozumiem, to masz takie wymagania:
    pan uzytkownik moze ustalic 3 parametry, sk-'szerokosc komorki', gk-jej glebokosc i dw-dlugosc
    slowa wyjsciowego;
    zakladam, ze te parametry nie moga byc dowolne, np. musi byc dw >= sk
    i ze jesli dw nie jest podzielne przez sk, to reszta z dzielenia dw/sk nie jest
    wypelniana kolejnymi bitami nastepnej komorki;
    mowiac po ludzku, jesli masz dw = 30, a sk =14, to w slowo wyjsciowe
    wpisujesz 2x14 bitow z 2 komorek a 2 pozostale z 30 pozycji sa nieistotne;***

    po bozemu to ja bym zrobil tak:
    w osobnym pliku piszesz sobie kod pamieci sram z parametrami sk i gk,
    kompilujesz go jako osobny projekt i upewniasz sie, ze ise faktycznie
    zrozumialo, ze to ma byc pamiec;
    obliczasz sobie zmienna
    BYLO: n = dw(mod)sk,
    POWINNO BYC: n = dw / sk;
    [jakies zacmienie umyslowe, na ktore zwrocil mi uwage zlootawy]

    czyli ile komorek ci potrzeba
    i tylez razy implementujesz sram w kodzie glownym;
    wejscia i wyjscia pamieci laczysz mniej wiecej wg. takiego schematu:

    for ( i=0 to i=n-1)
    sram[i] <= dane_we[ (i*sk + sk-1) : i *sk]
    dane_wy <= [ (i*sk + sk-1) : i*sk ]

    /moglem sie pomylic w liniach powyzej, ale jakos tak/
    nie mam pojecia, jak to zapisac w vhdl, ale skoro w verilogu sie da,
    to i w tym barbarzynskim jezyku powinno sie udac;
    "sram[i]" oznaczas "i-ta" instancje pamieci, nie indeks wejscia badz wyjscia;

    *** jesli to zalozenie jest nieprawdziwe, to problem tez jest do rozwiazania,
    ale musialbym sie gleboko zastanowic jak :)

    pndemon napisał:
    Wydaje mi się jednak, że jak rozpaćkasz tą pamięć na słowa o dowolnej długości,
    to i tak dostaniesz ff, z tej racji że na matrycach pamięć (tzw. distribiuted RAM w Xilinxie) jest
    uzyskiwana z bloków logicznych, które mogą służyć jako RAM 16x1, ale to tylko taki mój domysł.


    nie do konca tak, to jest swietny wynalazek xilinxa, ze look-up table w kazdej komorce, zwykle sluzaca
    jako generator funkcji logicznej, a w istocie bedacej przeciez pamiecia wlasnie, mozna skonfigurowac
    jako normalna pamiec 16x1 i z takich elementow zbudowac sram dowolnych nietypowych rozmiarow;
    pewnie parametry takiej pamieci sa gorsze od regularnych blokow ram, ale to ciagle jest
    pamiec a nie 'flip-flop see' jak u altery;

    J.A
  • #20 4386595
    sepher
    Poziom 19  
    Posty: 301
    Pomógł: 21
    Ocena: 4
    Ok, przyznaję się bez bicia, że kodu nie testowałem. Chciałem tylko napisać, że ISE automatycznie małe pamięci tworzy raczej z distributed RAM niż BlockRAM (kiedyś się o tym przekonałem tworząc cyfrową linię opóźniającą - potrzebowałem tego do filtrowania obrazu a miała tylko 64 bajty pojemności). Jeśli chcesz wymusić syntezę pamięci konretnego, interesjącego Ciebie typu, to wprowadzasz w kodzie atrybut:

    attribute ram_style: string;


    A później możesz napisać:

    attribute ram_style of {signal_name|entity_name}: {signal|entity} is “{auto|block|distributed}”; 


    Block RAM rzeczywiście jest sporo szybszy (co nie jest specjalnie dziwne, po to jest w strukturze dodawany), widać to szczególnie przy większych pojemnościach pamięci.
  • #21 4396790
    zlootawy
    Poziom 10  
    Posty: 54
    a jak najlepiej sprawic aby licznik po dojsciu do zera zatrzymal sie? tzn. lepiej jest umiescic w kodzie licznika klauzule:

    IF wynik > 0 THEN
    wynik <= wynik - 1;
    else
    wynik <= wynik;
    end IF;

    czy moze zabawic sie i wprowadzic CE?

    tylko ze CE bym ustawial na 0, wtedy gdy wynik doszedlby do 0:
    ce <= '0' when wynik = 0 else '1';

    mozna takie sprzezenie zwrotne dawac?

    Pozdrawiam
    Wojtek
  • Pomocny post
    #22 4397005
    pndemon
    Poziom 19  
    Posty: 444
    Pomógł: 35
    Ocena: 18
    zdecydowanie pomysł z warunkiem '>' nie jest dobry, coś na pewno uruchamia w twoim kodzie ten licznik, prawdopodobnie jest to maszyna stanu, stąd najlepszym wyjściem jest sygnał ce ustawiany przez ten sterownik

    Cytat:
    mozna takie sprzezenie zwrotne dawac?


    no jak jest to układ synchroniczny to wszystko jest ok, bo jeżeli osiągnięte jest '0' przez licznik, to ew. kolejna zmiana wartości licznika zdarzy się na następne narastające zbocze sygnału zegarowego, twój warunek musi "się spełnić' w ciągu jednego cyklu i wszystko będzie ok, inaczej mówiąc jeżeli czas propagacji sygnału poprzez logikę odpowiadającą za
    ce <= '0' when wynik = 0 else '1'; 
    jest mniejszy niż długość cyklu zegarowego, to cel zostanie osiągnięty
  • #23 4399075
    zlootawy
    Poziom 10  
    Posty: 54
    Cytat:


    no jak jest to układ synchroniczny to wszystko jest ok, bo jeżeli osiągnięte jest '0' przez licznik, to ew. kolejna zmiana wartości licznika zdarzy się na następne narastające zbocze sygnału zegarowego, twój warunek musi "się spełnić' w ciągu jednego cyklu i wszystko będzie ok, inaczej mówiąc jeżeli czas propagacji sygnału poprzez logikę odpowiadającą za
    ce <= '0' when wynik = 0 else '1'; 
    jest mniejszy niż długość cyklu zegarowego, to cel zostanie osiągnięty



    ale jak potem ce ustawic ponownie na '1'? licznik dochodzi do 0 zostaje od tylu wylaczony.

    kod licznika to:

    
     process(CLK)
       begin
          if falling_edge(CLK) then
    			if ENABLE = '1' THEN
    				if SET = '1' then
    					SIG_COUNTER <= conv_std_logic_vector(WRITE_STEPS-1, 9);
    				else
            			SIG_COUNTER <= SIG_COUNTER - 1;
    				END IF;	 
    			end if;
          end if;
       end process;
          Q <= SIG_COUNTER; 



    w stanie IDLE ustawiam set na '1' dzieki czemu do licnzia laduje sie wartosc startowa. potem chodze po stanach a licznik maleje. dochodzi do 0 licznik sie wylacza instrukcja wspolbiezna. nie moge go wiec pozniej ponownie wlaczyc w automacie...
  • Pomocny post
    #24 4399204
    pndemon
    Poziom 19  
    Posty: 444
    Pomógł: 35
    Ocena: 18
    przypuszczam że ten licznik jest ci potrzebny do odliczania ilości cykli automatu stanu, więc może to automat powinien sterować sygnałem 'enable', tak czy siak nie wiem za bardzo jaka jest relacja między automatem a licznikiem, więc na chwilę obecną jedyne co mogę poradzić to drugi sygnał 'en' pochodzący z automatu a kod zmienić wtedy tak:
    
    process(CLK)
       begin
          if falling_edge(CLK) then
             if ((ENABLE = '1') or (en = '1')) THEN
                if SET = '1' then
                   SIG_COUNTER <= conv_std_logic_vector(WRITE_STEPS-1, 9);
                else
                     SIG_COUNTER <= SIG_COUNTER - 1;
                END IF;   
             end if;
          end if;
       end process;
          Q <= SIG_COUNTER;
    


    czy jakoś tak.
  • #25 4399258
    zlootawy
    Poziom 10  
    Posty: 54
    pndemon napisał:
    przypuszczam że ten licznik jest ci potrzebny do odliczania ilości cykli automatu stanu, więc może to automat powinien sterować sygnałem 'enable', tak czy siak nie wiem za bardzo jaka jest relacja między automatem a licznikiem, więc na chwilę obecną jedyne co mogę poradzić to drugi sygnał 'en' pochodzący z automatu a kod zmienić wtedy tak:
    
    process(CLK)
       begin
          if falling_edge(CLK) then
             if ((ENABLE = '1') or (en = '1')) THEN
                if SET = '1' then
                   SIG_COUNTER <= conv_std_logic_vector(WRITE_STEPS-1, 9);
                else
                     SIG_COUNTER <= SIG_COUNTER - 1;
                END IF;   
             end if;
          end if;
       end process;
          Q <= SIG_COUNTER;
    


    czy jakoś tak.



    aha... no dzieki..

    enable nie moze byc sterowane z automatu, poniewaz musze wykryc, ze automat zmienil stan np. 27 razy... czyli kilka razy obrocil po wszystkich stanach... jesli w ktorymkolwiek stanie bym go wylazyl to licznik przestalby odliczac.

    chyba zeby dac w kazdym stanie sprawdzenie, czy to juz 27, i jesli tak to enable '0', a jesli nie to '1';

    no sam nie wiem co bardziej rozsadne...
  • #26 4399289
    pndemon
    Poziom 19  
    Posty: 444
    Pomógł: 35
    Ocena: 18
    Cytat:
    chyba zeby dac w kazdym stanie sprawdzenie, czy to juz 27, i jesli tak to enable '0', a jesli nie to '1';


    No to nie brzmi dobrze żeby w każdym stanie sprawdzać czy licznik ma już '0', ale z tego co piszesz to wynika, że jakaś operacja (której czas odmierza licznik) może się zakończyć w dowolnym stanie automatu i wtedy automat wraca do jakiegoś stanu wyjściowego. A może jest tak, że te liczby nie są całkowicie dowolne i że '0' występuje tylko przy jakiś konkretnym stanie np. masz stany write1, write2 i write3 które działają po sobie, a licznik np. może przyjmować liczby 3*i, to wtedy '0' wystąpi tylko w jednym z nich.
  • #27 4402696
    J.A
    Poziom 28  
    Posty: 596
    Pomógł: 159
    Ocena: 12
    zlootawy napisał:
    a jak najlepiej sprawic aby licznik po dojsciu do zera
    zatrzymal sie?

    a musi sie zatrzymac ?
    ja tez nie za bardzo rozumiem, co chcesz zrobic,
    ale moze wystarczy w odpowiednim miejscu zaladowac
    wartosc do odliczenia a potem wykryc, ze odliczanie skonczone;
    a licznik niech sobie liczy ...
    chyba, ze musisz oszczedzac na pradzie :)

    J.A
  • #28 4417025
    zlootawy
    Poziom 10  
    Posty: 54
    Cytat:

    po bozemu to ja bym zrobil tak:
    w osobnym pliku piszesz sobie kod pamieci sram z parametrami sk i gk,
    kompilujesz go jako osobny projekt i upewniasz sie, ze ise faktycznie
    zrozumialo, ze to ma byc pamiec;
    obliczasz sobie zmienna
    BYLO: n = dw(mod)sk,
    POWINNO BYC: n = dw / sk;
    [jakies zacmienie umyslowe, na ktore zwrocil mi uwage zlootawy]

    czyli ile komorek ci potrzeba
    i tylez razy implementujesz sram w kodzie glownym;
    wejscia i wyjscia pamieci laczysz mniej wiecej wg. takiego schematu:

    for ( i=0 to i=n-1)
    sram[i] <= dane_we[ (i*sk + sk-1) : i *sk]
    dane_wy <= [ (i*sk + sk-1) : i*sk ]

    J.A


    Projekt polega na tym, ze mam 10 przetwonikow 14-bitowych, z ktorych
    musze odczytac wartosci i zapisac to do SRAM (takiego prawdziwego,
    fizycznie umieszczonego na plycie). Potem oczywiscie musze moc to
    odczytac.

    Przetworniki sa widoczne od strony FPGA jako tablica 10 elemetowa,
    gdzie kazdy element to 14 bitow. Mowie tak, gdyz zobaczylem w
    constraints wpisy na zasadzie P_ADC(0)
    P_ADC(1)
    itd

    Czyli w glownym entity mam P_I_ADC : In TADCArray(ADC_NUMBER-1 downto 0);


    No i teraz odczytuje wszystkie 10 przetwornikow i kieruje do zapisu do
    SRAM. SRAM ma slowo 36 bitowe. Wiec w jednym slowie zmieszcza sie dwa
    przetorniki czternastobiotwe, reszta uzupelniona zerami, to juz
    zreszta przerabialismy.

    Zapis do SRAM odbywa sie raz na takt zegara jedno slowo 36-bitowe.

    Wiec fajnie by bylo to co sie odczytalo z wszystkich 10 urzadzen
    przechowac po drodze w pamieci (tej w fpga) i co takt zegara wystawiac
    z tej przechowali na odpowiedni port wyjsciowy kolejno po jednym
    slowie 36bitowym.

    A wszystkie liczby o ktorych do tej pory mowilem maja byc zmiennymi.

    pokombinuje jakby to ladnie zrobic, ale jesli mialby ktos pomysl jak te PRZECHOWALNIE zapisac, tak aby syntezator stworzyl pamiec, a nie FF, bede wdzieczny.
  • Pomocny post
    #29 4417271
    J.A
    Poziom 28  
    Posty: 596
    Pomógł: 159
    Ocena: 12
    zlootawy napisał:
    Projekt polega na tym, ze mam 10 przetwonikow 14-bitowych
    /.../

    na pierwszy rzut oka wydaje sie, ze nie ram w fpga a fifo
    pracujace z podniesionym kilkukrotnie na pll zegarem;

    J.A
  • #30 4417331
    zlootawy
    Poziom 10  
    Posty: 54
    J.A napisał:
    zlootawy napisał:
    Projekt polega na tym, ze mam 10 przetwonikow 14-bitowych
    /.../

    na pierwszy rzut oka wydaje sie, ze nie ram w fpga a fifo
    pracujace z podniesionym kilkukrotnie na pll zegarem;

    J.A



    >ramu ?

    Czyli z portu wejsciowego bedacego tablica, zegarem kilka razy szybszym zapisac dane do fifo. i uzyc do tego licznika, leciec po indeksie portu wejsciowego i co takt zwiekszac licznik o jeden i wstawiac do fifo zgodnie z taktem szybszego zegara.

    szybszy zegar uzyskac z dcm... moga sobie tak dwa zegary funkcjonowac obok siebie?

    fifo powinno miec juz szerokosc taka jaka ma SRAM zewnetrzny. Czyli w momencie wstawiania do fifo nalezy zrobic odpowiednie posklejania danych wejsciowych.


    Mniej wiecej to widze... tylko ten drugi zegar mnie niepokoi. trzbea by sie dobrze zastanowic o ile on musi byc szybszy... a sprawe komplikuje to ze czestotliwosc pracy ukladu tez jest parametryzowana. i w penym momencie uklad moze przestac pracowac bo zegar dla fifo okazal sie szybszy niz jest to mozliwe i fifo sie nie wyrobilo.

Podsumowanie tematu

✨ Dyskusja dotyczy problemów z implementacją licznika w automacie stanów na układzie FPGA (model vp30-5ff1152) w projekcie realizującym kontroler do pamięci SRAM. Autor chce, aby ostatni stan automatu trwał określoną liczbę taktów zegara, zliczaną za pomocą zmiennej lub sygnału. Zastosowanie zmiennej licznikowej i złożonych warunków logicznych (np. modulo) znacząco obniża maksymalną częstotliwość pracy (Max freq spada z 133 MHz do 30 MHz) i wydłuża czas optymalizacji syntezy. Wskazano, że lepszym rozwiązaniem jest licznik zliczający w dół, ładowany wartością liczby kroków do odmierzenia, co upraszcza dekodowanie i poprawia wydajność. Zalecane jest stosowanie sygnałów sterujących (reset, enable, load) do rejestrów i liczników, a także rozdzielenie automatu stanów na procesy kombinacyjne i sekwencyjne. Poruszono temat optymalizacji pamięci w FPGA, gdzie małe pamięci tworzone są z distributed RAM, a większe z Block RAM, które są szybsze. Wskazano możliwość wymuszenia stylu pamięci za pomocą atrybutu ram_style. Autor rozważał implementację licznika z zatrzymaniem po osiągnięciu zera, dyskutowano o sterowaniu sygnałem CE (clock enable) przez automat stanów. Poruszono też problem parametryzacji tablic wejściowych (np. 10 elementów po 14 bitów) i konieczności upakowania danych do słowa 36-bitowego SRAM. Zaproponowano użycie FIFO z zegarem o wyższej częstotliwości generowanym przez PLL/DCM do buforowania danych przed zapisem do SRAM. Wskazano, że synchronizacja i odpowiednie sterowanie licznikami oraz sygnałami sterującymi jest kluczowa dla zachowania wysokiej częstotliwości pracy i poprawnej funkcjonalności. Komunikat "Found area constraint ratio" odnosi się do wykorzystania powierzchni układu i może wskazywać na nadmierne rozbudowanie logiki. Podkreślono, że stosowanie constraintów czasowych (np. PERIOD) pomaga zidentyfikować krytyczne ścieżki sygnałowe i poprawić wydajność syntezy.
Wygenerowane przez model językowy.
REKLAMA