VHDL - konwersja bin2bcd

W ramach poznawania podstaw VHDL-a na CPLD pracuję obecnie nad pewnym projektem. O ile bez większego problemu udało mi się napisać większość potrzebnych komponentów (dzielnik częstotliwości, licznik binarny, sterownik wyświetlacza siedmiosegmentowego). Niestety - wygląda na to, że utknąłem na zagadnieniu konwersji liczby zakodowanej binarnie na kod BCD. Na wejściu komponentu mam siedmiobitowy STD_LOGIC_VECTOR, przez ktory przekazuję wartość mieszczącą się między 0 i 99. Na wyjściu znajduje się ośmiobitowy STD_LOGIC_VECTOR. Jego starszy półbajt ma mieścić liczbę dziesiątek, młodszy liczbę jedności.

Wydawało mi się, że mogę to zrobić prosto, tak samo jak na mikrokontrolerach - dziesiątki uzyskując za pomocą dzielenia przez 10, a jednostki za sprawą operacji modulo 10.

Napisałem więc coś następującego:

bcdval(7 DOWNTO 4) <= binval/10; bcdval(7 DOWNTO 0) <= binval MOD 10;

Niestety, synteza kodu wywala się właśnie w tym miejscu, zwracając błąd: "Operator <DIVIDE> must have constnt operands or first operand must be power of 2".

Wygląda więc na to, że nie mogę w prosty sposób wykonać dzielenia dowolnej liczby przez inną dowolną liczbę.

Jak w takim razie powinien być zrealizowany taki konwerter?

Reply to
Atlantis
Loading thread data ...

O VHDL nie ma pojecia wiec sie wypowiem :)

No, wszytkie mikrokontolery ktore mam dzielenie robia programowo. W wiekszych mmozenie jest sprzetowe, w mniejszych nawet mnozenie jest programowe.

Zgaduje ze VHDL z tego kodu chce zrobic siec logiczna ktora w "jednym kroku" produkuje wynik. Wszystkie procesory ktore znam majace sprzetowe dzielenie maja dzielenie wielotaktowe. Ogolnie jednotaktowa siec dzielaca jest skomplikowan i duza. Ty masz bardzo maly rozmiar danych, wiec jak sie upierasz to pewnie mozesz to zrobic "na sile": dla kazdego bitu wyniku napisac formule boolowska dajaca wartosc tego bitu, tzn cos w stylu

