SysCVideo: fiktív grafikus kártya SystemC modulként, SDL alapú megjelenítéssel Czirkos Zoltán 2015. augusztus 26. Kivonat Az ismertetett SystemC modul egy mikroprocesszoros rendszerhez illeszthető megjelenítő perifériaként működik szimulációban. 40×25-ös szöveges és ugyanekkora felbontású grafikus módot támogat (tetrishez, kukacos játékhoz ez épp elég.) Egy mikroprocesszoros rendszerhez könnyen illeszthető: 12 bites címbusszal, 8 bites adatbusszal rendelkezik, és a szokásos chip select, read enable, write enable és reset bemenetekkel. A megjelenítéshez az SDL grafikus könyvtárat használja. A modul a billentyűzet kezelését is segíti: az egyes billentyűk lenyomott állapota ellenőrizhető, illetve a gépelt szöveg pufferelődik, és karakterenként visszaolvasható. A modul használható önállóan is, függvényhívásokon keresztül.
1. Bevezetés A bemutatott SystemC modul arra való, hogy egy szimulált mikroprocesszoros rendszer perifériájaként működjön, lehetővé téve azt, hogy videókimenetet produkáljon a rendszer a szimuláció közben. Nem egy valós, létező perifériát utánoz, hanem kitalált vezérléssel rendelkezik. Szintetizálni nem lehet. A modul a következő képességekkel rendelkezik: • 40×25-ös szöveges képernyő, amely 256 beépített karakterrel rendelkezik, és a VGA kártyákról ismert az IBM437-es kódlapot használja. Fehér alapon fekete betűkkel rajzol. • A szöveges képernyő tartalma bájtonként elérhető, írható és olvasható. • Kurzor is használható, amelynek pozíciója tetszőlegesen írható és olvasható. • A szöveges képernyőre szöveg folytonosan, bájtonként írható. Ebben a módban a modul a kurzor pozícióját automatikusan változtatja, és görgeti is a képernyőt, ha az elérte annak alját.
1
1. ábra. Képernyőkép egy futó programról
• A 40×25-ös grafikus képernyő mérete megegyezik a szöveges képernyőével. A nagyított pixelek 256 különböző színnel rendelkezhetnek, amelyek a VGA palettát használják. • A modul néhány paranccsal is rendelkezik (pl. képernyőtörlés.) • A billentyűk lenyomva tartott állapota egyesével lekérdezhető. • Rendelkezik továbbá egy karakter pufferrel, amelybe a lenyomott billentyűk kerülnek. Innen a lenyomott billentyűk kódjai egyesével visszaolvashatóak. • A kártya a szimulációs idő szerinti 20 ms-onként, azaz szimulációs időbeli másodpercenként 50-szer rajzolja ki a képet.
2. A kártya illesztése A kártya vezérlő jelei a 2. ábrán láthatóak. Az egyes jelek magyarázata a következő: ADDRESS Címbusz, 12 bites bemenet. DATA Adatbusz, 8 bites ki- és bemenet. CSNEG Chip select bemenet, amellyel íráskor és olvasáskor a chip engedélyezhető. Aktív L szintű ez is. READNEG Read bemenet, olvasás engedélyezése. Ennek aktív szintjével a kártya regiszterei és memóriája olvashatók. WRITENEG Chip select bemenet, aktív L szinttel. Engedélyezésével a regiszterek és memória írhatóak. A kártya 12 bites címtartománnyal rendelkezik, azaz 4096 címezhető regisztere van. Illesztésére példát a 2. ábra mutat.
2
SysCVideo
ADDRESS[0..11] DATA[0..7]
CSNEG READNEG WRITENEG
2. ábra. A periféria vezérlő jelei
CPU
SysCVideo
DATA[0..7] ADDRESS[0..15]
DATA[0..7] ADDRESS[0..11] A[12..15]
CSNEG READNEG WRITENEG
READNEG WRITENEG
3. ábra. A periféria illesztése az 0xE000-0xEFFF címre. A SystemC programban a modult nem feltétlenül szükséges ilyen módon illeszteni; a regiszterir() és a regiszterolvas() metódusain keresztül közvetlenül is vezérelhető.
3
2.1. Reset jel A reset jel hatására szöveges módba vált az eszköz. Más inicializáció nem történik, és egyébként ez is elhagyható. Ha a jel aktív, akkor más jeleknek nincsen hatása.
2.2. Regiszter írása portműveletekkel Regiszterek írásához ezeket a lépéseket kell tenni: 1. A címbuszra kell tenni a kiválasztott regiszter vagy memóriaterület címét. 2. Engedélyezni, vagyis L szintbe kell állítani a chip select (CSNEG) jelet. (Ez általában a perifériaillesztés módja miatt automatikusan megtörténik.) 3. Az adatbuszra kell tenni az írandó értéket. 4. Engedélyezni kell a write enable (WRITENEG) jelet. A regiszterbe írás a WRITENEG jel lefutó élére történik meg. Ilyenkorra a CSNEG jelnek már aktívvá kell válnia, vagyis a két lefutás nem történhet időben egyszerre. Ezek után a vezérlőjelek visszavehetőek, és a buszokra tett értékekre már nincsen szükség. Például a 0x400 címre az 57 érték a következő SystemC kódrészlettel írható: a d d r e s s . w r i t e ( 0 x400 ) ; csneg . w r i t e ( 0 ) ; data . w r i t e ( 5 7 ) ; s c _ s t a r t ( 1 , SC_NS ) ; writeneg . w r i t e ( 0 ) ; s c _ s t a r t ( 1 , SC_NS ) ; writeneg . w r i t e ( 1 ) ; csneg . w r i t e ( 1 ) ; s c _ s t a r t ( 1 , SC_NS ) ;
// chip s e l e c t = a k t i v
// w r i t e enable a k t i v // w r i t e enable i n a k t i v
2.3. Regiszter olvasása portműveletekkel Az olvasás lépései: 1. A címbuszra kell tenni a kiválasztott regiszter vagy memóriaterület címét. 2. Engedélyezni kell a chip select (CSNEG) jelet. 3. Engedélyezni kell a read enable (READNEG) jelet, a CSNEG után nem nulla idővel. Amíg a READNEG jel aktív, a regiszterből kapott érték olvasható. Itt is figyelni kell arra, hogy a CSNEG és a READNEG aktívvá válása között kell valamekkora időnek eltelnie. Példaként a 0x400 cím olvasása:
4
a d d r e s s . w r i t e ( 0 x400 ) ; csneg . w r i t e ( 0 ) ; // chip s e l e c t = a k t i v s c _ s t a r t ( 1 , SC_NS ) ; readneg . w r i t e ( 0 ) ; // read enable s c _ s t a r t ( 1 , SC_NS ) ; s t d : : cout << data . read ( ) . t o _ u i n t ( ) ; // kepernyore readneg . w r i t e ( 1 ) ; s c _ s t a r t ( 1 , SC_NS ) ; csneg . w r i t e ( 1 ) ;
3. A kártya illesztés nélküli használata A modul használható önállóan is, szignálók bekötése nélkül. Ebben az esetben a SysCVideoStandalone osztályt kell használni, és a perifériaillesztési művelet teljes egészében elhagyható. A kommunikáció a regiszterir() és regiszterolvas() függvények segítségével működik: i n t sc_main ( i n t argc , char * argv [ ] ) { SysCVideoStandalone s c v s ; s c v s . r e g i s z t e r i r ( SysCVideo : : ParancsRegCim , 0 ) ; /* s z ö veges mód s e t */ /* . . . */ } A SystemC-t ebben az esetben is a programhoz kell linkelni, de semmi teendő nincsen vele, mindent elintéz a SysCVideoStandalone osztály.
4. A regiszterek címei és használatuk A regiszterek címei a 4. táblázatban láthatóak. Használatuk: Parancs regiszter. Az ide írt bájtok parancsokként működnek, amelyeket a modul végrehajt. Ez a regiszter nem olvasható. Kurzor regiszterek. A kurzor pozíciója állítható be vagy olvasható vissza ezeken keresztül. Lehetséges értékeik X=0. . . 39 és Y=0. . . 24; a (0; 0) pont a bal felső sarokban van. Karakter írás regiszter. Az ide írt karaktereket a modul az aktuális kurzorpozícióba írja, és a pozíciót balra, illetve szükség esetén lefelé növeli (mint egy C-s printf.) A képernyő aljára érve a görgetés is automatikusan történik. Az egyetlen értelmezett karakter a 10-es kódú sörtörés (C-ben ’\n’), amelynek hatására a modul új sort kezd.
5
cím
név a kódban
regiszter
olv./írh.
0x000 0x001 0x002 0x003 0x004 0x005 0x100-0x128 0x400-0x7E8 0x800-0xBE8
ParancsRegCim KurzorXRegCim KurzorYRegCim KarakterIrCim BillentyuPufCim BillentyuPuf256Cim BillentyuMatrCim SzovegesCim GrafikusCim
parancs regiszter kurzor x pozíció kurzor y pozíció karakter írás regiszter billentyűzet puffer LSB billentyűzet puffer MSB billentyű nyomvatartás szöveges memória grafikus memória
R R/W R/W W R R R R/W R/W
1. táblázat. A regiszterek címei
4. ábra. Az IBM 437-es kódtábla és a VGA paletta
6
Billentyűzet puffer. Az LSB-t olvasva a billentyűzet pufferben eltárolt következő karaktert kapjuk meg. Ha nem volt lenyomott karakter, akkor 0-t ad a regiszter. A billentyűk kódolása az SDL keysym-eknek megfelelő – ez Linux rendszereken általában az /usr/include/SDL/SDL_keysym.h fájlban megtalálható, de a legtöbb kód úgy van megválasztva, hogy az ASCII kódoláshoz illeszkedjen. Mivel a vezérlőgombok (nyilak stb.) kódolása 255 feletti értékeket is használ, azok nem férnek el egy bájtban: az LSB regiszter olvasása után a felső bitek az MSB regiszterbe kerülnek, és onnan olvashatóak ki. Billentyű nyomvatartás. A 40 bájtos memóriaterület bitjei az egyes billentyűk lenyomva tartott állapotát mutatják, ahol 1-es bit jelenti a nyomva tartott gombot. Egy adott gombhoz a KEYSYM/8. bájt KEYSYM%8. bitje tartozik, pl. az A billentyűhöz tartozó SDLK_a kódja 93, így a 11. bájt alulról 5. bitje tárolja a hozzá tartozó állapotot. Szöveges memória. A karakteres képernyőn tárolt jelek kódjai, a a 4. ábrának megfelelően. Grafikus memória. A grafikus memória pixeljei a 4. ábra színeinek megfelelően.
4.1. A parancsregiszter A 0x000 (ParancsRegCim) című regiszterbe írt bájtokkal különféle parancsok adhatók az eszköznek: 0 Váltás szöveges módba. 1 Váltás grafikus módba. 2 A szöveges képernyő törlése (szóközökkel feltöltése). 3 A kurzor bal felső sarokba állítása, a (0; 0) koordinátába. 4 Grafikus képernyő törlése (feketével feltöltése).
4.2. Szöveg kiírása: helló világ Az alábbi, hosszabb példában egy szöveget írunk ki a képernyőre, a bal felső sarokba. A szöveg kiírása a karakter író regiszteren keresztül történik, így nincsen szükség a képernyő koordináták számítására. A regiszter minden egyes írásakor egy új karakter jelenik meg a képernyőn. csneg . w r i t e ( 0 ) ; // c r s r home parancs a d d r e s s . w r i t e ( SysCVideo : : ParancsRegCim ) ; data . w r i t e ( 3 ) ; s c _ s t a r t ( 1 , SC_NS ) ;
7
writeneg . w r i t e ( 0 ) ; s c _ s t a r t ( 1 , SC_NS ) ; writeneg . w r i t e ( 1 ) ; s c _ s t a r t ( 1 , SC_NS ) ; char const * s t r =" Hello v i l a g ! \ nEz egy u j s o r . " ; f o r ( i n t i =0; s t r [ i ] ! = 0 ; ++ i ) { a d d r e s s . w r i t e ( SysCVideo : : KarakterIrCim ) ; data . w r i t e ( s t r [ i ] ) ; writeneg . w r i t e ( 0 ) ; s c _ s t a r t ( 1 , SC_NS ) ; writeneg . w r i t e ( 1 ) ; s c _ s t a r t ( 1 , SC_NS ) ; }
4.3. Regiszter írása és olvasása metódushívással A regisztereket nem feltétlenül kell portműveleteken keresztül elérni. Ha nem szükséges ilyen alacsony szintű modell, akkor a SyscVideo modul regiszterir() és regiszterolvas() tagfüggvényei közvetlenül is hívhatóak: SC_MODULE( SysCVideo ) { unsigned char r e g i s z t e r o l v a s ( unsigned a d d r e s s ) ; void r e g i s z t e r i r ( unsigned address , unsigned char data ) ; }; SysCVideo video ( " video " ) ; video . r e g i s z t e r i r ( 0 x004 , 0x12 ) ; Arra figyelni kell, hogy hasonlóan ahhoz, mint amikor portműveletekkel ér el adatot a processzor, ezek a metódushívások sem idempotensek. Több egymás utáni írás vagy olvasás más eredményt adhat, pl. a karaktert író vagy a billentyűt olvasó parancsregiszter esetén.
8