Microblaze Mutex

     Mai bejegyzés témája a közös hozzáférés a perifériákhoz. Valós szituáció : adott két ember és adott egy darab telefon. A telefon bent van egy szobában. Mindketten akarnak telefonálni időnként. Lehet, hogy egyszerre, lehet hogy időben távol egymástól. Ennek szinkronizálásan nem nehéz emberek esetében. Simán megkérdezi, az egyik, hogy mikor akarja használni a másik, s beosztják az időt. Vagy mikor eszükbe jut, mennek, s megnézik, hogy foglalt a telefon vagy nem. Ha foglalt, akkor később újrapróbálkoznak, ha meg nem foglalt, akkor lehet dumálni rajta.

     Ugyanígy kell elképzelni a MicroBlaze procikat is. Ketten akarják a soros portot használni, de lehetőleg úgy, hogy ne zavarják egymást közben, vagyis ne tudja megszakítani az egyik a másik beszélgetését. Erre találták ki a mutexet. Ez olyan, mint a zár az ajtón. Ha bementem, bezárom magam mögött az ajtót, ha végeztem, akkor kizárom, s kijövök. Ha megyek, s látom, hogy be van zárva, akkor újrapróbálkozom később. Röviden ennyi.

      Program elkészítésének lépései : Legelőször kell egy kétmagos projekt. Ennek elkészítése nem képezi szerves részét ennek a leírásnak. Ha az megvan, hozzáadunk az egyik processzorhoz egy soros kommunikációs eszközt, majd egy PLBBridge-t. Ez a bridge - magyarul híd, ahogy a neve is mutatja, kapcsolatot teremt a két processzor PLB buszrendszere között. A buszrendszerről annyit kell tudni, hogy ezen keresztül kommunikál a processzor a hozzá rendelt perifériákkal, úgy, hogy megcímezi őket, aztán a cím után küldi a megfelelő adatot. Ha a buszon van valaki, akinek ugyanaz a címe, akkor az értelmezi az adatokat és válaszol, vagy esetenként elvégez (vagy nem végez el) valamit. Ha a buszra olyan adat-utasítás páros kerül, amelyiknek a címe nem mutat egyezést egyik buszon lévő perifériával sem, akkor vagy hiba keletkezik, vagy csak simán elvész az adat.

     Ebből a szempontból elég jól meg van tervezve az XPS fejlesztőkörnyezet, mert akármit nem is enged megcímezni. Ha biztosak akarunk lenni abban, hogy valaki magáénak érzi az általunk PLB buszra rakott adatot, akkor előtte érdemes meggyőződni arról, hogy az illető perifériának a címe szerepel az xparameters.h állományban. Ebbe az állományba gyűjti össze az XPS azoknak a perifériáknak a címeit, amikhez az illető processzornak hozzáférése van. Persze ettől függeltenül lehet vaktában is lövöldözni a PLB buszra, hátha eltalálunk valakit. Mintha feladnánk egy levelet Bukarestbe a Liszt Ferenc utca 24 szám alá Gitano Armandonak, remélve, hogy megkapja. Legrosszabb, ami történhet, hogy a levél visszajön. Viszont ha valós periféria kap meg egy nem neki szánt üzenetet, az komolyabb galibát is okozhat.

     Időközben az XPS fenyegetőzik : WARNING:Security:40 - Your license for 'SDK' expires in 3 days.

     Második lépés a mutex hozzáadása az eddigiekhez. A mutexet is rá kell kötni mindkét PLB buszra. Ha ez is megvan, és a Generate Addresses gomb megnnyomása sem halmozott el irdatlanul nagy mennyiségű hibával, akkor máris tovább léphetünk a programozásra. Viszont ha hibaüzenetünk van, azon már csak a Google segíthet.

    A program szerkezetileg ugyanúgy néz ki, mint az eddig megírt programjaink, csak újradeifiniáljuk (direkt írtam egybe) az outbyte függvényt, illetve minden xil_printf hívás előtt lock-oljuk a mutexet, majd utána unlock-oljuk. Az outbyte függvény ujradefiniálása azért fontos, hogy kényszerítsük a xil_printf-et, hogy az általunk megadott sorosporton keresztül kommunikáljon a külvilággal.