out0 <= in0 /* Latwe */ out1 <= ( /* in = 2 lub in = 3 lub in = 6 lub in = 7 */ in1 and not in3 ... and not in7 /* in = 12 lub in = 13 */ or not in1 and in2 and in3 and not in4 ... ....

Przetlumaczone naiwnie da pewnie kilka tysiecy bramek. Optymalizator moze to troche uproscic, ale nie liczylbym na dramatyczne uproszczenia.

Rozsadniej zrobic wielotaktowa konwersje, tzn operacje "krok dzielenia". Dokladniej, na wejsciu kroku dzielenia masz dwie liczby 7-bitowe. Wyjscie to 1 bit wyniku dzielenia i liczba 7-bitowa (reszta z dzielenia). Ten bit wyniku to po prostu resultat porownania. Reszta to albo dzielna (jesli bit wyniku to 0) albo dzielna minus dzielnik (jesli bit wyniku to 1). Po kroku dzielnia oba argumenty dzielisz przez 2 (przesuwasz) i jesli trzeba robisz nastepny krok. W twoim przypadku krok dzielenia trzeba powtorzyc 4 razy. Teoretycznie mozesz po prostu uzyc kaskade 4 krokow, ale wtedy powielisz 4 razy glowna czesc.

W twojej konwersji masz maly zakres i pewnie szybkosc jest malo istotna. W takim przypadku mozesz uzyc 3 liczniki. Jeden zliczajacy az do argumetu. Drugi liczacy do 10 (daje reszte). Trzeci zliczajacy przeniesienia drugiego (daje wynik).

Jesli w projekcie masz pamiec to chyba najrozsadniejsze jest przechowywanie tabeli konwersji w pamieci.

Jeszcze jedno: bit 0 wyniku jest taki sam jak bit 0 wejscia, wiec problem redukuje sie do dzielnia liczby szesciobitowej przez 5. To pozwala na troche oszczednosci, ale nie zmienia zasady.

Reply to
antispam

piątek, 4 grudnia 2020 o 22:00:03 UTC+1 Atlantis napisał(a):

Nie ma się co dziwić że wywala błąd. Przy VHDL'u musisz myśleć "sprzętowo" a nie "programowo". Można co prawda zdefiniować moduł dzielenia, ale jest przy tym trochę zabawy. Tymczasem w sieci jest od cholery gotowych źródeł. Wpisz w szukarce : vhdl binary to bcd. Można jeszcze inaczej. Ja bym zamiast CPLD zastosował FPGA. Cena najmniej zasobnych FPGA jest w zasadzie taka sama jak CPLD, a możliwości i zasoby o wiele większe. Wystarczy że zdefiniujesz sobie w FPGA 256-bajtowy ROM lub RAM, wpiszesz tabelkę konwersji i po ptokach.

Reply to
Stachu Chebel

Ok, wielkie dzięki. Udało mi się znaleźć działający kod modułu do konwersji BIN-BCD.

Postawiłem na CPLD z dwóch powodów:

  1. FPGA przeważnie wymagają zewnętrznej pamięci do przechowywania konfiguracji. CPLD mają wbudowany flash i można je zaprogramować tak samo, jak zwykły mikrokontroler.
  2. Zwykle staram się dopasować użyty układ do planowanego stopnia złożoności projektu. Czyli np. nie będę używał STM32F4 tam, gdzie potrzeba po parę kB flasha i RAM-u.

Ale tak z ciekawości: jak złożone projekty można wepchnąć do tych najprostszych FPGA, w porównaniu do CPLD takiego jak CoolRunner II? Czy można już myśleć o dodaniu jakiegoś prostego mikroprocesora, który współpracowałby z pozostałymi peryferiami zaprogramowanymi w układzie?

Reply to
Atlantis

snipped-for-privacy@math.uni.wroc.pl snipped-for-privacy@math.uni.wroc.pl> napisał(a):

Napraw w końcu te polskie litery.

Reply to
Grzegorz Niemirowski

W dniu 04.12.2020 o 21:59, Atlantis pisze:

VHDL (i Verilog) to nie języki programowania tylko języki opisu sprzętu. Musisz przestawić swój tok myslenia, co nie jest łatwe. Głównie "rzeźbię" w Verilogu, którego składnia bardzo przypomina język programowania C. Potrzebowałem trochę czasu aby przekonać zwoje mózgowe, że to co widzę na ekranie, to nie kolejno wykonywane linie programu tylko zbieranina połączonych ze sobą bramek i przerzutników.

Wracając do Twojego problemu, to VHDL nie będzie próbował wykonać dzielenia, tylko będzie próbował zsyntezować na zasobach CPLD układ kombinacyjny realizujący zadaną funkcję dzielenia. Dzielenie liczby przez stałą nie będącą wielokrotnością potęgi 2 będzie wymagać na tyle dużo zasobów, że przekracza to możliwości typowego CPLD.

Mnożenie i dzielenie przez stałą będącą wielokrotnością potęgi dwójki nie wymaga praktycznie żadnych zasobów sprzętowych. To tylko kabelki :-)

Ale możesz wykorzystać rozdzielność dzielenia względem odejmowania. Poszukaj algorytmów dzielenia na procesory typu Z80, 6502 itp.

Reply to
Grzegorz Kurczyk

sobota, 5 grudnia 2020 o 20:47:15 UTC+1 Atlantis napisał(a):

Ośmiopinowy flash za jakieś 5 zeta to chyba nie problem. A programujesz JTAG'iem podobnie jak cokolwiek innego.

Niby racja, ale skoro możesz dostać więcej za tę samą cenę, to ja obstawiam na FPGA.

