Digitális technika II. (vimia111) 5. gyakorlat: Mikroprocesszoros tervezés, egyszerű feladatok HW és SW megvalósítása gépi szintű programozással



Hasonló dokumentumok
Digitális technika II. (vimia111) 5. gyakorlat: Tervezés adatstruktúra-vezérlés szétválasztással, vezérlőegység generációk

A MiniRISC processzor

A mikroszámítógép felépítése.

[cimke:] [feltétel] utasítás paraméterek [; megjegyzés]

Egyszerű RISC CPU tervezése

Digitális technika VIMIAA01

A TMS320C50 és TMS320C24x assembly programozására példák

12. NYOMÓGOMBOK ÉS KAPCSOLÓK PERGÉSMENTESÍTÉSE A FEJLESZTŐLAPON

A számítógép alapfelépítése

1. ábra: Perifériára való írás idődiagramja

5. KOMBINÁCIÓS HÁLÓZATOK LEÍRÁSÁNAK SZABÁLYAI

A Picoblaze Core implementálása FPGA-ba

LOGIKAI TERVEZÉS HARDVERLEÍRÓ NYELVEN. Dr. Oniga István

LOGSYS LOGSYS ECP2 FPGA KÁRTYA FELHASZNÁLÓI ÚTMUTATÓ szeptember 18. Verzió

Számítógépek felépítése, alapfogalmak

4. Fejezet : Az egész számok (integer) ábrázolása

1. Az utasítás beolvasása a processzorba

Dr. Oniga István DIGITÁLIS TECHNIKA 8

4. KOMBINÁCIÓS HÁLÓZATOK. A tananyag célja: kombinációs típusú hálózatok analízise és szintézise.

Digitális technika VIMIAA hét

Digitális technika VIMIAA hét

Dr. Oniga István DIGITÁLIS TECHNIKA 9

A feladatokat önállóan, meg nem engedett segédeszközök használata nélkül oldottam meg: Olvasható aláírás:...

Digitális technika (VIMIAA02) Laboratórium 5

Digitális technika (VIMIAA02) Laboratórium 5

0 0 1 Dekódolás. Az órajel hatására a beolvasott utasítás kód tárolódik az IC regiszterben, valamint a PC értéke növekszik.

Az INTEL D-2920 analóg mikroprocesszor alkalmazása

1. Kombinációs hálózatok mérési gyakorlatai

Mikroprocesszor CPU. C Central Központi. P Processing Számító. U Unit Egység

Mérés labor 2 AVR házi feladatok

Újrakonfigurálható eszközök

Laborgyakorlat 3 A modul ellenőrzése szimulációval. Dr. Oniga István

Az integrált áramkörök kimenetének kialakítása

Digitális technika (VIMIAA02) Laboratórium 1

A Számítógépek felépítése, mőködési módjai

FPGA áramkörök alkalmazásainak vizsgálata

Digitális technika (VIMIAA02) Laboratórium 1

Mérési jegyzőkönyv. az ötödik méréshez

Laborgyakorlat Logikai áramkörök számítógéppel segített tervezése (CAD)

A DDS áramkörök használata.

Laborgyakorlat Logikai áramkörök számítógéppel segített tervezése (CAD)

Digitális technika (VIMIAA02) Laboratórium 5.5

assume CS:Code, DS:Data, SS:Stack Start mov dl, 100 mov dh, 100 push dx Rajz

Laborgyakorlat Logikai áramkörök számítógéppel segített tervezése (CAD)

Tervezési módszerek programozható logikai eszközökkel

LOGIKAI TERVEZÉS HARDVERLEÍRÓ NYELVEN. Dr. Oniga István

Assembly utasítások listája

Gábor Dénes Főiskola Győr. Mikroszámítógépek. Előadás vázlat. 2004/2005 tanév 4. szemeszter. Készítette: Markó Imre 2006

A feladatokat önállóan, meg nem engedett segédeszközök használata nélkül oldottam meg: Olvasható aláírás:...

Digitális technika VIMIAA01 9. hét Fehér Béla BME MIT

Digitális technika VIMIAA01 9. hét

Hardver leíró nyelvek (HDL)

1. eset: a háromból két motor 5 s-nál hosszabb ideig leáll. (Időkésleltetett jelzés). 2. eset: mindhárom motor leáll. (Azonnali jelzés).

Digitális technika (VIMIAA02) Laboratórium 3

Digitális technika VIMIAA02 9. hét Fehér Béla BME MIT

PWM elve, mikroszervó motor vezérlése MiniRISC processzoron

A MiniRISC processzor (rövidített verzió)

Verilog HDL ismertető 2. hét : 1. hét dia

Kombinációs áramkörök modelezése Laborgyakorlat. Dr. Oniga István

Laborgyakorlat Logikai áramkörök számítógéppel segített tervezése (CAD)

2. Digitális hálózatok...60

Közlekedés gépjárművek elektronikája, diagnosztikája. Mikroprocesszoros technika. Memóriák, címek, alapáramkörök. A programozás alapjai

Összetett feladatok megoldása

3. Hőmérők elkészítése

CDC 2000 Vezérlő 6.Alap-,és speciális funkció beállítások

Balaton Marcell Balázs. Assembly jegyzet. Az Assembly egy alacsony szintű nyelv, mely a gépi kódú programozás egyszerűsítésére született.

Digitális technika (VIMIAA02) Laboratórium 3

DT4220 E xx xx xx (PS) Folyamatindikátor. Kezelési útmutató

Digitális rendszerek. Utasításarchitektúra szintje

ISE makró (saját alkatrész) készítése

XIII. Bolyai Konferencia Bodnár József Eötvös József Collegium, ELTE TTK, III. matematikus. A véletlen nyomában

LOGSYS EGYSZERŰ ALKALMAZÁS KÉSZÍTÉSE A LOGSYS KINTEX-7 FPGA KÁRTYÁRA A XILINX VIVADO FEJLESZTŐI KÖRNYEZET HASZNÁLATÁVAL június 16. Verzió 1.

A számítógép alapfelépítése

DSP architektúrák dspic30f család

AX-3003P AX-6003P. 1. A kezelési útmutató használata. 2. Biztonságra vonatkozó információk

