Blog
Nieco spóźniony wpis z projektem
17.12.2006 - Niedziela - 14:52
Jakiś czas temu miałem termin oddania projektu układu opisanego w VHDL-u. Ponieważ do dyspozycji miałem tylko CPLD Xilinx XC95108, który bardzo pojemnym układem nie jest, program nie mógł być zbyt skomplikowany. Napisałem więc symulator taśmociągu z dwiema programowalnymi bramkami.
Większość opisu napisałem u siebie w domu, skompilowałem i przetestowałem oglądając przebiegi czasowe. Ale już na miejscu, w pracowni, okazało się, że trochę "przedobrzyłem". Nie wziąłem pod uwagę faktu, że układ nie poradzi sobie z tak skomplikowanym programem... Musiałem się wziąć za "odchudzanie"... W moich pierwotnych założeniach układ był zupełnie niezależny od zegara znajdującego się na płytce. Odpowiednie działania miały się wykonywać w momencie pojawienia się narastających zboczy sygnałów symulujących i programujących (to jest wciśnięć przypisku symulującego paczkę i przycisków programowania bramek). Niestety, w XC95108 można wykorzystać tylko trzy sygnały, które będą sprawdzane pod kątem wystąpienia zbocza (takie sprawdzanie jest możliwe tylko w przerzutniku synchronicznym na jego wejściu zegarowym). Ja potrzebowałem niestety co najmniej czterech takich sygnałów. Musiałem więc sobie darować tę możliwość i wykorzystać uzależnienie od zegara wewnętrznego, co jest nieco gorszym rozwiązaniem. Kolejnym problemem była ilość porównać dokonywanych w układzie. Komparatory wielobitowe szybko i skutecznie zżerają zasoby układu, przez co momentalnie straciłem możliwość "wgrania" opisu do tego układu. Musiałem podjąć kolejne kroki optymalizacyjne: łączenie czterobitowych wektorów w ośmiobitowe (dzięki temu nieco lepiej mogłem rozdysponować zasoby w poszczególnych makrokomórkach), minimalizacja ilości zmiennych wewnętrznych (zwalniałem przerzutniki), usunięcie sygnałów typu buffer (kolejne wolne przerzutniki) itd. Po odchudzeniu układ dawał się zaprogramować, ale stracił kilka fajnych bajerów, które miałem ochotę do niego wrzucić. Ważne, że wyrobiłem się w czasie (jako jeden z nielicznych) i nie muszę teraz stosować dalszego odchudzania ;-)
Oczywiście zamieszczam pełny kod opisu układu. Oczywiście w VHDL ;-)
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity sterownik is
port(
WE, R, P0, P1, AKC: in std_logic;
CLK: in std_logic;
LED1, LED2: out std_logic_vector(7 downto 0));
end sterownik;
architecture urzadzenie of sterownik is
function hex2led (hex: std_logic_vector(3 downto 0)) return std_logic_vector is
variable s: std_logic_vector(7 downto 1);
begin
case hex is
when "0000" => s:= "1000000";
when "0001" => s:= "1111100";
when "0010" => s:= "0001001";
when "0011" => s:= "0011000";
when "0100" => s:= "0110100";
when "0101" => s:= "0010010";
when "0110" => s:= "0000010";
when "0111" => s:= "1111000";
when "1000" => s:= "0000000";
when "1001" => s:= "0010000";
when "1010" => s:= "0100000";
when "1011" => s:= "0000110";
when "1100" => s:= "1000011";
when "1101" => s:= "0001100";
when "1110" => s:= "0000011";
when "1111" => s:= "0100011";
when others => s:= "1010101";
end case;
return s;
end hex2led;
begin
process(CLK, WE, AKC, P0, P1, R)
variable B: std_logic_vector(7 downto 0) := "00000000";
variable BS: std_logic_vector(7 downto 0);
variable start: std_logic := '0';
begin
if R = '1' then
B := "00000000";
BS := "00000000";
LED1(0) <= '1';
LED2(0) <= '1';
start := '0';
elsif CLK'event and CLK = '1' then
if P0 = '1' then BS(7 downto 4) := BS(7 downto 4) + 1;
elsif P1 = '1' then BS(3 downto 0) := BS(3 downto 0) + 1;
elsif AKC = '1' then start := '1';
elsif WE = '1' then
if B(7 downto 4) < BS(7 downto 4) then
B(7 downto 4) := B(7 downto 4)+1;
if B(7 downto 4) = BS(7 downto 4) then
LED1(0) <= '0';
end if;
elsif B(3 downto 0) < BS(3 downto 0) then
B(3 downto 0) := B(3 downto 0)+1;
if B(3 downto 0) = BS(3 downto 0) then
LED2(0) <= '0';
end if;
elsif B = BS then
B := "00010000";
LED1(0) <= '1';
LED2(0) <= '1';
end if;
end if;
end if;
if start = '1' then
LED1(7 downto 1) <= hex2led(B(7 downto 4));
LED2(7 downto 1) <= hex2led(B(3 downto 0));
else
LED1(7 downto 1) <= hex2led(BS(7 downto 4));
LED2(7 downto 1) <= hex2led(BS(3 downto 0));
end if;
end process;
end urzadzenie;
Testbencha zamieścić? ;-)
Słowa kluczowe: vhdl programowanie komputer linux
Czemu X zamiast jedynki?
25.11.2006 - Sobota - 18:27
Spodobał mi się VHDL, więc postanowiłem nieco głębiej w niego "wejść", no ale do tego potrzebne mi jest oprogramowanie. Oczywiście, mogę sobie kupić płytkę testową z układem programowalnym, ale wydatek rzędu 150 dolarów mnie przeraża. Muszę korzystać z symulatorów. A pod Linuksem wcale nie jest tak różowo. Co prawda Altera i Xilinx (dwaj czołowi producenci układów programowalnych) udostępniają swoje oprogramowanie w wersji dla Linuksa, ale... ISE Webpack Xilinksa to nieco ponad gigabajt danych do ściągnięcia i spore wymagania jeśli chodzi o sprzęt. A na dodatek "Requires Red Hat Enterprise 3.0", przez co już wiadomo, że mogą być kłopoty z jego uruchomieniem na Ubuntu. W przypadku Altery też podobnie...
Dlatego muszę skorzystać z GHDL-a i Gtkwave'a. Niestety zintegrowanego pakietu, który zrobiłby wszystko za mnie nie znalazłem, ale może i dobrze. Lepiej poznam ten język. W pakietach typu ISE Webpack czy Quartus (Altera) po napisaniu kodu można sobie "wyklikać" przebiegi testowe i zobaczyć odpowiedź układu. W przypadku GHDL-a muszę sobie napisać samemu testbencha (program testujący). I tu się zaczynają schody...
Na początek napisałem sobie prosty licznik modulo 16:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity licznik16 is port( CLK: in std_logic; Q: out std_logic_vector(3 downto 0); R: in std_logic); end licznik16; architecture licz of licznik16 is begin process(CLK, R) variable stan: unsigned(3 downto 0):="0000"; begin if R = '0' then stan:="0000"; elsif (CLK'event and CLK='1') then stan:=stan+1; end if; Q <= std_logic_vector(stan); end process; end licz;
Napisałem, stwierdziłem, że powinien działać, ale warto byłoby go sprawdzić. No to wziąłem się za pisanie testbencha... Na początku wszystko szło bez przeszkód. Testbench napisał się momentalnie. Nieco zaglądałem do podręczników i skakałem po przykładach z Internetu, ale jakoś napisałem. Udało się skompilować i wygenerowałem plik z przebiegami, który obejrzałem sobie w Gtkwave. I tu zaskoczenie! Wszystko gra, ale nie do końca... Ale najpierw rzućmy okiem na testbencha:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity licztb is end licztb; architecture licztbarch of licztb is component licznik16 port(CLK: in std_logic; Q: out std_logic_vector(3 downto 0); R: in std_logic); end component; signal zegar, reset: std_logic; signal Q: std_logic_vector(3 downto 0); begin mapowanie: licznik16 port map(CLK=>zegar, R=>reset, Q=>Q); process begin Q<"0000"; wait for 10 ns; zegar <= '0'; wait for 10 ns; reset <= '1' after 1 ns, '0' after 90 ns, '1' after 150 ns; wait for 10 ns; for i in 0 to 100 loop zegar <= not(zegar); wait for 50 ns; end loop; wait; end process; end licztbarch;
Czyli jak widać, najpierw zeruję wyjście, co na przebiegach widać. Chwilę potem inicjalizuję zegar (zegar ma operować tylko na stanach 0 i 1, wszelkie pozostałe stany są wykluczone), co też widać. Następnie sprytnie generuję sygnał resetujący licznik, chociaż nie muszę tak naprawdę tego robić, bo licznik został zresetowany na początku procesu. W pętli, tworzę prostokątny przebieg zegara o okresie 100 nanosekund. Zegar ten jest sprzężony z zegarem CLK w w samym liczniku. Czyli z każdym zboczem narastającym (CLK'event and CLK='1') licznik będzie się zwiększał o jeden. I wszystko byłoby ok, gdyby nie to, że zamiast stanu 1 na przebiegach pojawia się stan X (co w logice dziewięciowartościowej oznacza stan nieznany). Mało tego! Układ traktuje go jako jedynkę, bo wcale jego pojawienie się nie zaburza działania. Ale mimo to tego stanu tam nie powinno być!
Ślęczę nad tym już którąś godzinę i nie wiem co z tym zrobić... Czyżby to było związane z konwersją zmiennej typu unsigned na sygnał std_logic_vector? Nie wiem... Ktoś pomoże?
Słowa kluczowe: vhdl programowanie komputer linux
Układy programowalne - fajne!
06.11.2006 - Poniedziałek - 20:50
Dzisiaj miałem właściwie pierwszą okazję zapoznać się w praktyce z działaniem układów programowalnych i muszę, z pełną odpowiedzialnością stwierdzić, że jest to fajne ;-)
Ale dla niewprowadzonych krótkie wyjaśnienie. Układy programowalne to takie uniwersalne układy elektroniczne, które można przystosować (zaprogramować) przez wykonywanie fizycznych połączeń pomiędzy poszczególnymi blokami funkcjonalnymi układów do wykonywania najróżniejszych zadań. To taka alternatywa dla drogich układów specjalizowanych.
A jak to wygląda w praktyce? W praktyce mamy w laboratorium płytki testowe, na których jest kilka przycisków, kilka świecących diodek i dwa wyświetlacze siedmiosegmentowe. Taka płytka z układem programowalnym jest podłączona do komputera. Na komputerze jest zainstalowane oprogramowanie producenta układu (w tym przypadku Xilinx), które jest kompilatorem języka VHDL do formatu, który jest wymagany przez ten układ. W VHDL-u piszemy sobie program, który opisuje zachowanie działającego układu. VHDL jest specyficznym językiem programowania, w którym oprócz zmiennych występują również sygnały, a instrukcje można wykonywać współbieżnie lub sekwencyjnie (tak jak to ma miejsce w popularnych, typowo komputerowych językach programowania), dlatego wymaga przestawienia się w inny tryb myślenia. Po skompilowaniu taki program jest wgrywany do pamięci układu. A zawartość pamięci steruje odpowiednimi tranzystorami polowymi, które "otwierają" drogę dla sygnałów, przez co układ zaczyna wykonywać swoje zadanie. W rzeczywistości jest to dość skomplikowane, ale to co widzimy - efekt naszego działania - jest już naprawdę fajną rzeczą ;-)
Z racji nieskomplikowanego układu testowego napisałem dziś tylko licznik modulo 256, z asynchronicznym resetowaniem oraz funkcją start/stop, który wyświetlał swój stan w formie binarnej przy pomocy diód LED oraz w formie szesnastkowej na wyświetlaczach siedmiosegmentowych. Niby nic wielkiego, ale cieszyłem się jak dziecko, choćby dlatego, że jako rasowy programista postawione mi zadanie wykonałem najszybciej i jedynym błędem był drobny błąd w dekoderze sygnału czterobitowego na sygnał ośmiobitowy wyświetlacza siedmiosegmentowego (a właściwie ośmio, bo z kropką ;-)), objawiający się dziwnym wyglądem cyfry "B" ;-) Błąd został szybko poprawiony, a radości nie było końca ;-) Poniżej zamieszczam pełny kod w VHDL-u tego licznika, dla potomności ;-)
library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.all; entity licznik is port( CLK: in std_logic; STOP: in std_logic; RESET: in std_logic; W1: out std_logic_vector(7 downto 0); W2: out std_logic_vector(7 downto 0); Q: inout std_logic_vector(7 downto 0)); end licznik; architecture alicznik of licznik is function hex2led (hex: std_logic_vector(3 downto 0)) return std_logic_vector is variable s: std_logic_vector(7 downto 0); begin case hex is when "0000" => s:= "10000001"; --kod wyswietlacza inny od standardowo przyjetego when "0001" => s:= "11111001"; when "0010" => s:= "00010011"; when "0011" => s:= "00110001"; when "0100" => s:= "01101001"; when "0101" => s:= "00100101"; when "0110" => s:= "00000101"; when "0111" => s:= "11110001"; when "1000" => s:= "00000001"; when "1001" => s:= "00100001"; when "1010" => s:= "01000001"; when "1011" => s:= "00001101"; when "1100" => s:= "10000111"; when "1101" => s:= "00011001"; when "1110" => s:= "00000111"; when "1111" => s:= "01000111"; when others => s:= "00000000"; end case; return s; end hex2led; begin process(CLK, STOP, RESET) variable wartosc: std_logic_vector(7 downto 0); begin if RESET = '1' then wartosc:="00000000"; elsif rising_edge(CLK) and STOP = '0' then wartosc:=wartosc+1; end if; W1<=hex2led(wartosc(7 downto 4)); W2<=hex2led(wartosc(3 downto 0)); Q<=not(wartosc); end process; end alicznik;
Chyba warto się jeszcze trochę podszkolić w VHDL-u ;-)
Słowa kluczowe: WAT komputer programowanie VHDL
Wynajdywanie koła
01.10.2006 - Niedziela - 00:06
Od dwóch dni siedzę przed komputerem i wynajduję ponownie koło. Konkretnie piszę system zarządzania treścią (CMS), który byłby podobny w użytkowaniu jak Wiki, ale mniej skomplikowany i zorientowany na moje wymagania. A wymagania są konkretne: CMS ma zostać zastosowany na stronie firmowej, na której będzie wpisywana aktualna oferta, opisy produktów, ich ewentualna możliwość zamówienia (taki mini sklep internetowy) i temu podobne rzeczy. Ważne jest, żeby CMS nie ograniczał się tylko do gromadzenia treści w bazie danych, ale umożliwiał również wrzucenie jakiegoś pliku ze skryptem PHP w miejsce standardowej strony wygenerowanej z zawartości bazy danych.
Mam już obręcz, czyli zarys działania i budowy systemu. Mam też już dosyć bogatą klasę (piszę obiektowo w PHP 5), ale większość metod wciąż jest pusta i wymaga implementacji. Szprychy wciąż do zrobienia...
Na razie nie zaimplementowałem kodu metody zamieniającej pseudokod (coś w stylu WikiML) na kod XML, ale czuję, że jak się za to wezmę, to trochę będzie grzebania. Wyrażenia regularne mogą wszystkiego nie załatwić. Szczególnie zastanawiam się na sposobem jakiegoś prostego (w zapisie i w sposobie przetworzenia) opisu tabel z danymi. Potem ładowanie i wstawianie obrazków. No i jakieś makra typowo sklepowe: {{cena}}. {{dostępność}}, {{zamów}} itp.
Pozostaje jeszcze problem odwrotnego przekształcenia, czyli przejścia z XML-a (XHTML-a) na wewnętrzny pseudokod. Może to być sporym kłopotem, więc póki co chyba będę robił przekształcenia tylko w jedną stronę, i obie wersje (pseudokod i XML) zapisywał do bazy. Dość nieeleganckie, ale trudno. Nie jest to priorytetem.
Póki co staram się utrzymywać jako taki porządek w kodzie i stosować się jakiejś konkretnej konwencji zapisu, ale jak znam siebie, to za jakiś czas będzie taki burdel, że sam nie będę wiedział co jest gdzie...
P.S. Wczoraj strzeliły mi 0x16|H lata ;-)
Słowa kluczowe: komputer PHP programowanie
Wielki come back?
04.03.2006 - Sobota - 01:24
Pamiętacie?! Kiedyś napisałem, że stworzyłem silnik blogowy, podobny do tego, który jest tutaj, na Antylameriadze. Dziś, starszy o rok wiedzy i doświadczenia, wprowadziłem trochę poprawek do kodu i w ten sposób golBie wrócił!
Jeśli jesteście wystarczająco odważni, możecie przetestować ;-)
Słowa kluczowe: blog golbie programowanie webmaster
ZSR czyli zdalne sterowanie routerem
11.02.2006 - Sobota - 22:25
Tak, już działa. Jest gdzieś w Sieci malutki formularz, do którego należy wklepać polecenie, a to polecenie wykona się na moim routerze ;-)
Aktualnie cron sprawdza dyspozycje co trzy minuty. I to jest chyba najodpowiedniejsza częstotliwość. Raczej nie będę tego zmieniał. Najwyżej rozrzedzę sprawdzanie w godzinach nocnych.
Pozostał mi jeszcze do wykonania moduł wysyłający informacje z routera do serwera pośredniczącego, ale na to też przyjdzie pora ;-)
Słowa kluczowe: komputer programowanie sieć linux
Pascal?! Brrrr....
21.01.2006 - Sobota - 18:11
Jak większość programistów amatorów, swoje pierwsze zetknięcia z programowaniem realizowałem w Turbo Pascalu. Nie zdążyłem jednak dobrze go poznać, bo szybko odkryłem rewelacyjny język, którym jest C. Po tym jak poznałem dobrze C, zacząłem zauważać, jak bardzo Pascal jest niewygodnym i nieintuicyjnym językiem z ograniczonymi możliwościami. W krótkim czasie Pascal stał się moim znienawidzonym językiem. Było to na początku 2000 roku.
Teraz jest rok 2006. Przez te sześć lat starałem się omijać Pascala z daleka i raczej mi się udawało. Najwyżej raz czy dwa, musiałem spojrzeć na kod w Pascalu.
Dziś zostałem poproszony o wprowadzenie poprawek i rozbudowanie pascalowego programu. Pierwsze co zrobiłem, to od razu Google -> "kurs pascala". Zdziwienie było straszne. Ten przestarzały język, który w dzisiejszych czasach ma małe racje bytu (wykluczam tutaj Object Pascala, czyli Delphiego, bo to zupełnie inny sektor), jest wciąż niesamowicie popularny, a kursy piszą już nawet programiści z dwutygodniowym doświadczeniem ;-) Nie wgłębiałem się jeszcze w żaden kurs, ale ważne, że już coś miałem "pod ręką"
Otwieram plik źródłowy programu. Hmm... Ale zupa... Wszędzie tylko widzę begin i end, na dodatek bez wcięć. Próbuję analizować. Nie ma szans. Straszny kod. Ale pewnie się skompiluje. Wciskam Run i wyskakują błędy. Ech... Po omacku staram się poprawić błędy (które później okazały się być strasznymi błahostkami). Udało się skompilować, ale wyniki coś nie tego. Istota programu polega na obliczeniu wszystkiego co tylko możliwe na podstawie dwóch boków trójkąta i kąta pomiędzy nimi. Wredna matematyka. Nie chce mi się sprawdzać wszystkich użytych wzorów po kolei, bo z pewnością musiałbym poświęcić na to cały dzień. Ale powracam do analizy. Wszystkie wzory wyglądają na poprawne, więc gdzie jest błąd... O! Tu coś jest! b:=(6*pi)/180;. Jakie sześć?! Chyba b:=(b*pi)/180;. O! I wyniki wreszcie są normalne.
Przystępuję do dalszych działań. Mam do napisania kod, który będzie rysował dany trójkąt oraz okrąg opisany na tym trójkącie. Co nieco pamiętam jak działał tryb graficzny w Borland C++, więc tutaj (w Turbo Pascalu) nie powinno być większych problemów. Trójkąt narysowałem, ale jak znaleźć środek okręgu?! ;-) Nie chce mi się kombinować, więc korzystam z wyznaczonego już promienia tego okręgu oraz symetralnej jednego z boków. Proste równanie kwadratowe (z pominięciem ujemnego pierwiastka tego równania) i już mam. Ale... Ale dlaczego to koło jest za małe?! Tak... Funkcja round() zawsze zaniża wartości. Trudno dodam nieco do promienia i będzie dobrze. Kompiluję, widzę, że działa. Sukces! Coś pamiętam z tego Pascala ;-)
Dorabiam wcięcia. Tutaj już się chciałem pochlastać, bo ten kod jest straszny. Zamiast klamerek, jakieś dziwne słówka, kropki, średniki, funkcje bez nawiasów... Wrr.... Dziwny język.
A teraz muszę z tego kodu zrobić schemat UML. Zaczynam się bać...
Zastanawiam się też, dlaczego rozpoczynając pisanie tego tekstu miałem w zamyśle stworzenie ostrej krytyki Pascala, a wyszło mi słabe opowiadanko bez drastycznych scen. Hm... Pascal, lepiej po prostu gotuj!
Słowa kluczowe: programowanie