Nawet nie ma co porównywać. Przepuść sobie implementację tego co masz zrobione na CPLD z ustawieniem na najprostszego Spartana-3 i popatrz na raport wykorzystania zasobów. Nie ma najmniejszego problemu jeśli chodzi o zaimplementowanie procesora w FPGA. Oczywiście wszystko zależy od stopnia złożoności projektu i wybranego modelu FPGA. Są dostępne w sieci darmowe IP na 8080,Z80,8051 itp. Ponadto na pokładzie FPGA masz też konfigurowalną pamięć BRAM. Dużo się da...

Reply to
Stachu Chebel

W dniu 04.12.2020 o 21:59, Atlantis pisze:

P.S. A może zamiast licznika binarnego zakoduj licznik BCD. Coś na wzór UCY7490 :-)

Reply to
Grzegorz Kurczyk

W dniu 07.12.2020 o 10:04, Grzegorz Kurczyk pisze:

lub raczej na wzór synchronicznego licznika UCY74192. Na wyjściu będziesz miał gotowe dane do sterowania dekodera wyświetlacza

7-segmentowego.
Reply to
Grzegorz Kurczyk

W dniu 04/12/2020 o 21:59, Atlantis pisze:

formatting link
Pozdrawiam

Adam Górski

Reply to
Adam Górski

Jest szansa, że taki design zsyntetyzuje się w wydajny sposób? Potrzebuję kilku liczników, które będą liczyły do określonej wartości, a po jej przekroczeniu zresetują się i wygenerują sygnał przepełnienia.

Na razie używam do tego liczników binarnych, których rozmiar ustalam za pomocą parametru generic dla konkretnej instancji. Licznik resetuje się po osiągnięciu konkretnej wartości. Wartość z wyjścia licznika przepuszczam przez konwerter bin2bcd i wyświetlam na wyświetlaczu 7 seg.

Wzorując się na UCY7490 musiałbym dodać logikę, która obserwowałaby wyjścia i resetowała licznik po zaobserwowaniu konkretnej wartości BCD, składającej się na dwucyfrową liczbę dziesiętną.

Reply to
Atlantis

Użytkownik "Grzegorz Kurczyk" napisał w wiadomości grup dyskusyjnych:5fcc1ae7$0$559$ snipped-for-privacy@news.neostrada.pl... W dniu 04.12.2020 o 21:59, Atlantis pisze:

Ale to nie oznacza, ze nie powinien umiec dzielenia zaprojektowac.

No, ciekawe ... najprosciej byloby tabelke wpisac. Wygenerowac gdzies obok i tylko wpisac w zrodlo :)

6 bitow wejsciowych, bo najmlodszy idzie bez zmian ... no tak, to moze byc w architekturze CPLD zabojcze.

J.

Reply to
J.F.

Jak najbardziej - schemat 7490 nie jest najlepszy, ale 74192 nie jest skomplikowany.

Ale jakies nieokragle liczby, typu np 43 czy 56 ? Czy mozesz to podzielic na licznik do 10 i np do 6 na starszej cyfrze ?

Takie liczenie w BCD do 43 ... no, ciekawe, schemat/wyrazenia sie komplikuja, przy pomocy pomocniczej bramki powinno pojsc w miare latwo ... tylko czy VHDL w CPLD sobie z tym poradzi ..

J.

Reply to
J.F.

Użytkownik "Adam Górski" napisał w wiadomości grup dyskusyjnych:5fce1f78$0$510$ snipped-for-privacy@news.neostrada.pl... W dniu 04/12/2020 o 21:59, Atlantis pisze:

Jesli dobrze rozumiem ... sam chcialem te metode zapronowac, ale ona jest "sekwencyjna".

Wynik sie pojawi po kilku/nastu cyklach zegara, i trzeba ten zegar miec.

Dla 2 cyfr dziesietnych ... moze da sie prosciej ukladem kombinacyjnym.

J.

Reply to
J.F.