Mérési útmutató. A/D konverteres mérés. // Első lépésként tanulmányozzuk a digitális jelfeldolgozás előnyeit és határait.

Digitális technika VIMIAA hét

Hobbi Elektronika. A digitális elektronika alapjai: Újrakonfigurálható logikai eszközök

A MiniRISC processzor

Miért van szükség fordítóprogramokra? Fordítóprogramok célja és szerkezete. Miért van szükség fordítóprogramokra?

DDS alapú szinusz jelgenerátor fejlesztése

11. KÓDÁTALAKÍTÓ TERVEZÉSE HÉTSZEGMENSES KIJELZŐHÖZ A FEJLESZTŐLAPON

Digitális technika VIMIAA02 9. hét

Beágyazott és Ambiens Rendszerek Laboratórium BMEVIMIA350. Mérési feladatok az 1., 2. és 3. mérési alkalomhoz

AES kriptográfiai algoritmus

Joint Test Action Group (JTAG)

10. EGYSZERŰ HÁLÓZATOK TERVEZÉSE A FEJLESZTŐLAPON Ennél a tervezésnél egy olyan hardvert hozunk létre, amely a Basys2 fejlesztőlap két bemeneti

E7-DTSZ konfigurációs leírás

Fordulatszámmérő és szabályozó áramkör tervezése egyenáramú kefés motorhoz

Boundary Scan. Új digitális áramkör-vizsgálati módszer alkalmazásának indokoltsága

Analóg és digitális jelek. Az adattárolás mértékegységei. Bit. Bájt. Nagy mennyiségû adatok mérése

Digitális technika (VIMIAA01) Laboratórium 9

E-Laboratórium 1 Kombinációs digitális áramkörök alkalmazása Elméleti leírás

FAAC 844T. Háromfázisú Toló Motor Vezérlés

A MiniRISC processzor

ELŐADÁS SZÁMÍTÓGÉP MŰKÖDÉSE FIZIKA ÉS INFORMATIKA

Ellenőrző mérés mintafeladatok Mérés laboratórium 1., 2011 őszi félév

A PicoBlaze vezérlő alkalmazása a LOGSYS kártyán

Digitális technika (VIMIAA01) Laboratórium 4

Számítógép Architektúrák

Átírás:

Digitális technika II. (vimia111) 5. gyakorlat: Mikroprocesszoros tervezés, egyszerű feladatok HW és SW megvalósítása gépi szintű programozással Megoldás Elméleti anyag: Processzor belső felépítése, adat és vezérlő struktúra részletes elemzése o Tipikus RISC architektúra és utasítás végrehajtás o INIT-FETCH-DECODE-EXECUTE állapotdiagram o Mikrovezérlő-mikroprocesszor különbségek o Neumann és Harvard architektúra o Utasítás formátumok, utasítás kódolás, utasítás csoportok és típusok o Címzési módok következő utasítás és adatelérés esetén Példa: A MiniRISC mikrovezérlő felépítése, utasításai, programozása egy egyszerű grafikus környezetben a LOGSYS kártyán Irodalom: Alapvetően az órai jegyzet, a tárgy honlapján elérhető MiniRISC processzorral kapcsolatos anyagok, Verilog programozási anyagok, és érdemes áttekinteni a Benesóczky Zoltán: Digitális tervezés funkcionális elemekkel és mikroprocesszorokkal, egyetemi tankönyv, (MK55033) 4. fejezetét, A mikroprocesszor és a mikroprocesszoros rendszer címmel. A gyakorlat anyaga megpróbál közvetlen összehasonlítási lehetőséget adni a kiválasztott egyszerű mintapéldák hardver és szoftver megvalósításai között. A mintamegoldások a LOGSYS SP3E kártyán tesztelhetők. A HW megoldások a LOGSYS GUI használatával, a SW megoldások a MiniRISC GUI fejlesztési környezettel működtethetők. A mellékletek tartalmazzák a letölthető kódokat, de természetesen a lényeg a megoldások elemzésében van. A HW megoldások Verilog nyelven készültek, jó például szolgálnak a különböző feladatok megoldásának HDL nyelvű kódolására, a terv hierarchia bemutatására. A leírások a szokásosnál több megjegyzést, magyarázatot tartalmaznak, emiatt esetleg bonyolultabbnak tűnnek, mint valójában. A SW megoldások a MiniRISC mintarendszerre és a MiniRISC assembly programok alkalmazására épülnek. Ennek használatával a mintaprogramok ellenőrizhetők, lépésenként végrehajthatók, stb. A MiniRISC programozását, utasításait, az assembler használatát, a kialakított MiniRISC mintarendszert, a perifériákat és a fejlesztői GUI alkalmazás szolgáltatásait és használatát a MiniRISC processzort bemutató diasorozat ismerteti. 1