Forráskód az egyik processzorra (nálam a főprocira ) :

#include <xparameters.h>
#include <xmutex.h>
#include <xuartlite_l.h>
#include <xstatus.h>
#include <stdio.h>
#include <stdlib.h>
#include <mb_interface.h>

/************************** Constant Definitions *****************************/


#define MUTEX_NUM               0
#define SHAREDCONSOLE_BASEADDR  XPAR_RS232_PORT_BASEADDR

/**************************** Type Definitions *******************************/


/***************** Macros (Inline Functions) Definitions *********************/



/************************** Function Prototypes ******************************/

void init_lock ();
void init_hw ();
void deinit_hw ();
void MLOCK ();
void MUNLOCK ();
void outbyte (char c);

/* mutex -- Our main mutex lock */

XMutex mutex;


volatile unsigned int *sharedstate = (unsigned int *)XPAR_SHARED_BRAM_IF_CNTLR_0_TOP_BASEADDR;

/* We are either CPU1 or CPU2. 
   Code below relies on the value being one of these two */

unsigned int cpu_status[2] = { 1000, 2000 };

void udelay(unsigned int delay)
{
unsigned int j, i; 

for(i=0; i<delay; i++)
   for(j=0; j<26; j++);
}

int main ()
{
    int            i;
    unsigned int   oldstate;
    int count = 0;

    init_lock();

    xil_printf ("--------------------------------------------------------------------\r\n");
    xil_printf ("Dual Processor Synchronization Demo!\r\n");
    xil_printf ("--------------------------------------------------------------------\r\n");
    xil_printf ("Desc -- CPU0 and CPU1 will synchronize their output to this\r\n");
    xil_printf ("        console using XPS Mutex Locks.\r\n");    
    xil_printf ("--------------------------------------------------------------------\r\n");
    xil_printf ("SHAREDCONSOLE: CPU0 and CPU1 rendezvousing...");
//    fflush (stdout);
//

    /* Rendezvous first to enable co-ordinated output */

    *sharedstate = 0x1;
    while (*sharedstate != 0x0)
        ;

    while (count++ < 10) {
        
        MLOCK ();

        oldstate = *sharedstate;
        *sharedstate = cpu_status[XPAR_CPU_ID]++;
        xil_printf ("CPU(%d) -- changing shared state from %d", XPAR_CPU_ID, oldstate);
        xil_printf (" to...");
        udelay (500000);
        xil_printf ("%d.\r\n", *sharedstate);
        udelay (500000);

        MUNLOCK ();
        udelay (50000);
    }

    MLOCK ();
    xil_printf ("SHAREDCONSOLE: CPU(%d) Ends.\r\n", XPAR_CPU_ID);
    MUNLOCK ();

    while (*sharedstate != 0x0)
        ;
    xil_printf ("SHAREDCONSOLE: End of Demo!\r\n");
    xil_printf ("--------------------------------------------------------------------\r\n");

}

/* We purposefully redefine outbyte here to force output from xil_printf and xil_xil_printf 
   to go to the UART we want it to go to, rather than the configured STDOUT */

void outbyte (char c)
{
    XUartLite_SendByte(SHAREDCONSOLE_BASEADDR, c);
}

void init_lock ()
{
    XMutex_Config *cfg;
    
    cfg = XMutex_LookupConfig (XPAR_MUTEX_0_IF_0_DEVICE_ID);
    if (cfg == NULL) {
        xil_printf ("SHAREDCONSOLE: Startup error!\r\n");
        abort ();
    }
    XMutex_CfgInitialize (&mutex, cfg, cfg->BaseAddress);
}

void MLOCK ()
{
#ifndef NO_SYNC
    XMutex_Lock (&mutex, MUTEX_NUM);                    /* Acquire lock */
#endif
}

