Az elmúlt évben elég sok időt töltöttem digitális technika oktatásával, főleg konzultációk formájában. Tapasztalatom szerint a legtöbb esetben azért okoz nehézséget a tananyag elsajátítása, mert nem sikerül ráérezni a dolgok lényegére a definíciók és ábrák alapján. (Ez többnyire akkor jelentkezik ha valakiben egyáltalán nincs “hardware-es” beállítottság, mivel itt egy kicsit másabb szemléletre van szükség, mint a programozásnál.)
Ennek a jegyzetnek a célja a fent említett eligazodás megkönnyítése. Ehhez elsősorban az előző évben összegyűjtött analógiákat szeretném itt összegyűjteni, mivel ezek sokaknál segítették az anyag megértését.
A következőkben nem lesznek definíciók és hasonló szabályok kimondva, mert ezek jól össze vannak gyűjtve az előadó jegyzetében is, értelmetlen lenne ide is leírni őket. Erre a célra továbbra is a tárgy honlapján található diákat javaslom. Itt inkább azoknak az anyagoknak a kiegészítései találhatóak, amik akkor segítenek, ha a száraz fogalmak alapján nem sikerül megérteni miről van szó. Éppen ezért ezek a megfogalmazások vagy példák meglehetősen “pongyolák”, pusztán a szemléletességet megértést, a koncepciók elsajátítását és a mélyebb megértést segítik. Ezek mellett néhány gyakorlati példát is összegyűjtöttem, az alkatrészek “elhelyezésének” segítésének céljából.
Az alapkoncepció mindkét esetben ugyanaz: a rendszer kap egy bemenetet és arra egy megfelelő kimenetet ad. A különbség a múlttal való viszony.
Például képzeljük el, hogy beszélgetünk a szobatársunkkal. Két dolgot szeretnénk elérni:
A sorrendi hálózatok esetén ez egy hagyományos beszélgetésnek felel meg. Célszerű tehát, ha előbb a tananyagról kérdeznünk és csak utána hozzuk fel a másik problémánkat, másképpen sosem tudjuk meg, mit kellene csinálni az adott feladatban. Tehát hiába ugyanazok a mondatok hangoztak el, a korábbi mondataink (vagyis a bemenetek sorrendje) meghatározók a kapott válasz szempontjából.
Ilyen mondjuk egy riasztórendszer panelje: Ha korábban érzékelt
valamit, akkor nem mondhatja ellenőrzéskor, hogy minden rendben van.
Hiába volt az elmúlt óra eseménytelen, ez nem felel meg annak, hogy
nem történt semmi rendkívüli, csak azért, mert éppen most nem
történik.
A kombinációs hálózatoknál az illető sajnos beütötte a fejét, így csak addig emlékszik a mondatainkra amíg nem reagált rájuk valamit. Itt nem számít a mondandónk sorrendje. Azután is készségesen segít majd nekünk, ha előbb a mosakodási szokásait kezdjük firtatni. Neki csak az számít, hogy a segítségkérésre magyarázattal, a csípős megjegyzésekre sértett pillantással reagáljon, a választ csak az határozza meg, hogy éppen mire reagál.
Így viselkedik például egy összeadó áramkör. 2 + 2 mindig 4. Attól
függetlenül, hogy milyen műveleteket végzett el korábban.
Ezek gyakorlatilag a programozásból ismert függvények megfelelői, feladatuk pontosan ugyan az, csak a hardware-es világban. A gyakran használt dolgokból szeretnénk ha mindig lenne kéznél, hogy ne kelljen folyton ugyan azt elkészíteni külön-külön minden projektben.
Ha szendvicset készítünk akkor mindegy, hogy szalámis vagy májkrémes lesz, a kenyér mindig ugyan olyan, és nincs is túl nagy kedvünk minden alkalommal sütni egyet, ha harapnánk valamit órák előtt. Ezért kaphatók az ilyen, gyakori hozzávalók készen a boltban és ugyanígy működik ez az elektronikus alkatrészeknél is (vagy éppen a programozásban, ahogy azt láttuk).
Gyakorlatilag egy kiválasztó eszközről van szó. Vannak kimenetei ami egy egy kiválasztható dologhoz mennek, ezek közül ott lesz magas a kiadott jel értéke amelyiket a (bináris) sorszámával “megneveztük”. Mint amikor elmondjuk hányadik fagyit szeretnénk a listából és a boltos rámutat.
A dekóder inverze, a bemenet a kiválasztott port. (Ott magas az érték, a többi kötelezően alacsony.) Ebből állítja elő a kiválasztott port sorszámát binárisan. Gyakorlatilag tömörebb formába alakítja az adatot. A fagyizós példában: Ha egy kisgyerek nem tud olvasni, akkor csak rámutat melyiket kéri, ebből mi megtudjuk mondani melyik az konkrétan. (Név helyett itt egy sorszám van.)
Az enkóderhez hasonló, de nem kötelező, hogy csak egy bemenet lehet kiválasztva, mindig a legnagyobb / legkisebb kiválasztott bemenet sorszámát kapjuk a kimeneten. A jól bevált cukrászdás analógiával: Elmondjuk, hogy szeretnénk egy sütit és, hogy melyikek tetszenek, de a konkrét választást a boltosra hagyjuk. Neki van egy sorrendje ezekből: legyen ez ár szerinti. És az alapján választja a “legfontosabbat” a listából. Tegyük fel, hogy élelmes boltossal állunk szemben és mindig a legdrágábbat tekinti a konkrét választásunknak…
Némileg hasonlítanak a dekóderre (a belsejükben van is egy). A benenet itt is bináris sorszám csak itt nem egy kimenetet húzunk magasra, hanem a különböző bemenetek / kimenetek közül választjuk ki, melyiket akarjuk használni. Ez a viselkedés egy vasúti váltóéhoz hasonlatos. Ott is van egy vágány amit opcionálisan több másikkal köthetünk össze. A vonatok mindig csak az összekötött pályákon át mozognak, az éppen szétkapcsolt szakaszok érdemben nem használhatók…
Ilyen az is amikor a discordon kiválasztjuk melyik mikrofont szeretnénk használni. Nyilván mindegyiktől érkeznek majd jelek, de mi csak egy konkrét eszközét akarjuk tovább engedni, hogy ne legyen “vízhangos” a beszédünk.
Itt is binárisan címzéssel lesz dolgunk, de most előre megadott értékeket lehet kiválasztani, mintha egy-egy polc tartalmát érhetnénk el a sorszámmal. (Nyilván megvalósítható egy multiplexerrel is aminek konstans bemenetei van, ilyen elő is fordul.) Ezzel tetszőleges logikai függvényt könnyen megvalósíthatunk: a rekeszekbe az igazságtábla megfelelő kimenete kell kerüljön. Ez sokszor egyszerűbb mint alapkapukkal megvalósítani, és van, hogy gyorsabb is.
Ilyen LUT-ket használnak a kombinációs logika megvalósítására az FPGA chipekben.
Szintén használják ROM memóriaként például kódolástechnikában a folyamatosan szükséges fix adatok tárolására, de gyakran tárolják így a trigonometrikus függvények eredményét is a gyors számítások érdekében. (A cím itt a paraméterként kapott szög bináris alakja, és a tárolókban a függvény helyettesítési értéke található.)
Két szám közzé megmondja milyen relációs jel kerül(het) azok közül amiket ő ismer.
A +1 vagy -1 műveletet végzik el egy számon. Pont olyan gyakran jön jól mint programozásban, szóval érdemes “céleszközt” csinálni rá.
Két 1 bites számot adnak össze. A full-nál van egy átviteli bit a bemenetek között is a half-nál nincs. Ezeket sorbakötve kapunk nagyobb számokhoz való összeadókat. Half adder ilyenkor csak a sor végére kerülhet, mert minden más helyen lehet átvitel. (Gyakorlatban többnyire a végén is full adder van, mert így kivonásokra is “rávehetőek” ugyanazok a kapuk, de ez (tudtommal) nem tananyag digitből, csak érdekességként írom le ide.)
Ez az órajel(generátor) adja meg a dolgok ütemét, hogy mikor történjen minden. (Hasonlatos egy metronómhoz.) Megvalósítani egy négyszögjellel szokták. Itt “egy ütem” két szomszédos magas vagy alacsony szintre váltás közti időtartam. Az ugyan abba az ütemben lévő események “egyszerre” történnek.
1 bit tárolására jó. Ha órajelet kap megjegyzi az értéket ami éppen a bemenetén van, és a kimenetére teszi. Ezt az értéket tartja a következő órajelig, függetlenül a bemenet változásától.
Gyakorlatilag egymás mellett lévő D Flip - Flopok, így több bites adatok tárolására használhatók. A clk és egyéb vezérlőjeleik ugyan oda vannak kötve, az adatvezetékek természetesen különbözőek.
Olyan regiszterek amik órajelre nem kívülről töltenek be adatot, hanem a meglévő adatot növelik vagy csökkentik eggyel. Ha elérik a felső vagy alsó korlátot akkor a másik oldalról újrakezdik a számolást.
Olyan regiszter amit az egyik vége felől bitenként tudunk feltölteni. Elképzelhetjük ezt egy magas polcként amire csak úgy tudunk pakolni, hogy az egyik szélénél ágaskodva tesszük rá a tárgyakat, úgy, hogy az újjal odébb toljuk a már fent lévőket egy - egy hellyel. Ilyenkor azt is láthatjuk, hogy ha “túl sok” tárgyat akarunk a polcra feltenni, akkor az új tárgy felrakásával egy idő után mindig lelökjük a legrégebben fent lévőt a polc másik oldalánál.
Hasonló elvet követnek a boltok LED-es futófényei is. A tábla végén mindig belép egy új sor, arrébb tolva a már meglévőket, míg az utolsó lekerül a kijelző túloldalán.
Több bites adatokat tárolhatunk benne, de mindig csak a legfrissebben bekerülthöz férhetünk hozzá. Ez az egyetlen alkatrész amihez van elterjedt párhuzam: Valóban olyan mintha egy gödröt töltenénk fel. Itt az adatok a különböző talajrétegeknek felelnek meg és természetesen mindig csak az aktuálisan legfelsőt tudjuk kivenni a tárolóból. Tehát ha a legrégebbi réteg érdekel minket akkor minden fölötte lévőt ki kell “ásnunk”, hogy hozzáférhessünk.
Ilyen tárolókat használunk például a függvényhívásoknál, hogy megtudjuk hová kell majd visszatérnünk. Nyilván mindig a legfrissebben meghívott függvényt fejezzük be leghamarabb, mert a többinek része az, hogy abból visszatérünk.
Hasonlít a LIFO-hoz, de itt mindig a legrégebben betöltött adathoz tudunk hozzáférni. Gondoljunk például egy silóra amibe felülről töltik be a magokat és alul a gravitáció segítségével tudják kiengedni egy részüket ha szükség van rájuk. Hasonlóan jó analógia lehet a sorban állás is. Az emberek ahogyan megérkeznek, beállnak a sor végére és mindig a sor elején álló (azaz a legrégebben érkezett) mehet legközelebb intézni az üget amiért érkezett. (Persze fel kell tenni, hogy senki nem tolakodik a sorban, illetve senki nem unja meg a dolgot és megy haza mielőtt sorra kerülne.)
Ilyen elven működnek például a számítógép pufferei, mondjuk a billentyűzetnél. Szegény gép nem tudja olyan gyorsan feldolgozni az adatokat mint amilyen gyorsan mi nyomkodjuk a billentyűzetet. (Ehhez válasszunk kellően öreg gépet… Nyilván vannak sokkal jobb példák, de ez egy bevezető jegyzet, így célszerű ha a példához nem kellenek extra ismeretek.) Ezért a bejövő adatot beteszi egy ilyen tárolóba amíg oda nem ér a feldolgozásban. Látható, hogy ilyenkor mindig a legrégebb lenyomott karaktert kell néznie különben a betűk nem az általunk megadott sorrendben jelennének meg a monitoron.
Ezek a sorrendi hálózatok egy megjelenési formái. A lényeg, hogy a rendszernek vannak jól definiált állapotai amikben lehet. (Egyszerre csak egyben.) Az, hogy a rendszer hogyan reagál az nemcsak a bemenettől, hanem az aktuális állapottól is függ. A korábbi szobatársas példához visszatérve: Nem ugyan azt a választ kapjuk egy kérdésre, ha előzőleg megsértettük a másikat. (Azaz a hangulata sértett lett, ami tekinthető egy állapotnak.)
Az állapotgépeknek nagyon nagy gyakorlati haszna van, de a megjelenésük teljesen más mint például egy funkcionális egységnek. Inkább modellezési eszköz ami átláthatóbbá, kezelhetőbbé teszi a rendszert, de a használatuk nem feltétlenül szükséges mindig a megoldáshoz. (Bár határozottan hasznos ez a megközelítés.)
Állapotgépes tervezésre egy nagyon érdekes példa az F 22-es vadászgépek vezérlőrendszere: A repülés különböző szakaszaiban a repülők nem ugyanúgy reagálnak, továbbá az emberi intuíció és reflexek sokszor pont ellentétes mozdulatokat sugalnak, mint amit a kívánt eredményhez tenni kellene. A pilóták képzésénél erre éppen ezért rengeteg figyelmet kell szentelni, de még így is sok problémát okoznak ezek a jelenségek. Emiatt az F22-esnél a vezérlőszervek jelei egy állapotgépen haladnak át. A rendszer állapota az aktuális repülési információtól függ, és az adott helyzethez tartozó természetes reakciókhoz és egyéb paraméterekhez illeszkedő parancsokat továbbít a vezérsíkoknak és hajtóműveknek. Ennek köszönhetően eredményesebbek lehetnek a pilóták, mert nem kell “saját maguk ellen küzdeniük”.
Itt egy gyors áttekintés található a tipikus megvalósítás részeiről.
Tárolja a rendszer aktuális állapotát, többnyire valamilyen azonosítószámmal megfeleltetve.
Kombinációs logikai áramkör ami a bemenetek és az aktuális állapot alapján megmondja milyen állapotban lesz legközelebb a rendszer. A kimenete lesz az állapotregiszter bemenete.
Kombinációs logikai áramkör ami a bemenetek és az aktuális állapot alapján megadja az aktuális kimenetet.
Ezek az eszközök valamilyen konkrét feladat megoldására szolgálnak. (Az előadáson egy üdítőautomata szerepel példaként.) Két fontos részből állnak:
A rendszer szempontjából fontos változók tárolása és a rajtuk szükséges műveletek eredményeinek előállítása. (Kombinációs logikával, mindig minden számítást elvégez párhuzamosan. saját maga “nem hoz döntést”, csak előkészít minden információt, mint egy asszisztens.) Továbbá az adatok alapján különböző jelzéseket állít elő. A saját adatait külső jelzések alapján frissíti.
Itt van megvalósítva az “üzleti logika”: Az adatszerkezet adatai és jelzései alapján vezérli az adatszerkezet működését. Ő maga rendszerint egy állapotgéppel működik, ezért sorrendi hálózat.
Akkor szokás ilyen áramköröket tervezni, ha egy adott, jól körülhatárolt feladatnál fontos a vezérlés teljesítménye. Mivel tudjuk milyen adatokon milyen műveletek lehetségesek, ezért minden “azonnal” rendelkezésre állhat a párhuzamos számításoknak köszönhetően. Álltalában is elmondható, hogy egy céleszköz jobban teljesít adott feladatban mint egy álltalános megoldás.
Egy ilyen eszköz mindig az adott feladathoz specifikus áramköröket igényel, gyakorlatilag minden alkalommal nulláról kell kezdeni a munkát, ezért a fejlesztés hosszabb ideig tart és egy egyedi chip (ASIC) gyártása rendkívül költséges, ezért nem feltétlenül a legjobb megoldás, ha nincs szükségünk a fent említett teljesítményre.
Ezekre az esetekre jöttek létre a mikroprocesszorok. A felépítésük hasonló az előbbiekhez: Itt is van egy számításokat végző adatstruktúra és egy vezérlő ami a munkáját irányítja, de van néhány komoly különbség:
Ugyan az a chip számtalan feladatnál felhasználható ezért jóval olcsóbban elérhető megoldást nyújt a problémákra. Mivel a hardver rendelkezésre áll és csak programozni kell, gyorsabban és olcsóbban elkészíthető a kívánt eszköz.
A soros végrehajtás miatt a számítások lassabbak lesznek, ezzel megnő a rendszer válaszideje.