Gyakorló példák: 5.1. Tervezze meg egy bináris tömbszorzó áramkör kapcsolási rajzát! Elemezze a szorzási műveletet (hagyományos papír-ceruza módszer), majd tervezze meg a szükséges elemeket, amelyekből a szorzó egyszerűen összerakható. A terv legyen képes 4 bites nem negatív számok (0-15) összeszorzására. A bemeneti operandusok: SZORZÓ SW[3:0], SZORZANDÓ SW[7:4]. Az eredményt jelezzük ki a LED[7:0] kijelzőn. Az előjel nélküli bináris szorzás legegyszerűbben a normál papír-ceruza szerinti szorzási algoritmus szerint végezhető el. A művelet végrehajtásakor a bináris aritmetika szabályai szerint járunk el, nem alkalmazunk semmilyen speciális optimalizálást. A szorzó áramkör külső interfészei és belső felépítése a következő ábrákon látható: A bináris tömbszorzó egy tisztán kombinációs hálózat. A szorzó bitjei és a szorzandó meghatározzák részszorzatokat, amelyek vagy 0 vagy a szorzandó értékét veszik fel. Ezeket azután az aktuális szorzó bitek bináris súlyának megfelelően kell összegezni. //* Digitális tömbszorzó példaáramkör 4 bites, előjel nélküli számok szorzására* //* A bemenetei értéktartomány 0-15, a maximális eredmény 15*15 = 225, * //* tehát a 8 bites eredményben soha nem léphet fel túlcsordulás * //* A tömbszorzó megvalósítása: * //* * //* 1001 * 0110 * //* ------- * //* 0000 = (1001 & 0000) << 0 * //* 10010 = (1001 & 1111) << 1 * //* 100100 = (1001 & 1111) << 2 * //* +0000000 = (1001 & 0000) << 3 * //* -------- * //* 00110110 * //* * //* A megvalósításnál a papír-ceruza módszert használjuk. A részszorzatokat * //* megkapjuk a szorzandónak és a szorzó egyes bitjeinek ÉS kapcsolataként, * //* melyet el kell shiftelni balra a szorzó adott helyiértékének megfelelő * //* számú bittel. Ezután össze kell adni az egyes részszorzatokat. 4 bites * //* összeadók elegendőek a 0-k beshiftelése miatt. Az összeadók kimenete 5 * //* bites, az MSb az átvitelbit. A részszorzatösszegek LSb bitje egyúttal a * //* teljes szorzat adott helyiértékű eredménybitje, tehát ezt a teljes 8 bites * //* szorzat kialakításakor felhasználjuk * module mul_4bitu( input wire [3:0] multiplicand, //Szorzandó input wire [3:0] multiplier, //Szorzó output wire [7:0] product //Szorzat ); //Változók a részeredmények kiszámításához. wire [3:0] partial_product0, partial_product1; wire [3:0] partial_product2, partial_product3; wire [4:0] sum1, sum2, sum3; // A szorzás elemi műveletei a részszorzatok előállítására egyszerű bitszorzatok 2

// Az ÉS művelet 2. operandusa a szorzó egyes bitjeit felhasználva // képezett 4 bites bitvektor. Hasonlóan helyes a következő is: // Ha a szorzó bitje 1, akkor a részszorzat a szorzandó, egyébként 0. Tehát // // assign partial_product_x = multiplier[x]? multiplicand : 4'b0; // // Az így betervezett multiplexer a 0 adatbemenet miatt éppen az alábbi logikára // egyszerűsödne assign partial_product0 = multiplicand & {4{multiplier[0]}}; assign partial_product1 = multiplicand & {4{multiplier[1]}}; assign partial_product2 = multiplicand & {4{multiplier[2]}}; assign partial_product3 = multiplicand & {4{multiplier[3]}}; // A szorzat a részszorzatok súlyozott iteratív összegzése assign sum1 = {1'b0, partial_product0[3:1]} + partial_product1; assign sum2 = sum1[4:1] + partial_product2; assign sum3 = sum2[4:1] + partial_product3; //A szorzat előállítása. assign product = {sum3, sum2[0], sum1[0], partial_product0[0]}; endmodule Az áramkör specifikációja a mult_4bitu.v verilog fájlban található. A kész terv működése bemutatható a mult_4bitu_top.bit fájl segítségével. Érdemes egy-két szót szólni a kettes komplemens számábrázolás szerint megvalósítható előjeles szorzóáramkör kialakíthatóságáról is. Eltérést jelent az MSB bit negatív értelmezése. Más a hatás, ha a szorzó, a szorzandó, ill. mindkettő negatív. Igen érdekes a -1 * -1 művelet. 3

5.2. Készítse el a 4 bites pozitív számok szorzására képes MiniRISC assembly programot. A bemeneti adatok SZORZÓ SW[3:0], SZORZANDÓ SW[7:4] szerint a 0x01 címen az SW perifériáról olvashatók be, az eredmény a 0x00 címen lévő LED periférián jelenjen meg. A program végtelen ciklusban működjön. A szorzás művelet legegyszerűbb verziója, nem okozhat nehézséget. A forrásfájlok megtalálhatók a mellékletben. A kommentezett assembly program lépéseit mutassuk be értelmezve. ;* 4 x 4 bites előjel nélküli tömbszorzó. * ;* * ;* A tömbszorzó megvalósítása: * ;* * ;* 1001 * 0110 * ;* ------- * ;* 0000 = (1001 & 0000) << 0 * ;* 10010 = (1001 & 1111) << 1 * ;* 100100 = (1001 & 1111) << 2 * ;* +0000000 = (1001 & 0000) << 3 * ;* -------- * ;* 00110110 * ;* * ;* A megvalósításnál a papír-ceruza módszert használjuk. A részszorzatokat * ;* megkapjuk a szorzandónak és a szorzó egyes bitjeinek ÉS kapcsolataként, * ;* melyet el kell shiftelni balra a szorzó adott helyiértékének megfelelő * ;* számú bittel. Ezután össze kell adni az egyes részszorzatokat. * DEF LD 0x80 ; LED regiszter (írható/olvasható) DEF SW 0x81 ; DIP kapcsoló regiszter (csak olvasható) CODE ;* A program kezdete. A programmemória 0x00 és a 0x01 címe a reset, illetve * ;* a megszakítás vektor. Ide ugró utasításokat kell elhelyezni, amelyek a * ;* megfelelő programrészre ugranak. Ha nem használunk megszakítást, akkor a * ;* program kezdődhet a 0x00 címen is. * start: mov r0, SW ; Beolvassuk a kapcsolók állapotát. ; SW[7:4] = Szorzandó SW[3:0] = Szorzó mov r1, r0 ; A szorzót (SW[3:0]) az r1 regiszterbe másoljuk and r1, #0x0f ; és nullázzuk a felső 4 bitet. and r0, #0xf0 ; Az alsó biteket nullázva r0 tartalmazza a szorzandót. sr0 r0 ; Ezt jobbra shiftelve rendelkezésre áll az első ; részszorzat (ha így kezdjük, jobb az algoritmus). mov r2, #0 ; r2 előkészítése a szorzat tárolására ; A szorzást ciklusokban végezzük el, r2-ben ; folyamatosan akkumláljuk a részszorzat összegeket mov r3, #4 ; A 4 bites szorzáshoz a ciklust inicializáljuk mul_loop: tst r1, #0x08 ; Megvizsgáljuk a szorzó legnagyobb helyiértékű jz no_add ; bitjét. Ha 0, akkor nem kell a részszorzatösszegzés add r2, r0 ; Hozzáadjuk a részszorzatot az r2 regiszterhez. no_add: sr0 r0 ; A szorzandót jobbra kell shiftelni, hogy ; megkapjuk a kövezkező részszorzatot. sl0 r1 ; A szorzót balra kell shiftelni, hogy a ; következő vizsgálandó bit a 3. bitpozicióba kerüljön. sub r3, #1 ; Csökkentjük a ciklusváltozót. jnz mul_loop ; Ha nem nulla még, akkor visszaugrás. mov LD, r2 ; A szorzatot megjelenítjük a LED-eken. jmp start ; Ugrás a program elejére.. 4