void MUNLOCK ()
{
    u32 status;
#ifndef NO_SYNC
    status = XMutex_Unlock (&mutex, MUTEX_NUM);         /* Release lock */
    if (status != XST_SUCCESS)
        abort ();
#endif
}


Forráskód a másik procira :

/***************************** Include Files *********************************/

#include <xparameters.h>
#include <xmutex.h>
#include <xuartlite_l.h>
#include <xstatus.h>
#include <stdio.h>
#include <stdlib.h>
#include <mb_interface.h>


/************************** Constant Definitions *****************************/
#define MUTEX_NUM               0
#define SHAREDCONSOLE_BASEADDR  XPAR_RS232_PORT_BASEADDR 


/**************************** Type Definitions *******************************/


/***************** Macros (Inline Functions) Definitions *********************/



/************************** Function Prototypes ******************************/

void init_lock ();
void MLOCK ();
void MUNLOCK ();
void outbyte (char c);

void udelay(unsigned int delay)
{
unsigned int j, i; 

for(i=0; i<delay; i++)
   for(j=0; j<26; j++);
}



/* mutex -- Our main mutex lock */

XMutex mutex;

volatile unsigned int *sharedstate = (unsigned int *)XPAR_SHARED_BRAM_IF_CNTLR_0_BOTTOM_BASEADDR;

unsigned int cpu_status[2] = { 1000, 2000 };

int main ()
{
    int            i;
    unsigned int   oldstate;
    int count = 0;

    init_lock();


    /* Rendezvous first to enable co-ordinated output */
    while (*sharedstate != 0x1)
        ;
    xil_printf ("done\r\n");
    *sharedstate = 0x0;

    while (count++ < 10) {
        
        MLOCK ();

        oldstate = *sharedstate;
        *sharedstate = cpu_status[XPAR_CPU_ID]++;
        xil_printf ("CPU(%d) -- changing shared state from %d", XPAR_CPU_ID, oldstate);
        xil_printf (" to...");
        udelay (500000);
        xil_printf ("%d.\r\n", *sharedstate);
        udelay (500000);

        MUNLOCK ();
        udelay (50000);
    }

    MLOCK ();
    xil_printf ("SHAREDCONSOLE: CPU(%d) Ends.\r\n", XPAR_CPU_ID);
    MUNLOCK ();

    *sharedstate = 0x0;

}

/* We purposefully redefine outbyte here to force output from xil_printf and xil_xil_printf 
   to go to the UART we want it to go to, rather than the configured STDOUT */

void outbyte (char c)
{
    XUartLite_SendByte(SHAREDCONSOLE_BASEADDR, c);
}

void init_lock ()
{
    XMutex_Config *cfg;
    
    cfg = XMutex_LookupConfig (XPAR_MUTEX_0_IF_1_DEVICE_ID);
    if (cfg == NULL) {
        xil_printf ("SHAREDCONSOLE: Startup error!\r\n");
        abort ();
    }
    XMutex_CfgInitialize (&mutex, cfg, cfg->BaseAddress);
}

void MLOCK ()
{
#ifndef NO_SYNC
    XMutex_Lock (&mutex, MUTEX_NUM);                    /* Acquire lock */
#endif
}

void MUNLOCK ()
{
    u32 status;
#ifndef NO_SYNC
    status = XMutex_Unlock (&mutex, MUTEX_NUM);         /* Release lock */
    if (status != XST_SUCCESS)
        abort ();
#endif
}


     A kódhoz sok hozzáfűznivalóm már nincs. Megkerült ennek is az eredeti helye és eredeti szerzője (mint már említettem, ezek csak "feldolgozások"...) Az eredeti leírásra mutat a következő link:
http://www.xilinx.com/support/documentation/application_notes/xapp996.pdf
     Ugyanott megtalálható az eredeti forráskódra mutató link is. Igaz, kicsit kell vele dolgozni, meg kell az a bizonyos Isteni szikra is, viszont az alap már megvan.

     Ennyi mára.

0 megjegyzés:

Megjegyzés küldése

Return top