To ma być klasyczny zegar, który później chciałbym wzbogacić o funkcję synchronizacji z DCF77. Typowy projekt edukacyjny. ;) Dlatego też nie byłoby większego problemu ze zliczaniem sekund i minut - młodsza część zawsze liczy od 0 do 9, od 0 do 5. Bardziej problematyczny jest licznik. Zależy mi trynie 24 godzinnym, więc mamy do czynienia z kilkoma możliwościami:

- Jeśli starsza cyfra wynosi 0 ub 1, młodsza liczy od 0 do 9.

- Jeśli starsza cyfra wynosi 2, młodsza liczy od 0 do 3.

Prościej mi było to zaimplementować w postaci licznika binarnego i tłumaczyć na BCD.

BTW czy gdzieś w VHDL-u istnieje możliwość uzyskania czegoś na wzór kompilacji warunkowej z języków programowania? Mam na myśli coś takiego, że przekazuje przez generic określoną wartość i w zależności od niej tworzę (lub nie) pewne sygnały wewnątrz portu albo architektury. Pozwoliłoby mi to zawsze oszczędzić trochę zasobów, bo w chwili obecnej niektóre instancje posiadają wyprowadzone sygnały, które są zdefiniowane w komponencie, ale których te konkretne instancje nie potrzebują.

Reply to
Atlantis

Może w takim razie Xilinx produkował jakieś prostsze FPGA, które byłyby względnie kompatybilne pinowo ze swoimi starszymi układami CPLD? Konkretnie mam na myśli rodzinę CoolRunner w 100 pinowej wersji obudowy. Zdaję sobie sprawę z tego, że nie wszystko może pasować (bo chociażby pamięć trzeba podpiąć) ale gdyby piny zasilania, masy, Clk, Rst i JTAG były w tych samych miejscach, to znacznie prościej byłoby przeprojektować płytkę. :)

Reply to
Atlantis

Wręcz przeciwnie. Prościej zrobić asynchroniczne liczniki od 0 do 9 i od

0 do 5 łącząc je w kaskadę. Licznik asynchroniczny 0..9 liczący w górę to cztery przerzutniki i jedna bramka AND Jaki to konkretnie CPLD? Xilinx?

Coś mi się kojarzy, że w niektórych CPLD sygnały zegarowe wszystkich przerzutników są na stałe połaczone ze sobą co wyklucza licznik asynchroniczny. Z drugiej strony synchroniczny nie jest dużo bardziej skomplikowany

syntezer powinien automatycznie zredukować nieistniejące połaczenia redukując potrzebne zasoby

Reply to
Grzegorz Kurczyk

CoolRunner II, konkretnie XC2C128. Docelowo miał być XC2C256, ale pod ręką miałem tylko 128 w 100 pinowej wersji obudowy. W tej chwili nigdzie w polskich sklepach nie widzę wersji 256, a miejsce w układzie powoli się kończy. ;)

Reply to
Atlantis

Jak oglądam budowę makroceli, to powinieneś bez problemu zbudować zarówno licznik synchroniczny jak i asynchroniczny. A co ciekawsze prawdopodobnie zajmie to tyle samo zasobów. Jeden bit licznika, to jedna makrocela.

w Verilogu taki licznik synchroniczny to

reg [3..0] licznik; always @(posedge clk) if(reset | (licznik = 9)) then licznik <= 0; else licznik <= licznik + 1;

W przypadku zegara calkowicie nie widzę sensu robić licznika binarnego i konwertować do BCD. Łatwiej wszystko robić w BCD.

Reply to
Grzegorz Kurczyk

poniedziałek, 7 grudnia 2020 o 19:02:03 UTC+1 Atlantis napisał(a):

FPGA i CPLD to dwie różne filozofie. Na żadną kompatybilność pinową nie ma co liczyć. Tylko przeprojektowanie PCB wchodzi w rachubę. A co do podpinania pamięci, to zależy ile jej potrzebujesz. Wszystkie obecnie produkowane FPGA mają na pokładzie pamięć BRAM, którą możesz konfigurować w dowolne bloki. Popatrz sobie w dataszity i oceń sam co się lepiej opłaca. Pamięć zewnętrzna lub wewnętrzna w FPGA. Wybór należy do Ciebie.

Reply to
Stachu Chebel

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.