5.3 Tervezze meg egy 8 bites bináris érték aktív egyeseit megszámláló áramkör kapcsolási rajzát. A bemeneti adatok a SW[7:0] bemeneten állíthatók be, az eredményt a LED[7:0] kimeneten, és/vagy a 4 digites 7 szegmenses kijelző legkisebb helyiértékén jelenítse meg. A népesség számláló áramkör sok alkalmazásban előkerül, mint feladat (többek között a nagysebességű pipeline szorzóáramkörök belső összeadó hálózatában is). A hardver megoldásra több lehetőség adódik, ezek egyike az egybites összeadók használata. Ebben a tervben egy teljes összeadó fát építettünk fel, és a numerikus kijelzést egy bin_2_7seg dekóder biztosítja (csak 0-tól 8-ig dekódol). A feladat egy 8 bemenetű, 3 kimenetű logikai függvény, tehát közvetlenül, kombinációs hálózattal realizálható. (Lehetne persze egy iteratív számlálós megoldást is készíteni, de ebben a bitméretben nincs értelme). Tehát használhatnánk egy 256 * 3 bites ROM memória táblázatot. Ez azonban költséges lehet. Másik megoldás, 2 db 4 bemenetű, 3 kimenetű részhálózat, + egy 3 bites összeadó. Azaz 2 db 16 * 3 bites ROM + 3 bit ADD. Ez már egyszerűbbnek tűnik, mint a fenti adatfolyam gráf. A fenti blokkvázlat (Nem kapcsolási rajz!!!) összeadó fa első szintje 4 db 1 bites félösszeadót, a második szint 2 db 2 bites összeadót, a harmadik pedig 1 db 3 bites összeadót tartalmaz. Ez utóbbi 3 eredménybitje, az átvitel bittel együtt kiadja a 0-8-ig szükséges értékek bináris reprezentálhatóságát. Lehetne használni inkrementereket lineáris láncban is, de az lenne a legköltségesebb és a leglassabb. (1 db HA, 2 db 2 bit INC, 4 db 3 bit INC). Megjegyzés: 8 bit esetén nincs jelentősége, de nagyobb méretnél (>20-100 ) érdemes elgondolkodni az első szintek megvalósításán, ahol gyakran alkalmaznak közvetlen 3 -> 2 (ez az 1 bites teljes összeadó) vagy 5->3 ill. 7->3 típusú (kombinációs) számoló áramköröket. További optimalizációs lehetőség, a magasabb szinteken az összeadók szabad carry bemenetének kihasználása. 5

module pop_cnt( input wire [7:0] data, output wire [3:0] population ); //Bemeneti adatvektor //Kimeneti eredmény //* A 8 bites bináris számban található 1 biteket hét összeadó segítségével * //* számolhatjuk meg: össze kell adnunk a szám összes bitjét. Az összeadókat * //* célszerű fa formában elrendezni, az egyes szinteken növekvő bitszámú * //* összeadókat felhasználva az átvitel miatt. * //* * //* bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 * //* \ / \ / \ / \ / * //* + + + + 1 bites összeadók * //* * //* \--- + ---/ \--- + ---/ 2 bites összeadók * //* * //* \-------- + --------/ 3 bites összeadó * //* * //* num_of_1s[3:0] * //* * //* Megjegyzés: Érdemes elgondolkodni, hogy milyen más megoldások létezhetnek, * //* amik kevesebb aritmetikai áramkörrel oldják meg a feladatot? * assign population = ((data[7] + data[6]) + (data[5] + data[4])) + ((data[3] + data[2]) + (data[1] + data[0])); endmodule A tervezői fájlok: pop_cnt.v és bin_2_7seg.v. A pop_count_top.bit fájl a terv bemutatására szolgál. 6

5.4. Készítsen MiniRISC assembly programot, ami beolvassa az SW periférián beállított értéket és megszámolja az aktív bitek számát, majd ezt kijelzi a LED periférián és/vagy a 4 digites 7 szegmenses kijelző legkisebb helyiértékű digitjén. Ez a program hasonló komplexitású, mint az előző. Az aktív bitek száma ciklusban számlálódik, mindaddig, amíg a léptetéssel el nm érjük, hogy a vizsgált regiszter tartalma csupa 0. Ez a ciklus tehát nem 8N ideig fut, hanem csak k*n, ahol k az utolsó aktív bit indexe, N a számláló ciklus átlagos hossza (jelen esetben 4,5 utasítás). Mutassuk be a kijelző megoldást. Jelezzük, hogy a hétszegmenses kijelző periféria nem tartalmaz BCD > 7SEG konverziót, a táblázat a közvetlen kódképeket tartalmazza, tehát bármilyen animáció lejátszható rajta. Hangsúlyozzuk, hogy az adatbájtok nem maguktól kerülnek az adatmemória területre, azt a fejlesztői környezet tölti be a letöltés során. E nélkül programból kellene közvetlen adat utasításokkal feltölteni, ami jelentős program overhead-et jelentene (még kb, 16 utasítás). ;* 8 bites bináris számban az egyesek megszámlálása. * DEF LD 0x80 ; LED regiszter (írható/olvasható) DEF SW 0x81 ; DIP kapcsoló regiszter (csak olvasható) DEF D0 0x90 ; A kijelző DIG0 regisztere (írható/olvasható) CODE ;* A program kezdete. A programmemória 0x00 és a 0x01 címe a reset, illetve * ;* a megszakítás vektor. Ide ugró utasításokat kell elhelyezni, amelyek a * ;* megfelelő programrészre ugranak. Ha nem használunk megszakítást, akkor a * ;* program kezdődhet a 0x00 címen is. * start: mov r0, SW ; Beolvassuk az adatot a SW-ről az r0 regiszterbe. mov r1, #0 ; Töröljük a "népesség" számláló munkaregisztert. loop: ; Ciklusban számoljuk az aktív biteket. ; Kilépünk a ciklusból, ha r0 értéke 0. tst r0, #0x01 ; Megvizsgáljuk az LSb-t. Nem növeljük jz no_inc ; meg r1 értékét, ha a vizsgált bit 0. add r1, #1 ; Megnöveljük az 1 bitek számát. no_inc: sr0 r0 ; Jobbra shifteljük az adatot, hogy a következő ; bit az LSb-re kerüljön. jnz loop ; A ciklusban maradunk, ha van még 1 bit. mov LD, r1 ; Kiírjuk az 1 bitek számát a LED-ekre. add r1, #sgtbl ; A táblázat kezdőcímét hozzáadjuk az 1 bitek számához. mov r2, (r1) ; A táblázat alapján elvégezzük a BIN->7SEG konverziót mov D0, r2 ; Megjelenítjük az 1 bitek számát a hétszegmenses kijelzőn. jmp start ; Végtelen ciklusban ismételjük az adat beolvasását. DATA ;* Programkonstansokat az adatmemóriában tárolhatunk. Az első kilenc címre * ;* feltöltjük a hétszegmenses dekóder szegmensképeit. Ebből a táblázatból * ;* regiszter indirekt címzéssel könnyen kiolvashatjuk a megfelelő értékeket. * sgtbl: DB 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f 7

5.5 Tervezze meg azt az áramkört, ami egy 8 LED-es kijelzőn animálja a Knight Rider fényeffektus egyszerűsített verzióját (egy vagy kettő vagy három teljes fényességű LED vándorol balról jobbra majd vissza). Készítsen HW blokkvázlatot és rajzolja fel a tervezett logikát. A logika a LOGSYS kártya 16MHz-es órajeléről működjön, a léptetés sebessége 0,5s. A HW terv központi része egy egyszerű shiftregiszteres logika. A külső interfészei és belső felépítése a következő ábrákon látható: A terv specifikációját a kr_2leds_top.v, a kr_2leds.v és a clk_div_500ms.v Verilog fájlok tartalmazzák. A terv egy hierarchikus logikai terv, a fenti 2 modulból áll. A szélső értékek elérése előtt gondoskodunk az irányválasztó flag átbillentéséről, tehát a szélső értékbe lépés után a lépésirány megfordul. //* Knight Rider futófény két LED-del megvalósítva. * module kr_2leds( input wire clk16m, //16 MHz órajel input wire rstbt, //Reset jel input wire clk_div_tc, //Ütemező jel output reg [7:0] shr //Kijelző állapota ); //* Shiftregiszter. * //* Egy 8 bites kétirányú shiftregiszterben tároljuk a LED-ek állapotát. Reset * //* hatására a két baloldali LED-et (LD7 és LD6) gyújtjuk ki. Ha a működése * //* engedélyezett, akkor egy nullát shiftelünk be az iránynak megfelelő bitbe. * //Irány kiválasztó jel (0: jobb shift, 1: bal shift). reg shr_dir; always @(posedge clk16m) begin if (rstbt) shr <= 8'b1100_0000; if (clk_div_tc) if (shr_dir) shr <= {shr[6:0], 1'b0}; shr <= {1'b0, shr[7:1]}; end //Reset //Bal shift //Jobb shift 8

//* Az irány kiválasztó regiszter. * //* Reset hatására a shiftregiszter jobbra fog shiftelni. Az irányt mindig * //* a végállapot elérése előtti állapotban kell megváltoztatni a szinkron * //* működés miatt. * //* * //* Irány 7 6 5 4 3 2 1 0 * //* -> _ # # _ : váltás bal shiftelésre (1 beírása) * //* <- _ # # _ : váltás jobb shiftelésre (0 beírása) * wire change_to_left = ~shr_dir & shr[2] & shr[1]; wire change_to_right = shr_dir & shr[6] & shr[5]; always @(posedge clk16m) begin if (rstbt) shr_dir <= 1'b0; if (clk_div_tc) if (change_to_left) shr_dir <= 1'b1; if (change_to_right) shr_dir <= 1'b0; end //Reset: jobb shift //Váltás bal shiftelésre //Váltás jobb shiftelésre endmodule Az clk_div_500ms minden fél másodpercben kiadja az 1 órajelperiódus (16MHz -> 62.5ns) hosszúságú clk_div_tc jelet. Ez engedélyezi a kr_2leds.v modulban lévő shift regiszter léptetését. //* Fél másodperces ütemező, 16MHz órajelről * module clk_div_500ms( input wire clk16m, //16 MHz órajel input wire rstbt, //Reset jel output wire clk_div_tc //2 Hz-es ütemező jel ); //* Órajel osztó. * //* A futófény léptetésének sebessége 0,5 s. A 2 Hz-es engedélyező jelet egy * //* 23 bites lefele számlálóval állítjuk elő, amelybe reset vagy a végállapot * //* elérésekor 7999999 (= 16*10^6 / 2-1) értéket töltünk be. * //A számláló állapotát tároló regiszter. reg [22:0] clk_divider; //A számláló végállapot jelzése. Ez lesz a főmodul engedélyező jele. assign clk_div_tc = (clk_divider == 23'd0); always @(posedge clk16m) begin if (rstbt clk_div_tc) clk_divider <= 23'd7999999; clk_divider <= clk_divider - 23'd1; end endmodule A működés a kr_2leds_top.bit fájl letöltésével bemutatható. 9

5.6. Készítse el az 5.5. feladat SW verzióját, a MiniRISC mikrovezérlő használatával. A mikrovezérlő utasításkészletét összefoglalóan a MiniRISC processzort bemutató diasorozat ismerteti. A LED periféria a 0x80 címen elérhető kimeneti periféria, visszaolvasási lehetőséggel (Basic_OwR). A processzor órajele 16MHz, a léptetés sebessége legyen kb. 0,5s. A megoldás ismertetéséül mellékelem az assembler fordítási listáját. A program 25 soros, sajnos ennél egyszerűbb feladatokat (aminek van valami értelme is), nehéz kitalálni. A forráslista, és a letölthető kr_2leds.svf a mellékletben található. A hardver időzítőn (TIMER) alapuló megoldás a gyakorlaton nem szerepelt, mert a perifériák bemutatása sem volt még az előadáson. Ennek ellenére a megoldásban, mint szemléltető példa rendelkezésre áll. A sárgával kiemelt rész a 8 bites időzítő/számláló felprogramozása és használata várakozásos üzemmódban. A processzor akkor is tud valami hasznosat végezni, amikor az időzítő méri az időt, csak bizonyos időnként tesztelni kell a flag-et, vagy engedélyezni kell a megszakítást. ;* Knight Rider futófény két LED del megvalósítva. A program * ;* a MiniRISC mintarendszerben található hardveres időzítőt használja. * DEF LD 0x80 ; LED regiszter (írható/olvasható) DEF TM 0x8c ; Időzítő számláló regiszter (írható/olvasható) DEF TC 0x8d ; Időzítő parancs regiszter (csak írható) DEF TS 0x8d ; Időzítő státusz regiszter (csak olvasható) CODE ;* A program kezdete. A programmemória 0x00 és a 0x01 címe a reset, illetve * ;* a megszakítás vektor. Ide ugró utasításokat kell elhelyezni, amelyek a * ;* megfelelő programrészre ugranak. Ha nem használunk megszakítást, akkor a * ;* program kezdődhet a 0x00 címen is. * start: mov r0, #0xc0 ; A LED ek állapotát az r0 regiszter tárolja. mov LD, r0 ; A kezdeti állapot kiírása a LED ekre. mov r1, #0 ; A shiftelés irányát az r1 regiszter tárolja. ; 0: jobbra shiftelés, 1: balra shiftelés. ; Az időzítő beállítása kb. 0,5 s periódusidőre (2 Hz). ; 16*10^6 Hz / 65536 / 122 = 2 Hz mov r2, #121 ; A számláló regiszter értéke 121 (0x79). mov TM, r2 ; Beírás a TM időzítő regiszterbe. mov r2, #0x73 ; Az időzítő konfigurálása: 65536 os előosztás, mov TC, r2 ; ismétléses mód, időzítő engedélyezve (0111_0011). mov r2, TS ; Az időzítő esetleges TOUT jelzésének törlése. tm_loop: ; Várakozunk, amíg az időzítő nem jelez. mov r2, TS ; Beolvassuk az időzítő státusz regisztert tst r2, #0x04 ; a TOUT bit vizsgálatához. jz tm_loop ; Várakozás, ha a TOUT bit még mindig 0. cmp r1, #0 ; Megvizsgáljuk a shiftelés irányát, jz sh_right ; ugrás jobbra shiftelés esetén. sh_left: ; Ha nem ugrottunk el, akkor sl0 r0 ; balra shifteljük az r0 regisztert mov LD, r0 ; és kiírjuk az új állapotot a LED ekre. cmp r0, #0xc0 ; A shiftelés iránya marad balra (< ), ; ha még nem az LD7 és az LD6 világít, jnz tm_loop ; ezért visszaugrunk, várunk és sh_left. mov r1, #0 ; De ha már végigértünk, akkor irányváltás jmp tm_loop ; és utána folytatás (de majd jobbra léptetéssel). 10

sh_right: sr0 r0 ; Jobbra shifteljük az r0 regisztert mov LD, r0 ; és kiírjuk az új állapotot a LED ekre. cmp r0, #0x03 ; A shiftelés iránya marad jobbra ( >), ; ha még nem az LD1 és LD0 világít, jnz tm_loop ; ezért visszaugrunk, várunk és sh_right. mov r1, #1 ; De ha már végigértünk, akkor irányváltás jmp tm_loop ; és utána folytatás (de majd balra léptetéssel). TIMER használatával két folyamat fut párhuzamosan, a TIMER-es időzítés egyenletes, ezek a függőleges vonalak. Ezzel egy időben a processzor dolgozhat, ezek az U utasítások, melyek elvégzése változó ideig tarthat, csak a TIMER periódus előtt fejezze be. Azután várakozik, a várakozás hossza dinamikusan a maradék időre állítódik. TIMER felprogramozása, start, UUUUUUvvvvvvvvvvvUUUvvvvvvvvvvvvUUUUUUUvvvvvvvvUUUUvvvvvvvvvvv SZOFTVER időzítés: itt az i időzítés szubrutin ideje állandó, tehát az (u+i) időtartam lötyöghet, ha a feladat adatfüggő lenne (itt most nem, mert teljesen szimmetrikus a két feladat és a feltételes ugrás végrehajtási ideje is független a teszt eredményétől). Az alábbi példa mutatja, hogy az időzítések értéke eltérő lehet. SW időzítés végrehajtása UUUUUUiiiiiiiiiiUUUiiiiiiiiiiUUUUUUUiiiiiiiiiiUUUUiiiiiiiiii Tényleges periódusidők ;* Knight Rider futófény két LED-del megvalósítva. A program * ;* szoftveres időzítést használ. * DEF LD 0x80 ; LED regiszter (írható/olvasható) CODE ;* A program kezdete. A programmemória 0x00 és a 0x01 címe a reset, illetve * ;* a megszakítás vektor. Ide ugró utasításokat kell elhelyezni, amelyek a * ;* megfelelő programrészre ugranak. Ha nem használunk megszakítást, akkor a * ;* program kezdődhet a 0x00 címen is. * start: mov r0, #0xc0 ; A LED-ek állapotát az r0 regiszter tárolja. mov LD, r0 ; A kezdeti állapot kiírása a LED-ekre. mov r1, #0 ; A shiftelés irányát az r1 regiszter tárolja. ; 0: jobbra shiftelés, 1: balra shiftelés. main_loop: jsr sw_tmr ; A szoftveres időzítő szubrutin meghívása. cmp r1, #0 ; Megvizsgáljuk a shiftelés irányát, jz sh_right ; ugrás jobbra shiftelés esetén. sh_left: ; Ha nem ugrottunk el, akkor sl0 r0 ; balra shifteljük az r0 regisztert mov LD, r0 ; és kiírjuk az új állapotot a LED-ekre. cmp r0, #0xc0 ; A shiftelés iránya marad balra (<-), ; ha még nem az LD7 és az LD6 világít, jnz main_loop ; ezért visszaugrunk, várunk és sh_left. mov r1, #0 ; De ha már végigértünk, akkor irányváltás jmp main_loop ; és utána folytatás (de majd jobbra léptetéssel). sh_right: sr0 r0 ; Jobbra shifteljük az r0 regisztert mov LD, r0 ; és kiírjuk az új állapotot a LED-ekre. cmp r0, #0x03 ; A shiftelés iránya marad jobbra (->), ; ha még nem az LD1 és LD0 világít, jnz main_loop ; ezért visszaugrunk, várunk és sh_right. mov r1, #1 ; De ha már végigértünk, akkor irányváltás jmp main_loop ; és utána folytatás (de majd balra léptetéssel). ;* Az időzítéshez használt szubrutin, amely 0,5 s ideig várakozik. A rendszer * ;* 16 MHz-es órajelről jár, egy utasítás 3 órajelciklus alatt hajtódik végre. * ;* A ciklusból való kilépéshez a Carry flag értékét célszerű tesztelni, amely * ;* a -1 érték esetén lesz először 1. Ez kevesebb utasítást igényel, mint a * ;* ciklusváltozó 0 értékének tesztelése. A ciklusválzozó kezdeti értékének * ;* meghatározásakor figyelembe kell venni a ciklusváltozó inicializálását és * ;* a szubrutinból való visszatérést (ret utasítás) is. * 11

;* * ;* Ennek megfelelően a ciklusváltozó kezdeti értéke: * ;* ((16*10^6 Hz * 0,5 s / 3) - 3-1) / 4-2 = 666664 (0x0a2c28 -> 24 bit) * sw_tmr: mov r4, #0x28 ; A 24 bites ciklusváltozó kezdeti értékének mov r5, #0x2c ; beállítása (3 utasítás). r4 az LSB, r6 az MSB. mov r6, #0x0a tmr_loop: ; Az időzítési ciklus kezdete (1 iteráció: 4 utasítás). sub r4, #1 ; Csökkentjük a 24 bites ciklusváltozót. A ciklusból sbc r5, #0 ; akkor lépünk ki, ha elértül a -1 értéket, a Carry sbc r6, #0 ; flag ekkor lesz először 1. jnc tmr_loop ; Ha nincs átvitel, akkor vissza a ciklus elejére. rts ; Visszatérés a hívóhoz (1 utasítás). EXTRA FELADAT 5.7. Tervezzen egy fényerőszabályozó egységet a LED-ek meghajtására. Az áramkör alapvetően a 3. gyakorlaton a 3.6 példában megismert pulzusszélesség modulátor áramkörhöz hasonló. A fényerő két nyomógombbal állítható. Az egyik gomb a nagyobb, a másik a kisebb értékek irányába változtatja a fényerőt, 0% és 100% értékek között. A LED fényerőszabályozó egy egyszerű PWM (pulzusszélesség) vezérlő modul. A könnyű szabályozhatóság érdekében a sebességet lecsökkentettük, így a változás hatása a 20ms-os lépésidőzítésnek köszönhetően jól látható. A clk_div_tc egy 1 órajel széles engedélyező pulzus. A dimmer_control modul állítja be a 0 és 255 közötti fényesség értékeket, azaz jobb. mint fél % felbontással szabályozható. A 8 bites számláló szétválasztott irányvezérléssel rendelkezik, a végértékeknél szaturálódik, azaz nem nő vagy csökken tovább. Ha mindkét nyomógomb aktív, akkor értékét nem változtatja. 12

A PWM egy szabadon futó számláló, melynek értékét a dim_cnt értékével hasonlítjuk össze. Amíg a dim_cnt > pwm_cnt, addig a pwm_out jel aktív, egyébként kikapcsol. Így RESET után a LED-ek kikapcsolt állapotból indulnak. //* A LED-ek kitöltési tényezőjét meghatározó 8 bites számláló. * //* A számlálót az órajel osztó engedélyezi. Ha csak a BTN0 van megnyomva, * //* akkor növeljük a számláló értékét, ekkor növekszik a LED-ek fényereje. * //* Ha csak a BTN1 van megnyomva, akkor csökkentjük a számláló értékét, ekkor * //* csökken a LED-ek fényereje. Ha a számláló elérte a végállapotát, akkor az * //* állapotát nem módosítjuk. Reset hatására kikapcsoljuk a LED-eket. * module dimmer_control( input wire clk16m, //16 MHz órajel input wire rstbt, //Reset jel input wire clk_div_tc, //Ütemező jel input wire up, //Fényerő növelése input wire dwn, //Fényerő csökkentése output reg [7:0] dim_cnt //Fényerő érték ); //* A LED-ek kitöltési tényezőjét meghatározó 8 bites számláló. * //* A számlálót az órajel osztó engedélyezi. Ha csak az UP aktív, akkor * //* növeljük a számláló értékét, ekkor növekszik a fényerő. Ha csak a DWN * //* aktív, akkor csökkentjük a számláló értékét, ekkor csökken a fényerő. * //* Ha a számláló elérte a végállapotát, akkor az állapotát nem módosítjuk. * //* Reset hatására a fényerő nulla. * always @(posedge clk16m) begin if (rstbt) dim_cnt <= 8'd0; //Reset if (clk_div_tc) if ((up) && (!dwn) && (dim_cnt!= 8'd255)) dim_cnt <= dim_cnt + 8'd1; //Felfele számlálás if ((dwn) && (!up) && (dim_cnt!= 8'd0)) dim_cnt <= dim_cnt - 8'd1; //Lefele számlálás end endmodule 13

//* Impulzusszélesség modulátor egység. * //* Nyolcbites számláló, amely értékét összehasonlítjuk a kitöltési tényezőt * //* meghatározó jellel. * module pwm( input wire clk16m, //16 MHz órajel input wire rstbt, //Reset jel input wire [7:0] dim_cnt, //Fényerő output wire pwm_out //Pulzusszélesség modulált kimenet ); //* 16 MHz-es órajelről járó 8 bites számláló. * //* A LED-eket bekapcsoljuk, ha a kitöltési tényező számláló értéke nagyobb * //* ennek a számlálónak az értékénél. * reg [7:0] pwm_cnt; always @(posedge clk16m) begin if (rstbt) pwm_cnt <= 8'd0; pwm_cnt <= pwm_cnt + 8'd1; end //A pulzusszélesség modulált jel előállítása assign pwm_out = (dim_cnt > pwm_cnt); endmodule A terv moduljait a clk_div_20ms.v, a dimmer_control.v és a pwm.v Verilog fájlok tartalmazzák. A működés a led_dimmer_top.bit fájl használatával bemutatható. 5.8. Készítse el a LED fényerőszabályozó programot a MiniRISC vezérlőre, assembly nyelven! A fényerő növelése a BTN1-es gombbal, a fényerő csökkentése a BTN0-s gombbal történjen. Ez a legbonyolultabb, a HW verzió is itt használ a legtöbb erőforrást. Itt már érdemes egy folyamatábrát rajzolni a működésről. Felhívjuk a figyelmet az időzítő használatának jelentőségére ebben az esetben. Itt a SW időzítés nem lenne jó, mert akkor a kimeneti pwm_out jel folyamatos működtetése nem lenne lehetséges. Ez a program két párhuzamosan futó szálat tartalmaz. A pwm_out jel folyamatos generálása (kisebb jitterrel), és az időzítés figyelése, TOUT esetén gombnyomás kezelése. Tehát a nyomógombokkal beállítunk valamilyen kívánt intenzitás értéket és (ez van az r0 regiszterben) és az r1 regisztert állandóan inkrementáljuk, ami egy idő után természetesen túlcsordul és átfordul, ezzel tehát generálunk egy numerikus fűrészjelet (rajzoljuk fel, ha a 3. gyakorlaton nem szerepelt volna). Eközben folyamatosan hasonlítjuk az r0-hoz. A teszt eredménye alapján történik a LED-ek ki és bekapcsolása, valójában ki-ki-ki-ki-be-be-be-be-be formában, azaz sok felesleges periféria művelet végrehajtásával történik, de így egyszerűbb, nem kell vizsgálni, hogy vajon már be van-e kapcsolva, ha esetleg éppen be kell kapcsolni. Minden LED periféria művelet után ellenőrizzük az időzítést. Ha nem telt le, újból a LED-ekkel foglalkozunk. Ha letelt, akkor ellenőrizzük a bemeneti MMI (Man-Machine Interface), azaz a két nyomógomb aktuális állapotát és a megfelelő irányba módosítjuk a regiszter értékét. Mi történik, ha mindkét gomb egyidejűleg aktív? ;* LED Fényerőszabályozó (Dimmer). * DEF LD 0x80 ; LED regiszter (írható/olvasható) DEF BT 0x82 ; Nyomógomb regiszter (csak olvasható) DEF TM 0x8c ; Időzítő számláló regiszter (írható/olvasható) DEF TC 0x8d ; Időzítő parancs regiszter (csak írható) DEF TS 0x8d ; Időzítő státusz regiszter (csak olvasható) CODE ;* A program kezdete. A programmemória 0x00 és a 0x01 címe a reset, illetve * 14

;* a megszakítás vektor. Ide ugró utasításokat kell elhelyezni, amelyek a * ;* megfelelő programrészre ugranak. Ha nem használunk megszakítást, akkor a * ;* program kezdődhet a 0x00 címen is. * start: ; A TIMER periféria felprogramozása ; Az időzítő beállítása kb. 50 Hz-re a gombok állapotának ; vizsgálatához. 16*10^6 Hz / 16384 / 19 = 51.4 Hz mov r0, #18 ; A számláló regiszter értéke 18 (0x12). mov TM, r0 mov r0, #0x63 ; Az időzítő konfigurálása: 16384-es előosztás, mov TC, r0 ; ismétléses mód, időzítő engedélyezve (0110_0011). mov r0, TS ; Az időzítő esetleges TOUT jelzésének törlése. ; A változók inicializálása. mov r0, #0 ; A kitöltési tényező kezdetben 0. mov r1, #0 ; A PWM számláló kezdetben 0. chk_tm: ; Megvizsgáljuk az időzítő jelzését. mov r2, TS ; Beolvassuk az időzítő státusz regisztert. tst r2, #0x04 ; A TOUT bit vizsgálata. jz dc_nc ; Ugrás, ha még nem járt le az időzítő. mov r2, BT ; Beolvassuk a nyomógombokat állapotát. and r2, #0x03 ; Csak a BT1 és a BT0 érdekes, maszkoljuk őket. cmp r2, #0x01 ; BT0 -> a kitöltési tényező növelése jz dc_inc ; Ha aktív, akkor ugrás kit. tény. növelésre. cmp r2, #0x02 ; BT1 -> a kitöltési tényező csökkentése. jz dc_dec ; Ha aktív, akkor ugrás kit. tény. csökkentésre. jmp dc_nc dc_inc: ; Növeljük a kitöltési tényezőt, ha értéke < 255. cmp r0, #255 ; Ellenőrzés < 255 jz dc_nc ; Inkrementálás kihagyása, ha nem add r0, #1 jmp dc_nc dc_dec: ; Csökkentjük a kitöltési tényezőt, ha értéke > 0. cmp r0, #0 jz dc_nc sub r0, #1 dc_nc: ; A kimeneti a PWM jel előállítása mov r2, r1 ; A PWM számlálóból (r1) kivonjuk a kitöltési sub r2, r0 ; tényezőt értékét (r0). Ha r0 < r1, akkor CARRY=1. jc leds_on ; A LED-eket bekapcsoljuk, ha r0 < r1. leds_off: ; Kikapcsoljuk a LED-eket és növeljük a PWM számlálót. mov r2, #0x00 mov LD, r2 add r1, #1 jmp chk_tm ; Ugrás az időzítő vizsgálatához. leds_on: ; Bekapcsoljuk a LED-eket és növeljük a PWM számlálót. mov r2, #0xff mov LD, r2 add r1, #1 jmp chk_tm ; Ugrás az időzítő vizsgálatához. 15