Leporolni a tudást

     Egyszer régen, amikor még sok sok szabadidőm volt, elkészítettem pár bonyolultabb programot, gondolván a jövőmre is. Ezeknek fogtam neki ujból, kicsit nézzem át őket. Volt ott osztott memória kezelés, mailbox és mutex. Ezekkel azért jó tisztában lenni, hogy a legjobb megoldást válasszuk egy komplexebb projekt esetén.

     Abból az alapfeltevésből indulunk ki, hogy van egy dualcore-os procink, amelyikben a processzorok szeretnének egymással és a külvilággal kommunikálni. Egymással elég könnyen tudnak. Deklarálunk egy osztott memória részt, amihez mindkét proci hozzáfér, oda beírják a gondjaikat, a másik proci meg kiolvassa. Itt szembesülünk először az ütemezési problémával, vagyis azzal, hogy melyik proci mikor ír és mikor olvas arról a közös memóriáról, illetve honnan tudja, hogy a másik proci már feldolgozta-e az ott lévő adatot, vagy sem. Ez egy nagyon komoly hátrány. Viszont megvan az az előnye, hogy nagyon könnyű kezelni. Még egy ovodás gyerek is (pár perces magyarázat után) meg tudja érteni, hogyan is működik.


     A következő lépés a boldogság felé vezető úton a mailbox lehetne, ami arra jó, hogy a processzorok üzeneteket küldözgessenek egymásnak. Legelső lépés inicializálni a mailboxot:

    XMbox mbox;
    XMbox_Config *cfg;
    cfg = XMbox_LookupConfig (XPAR_MAILBOX_0_IF_0_DEVICE_ID);
    status = XMbox_CfgInitialize (&mbox, cfg, cfg->BaseAddress);

     Itt megvizsgáljuk a status változó értékét, ami ha XST_SUCCESS, akkor sikeresen inicializáltuk a mailboxot, ha valami egyéb, akkor meg nem. Ezután következet az üzenet küldés, ami lehet blokkolásos, illetve nem blokkolásos. A kettő között az a különbség, hogy a blokkolásos üzemmódban az egyik proci addig vár, amíg a másik nem fogadja az ő üzenetét.

     Ezt postással és levéllel úgy lehetne elmagyarázni, hogy jön a postás, és nincs postaláda. Ennek következtében a postás kénytelen addig várni a kapu előtt, amig én ki nem megyek, hogy elvegyem tőle a levelet. Viszont ha én épp mással vagyok elfoglalva (annak fontosságától függetlenül), akkor lehet, hogy a postás sokáig fog várni, amig én kimegyek. Viszont ugyanez van fordítva is. Ha én akarok levelet feladni, akkor addig kell várjak a levéllel a kapu előtt, amíg arra nem jár a postás és elveszi tőlem. Ez akkor jó, ha bizonyos folyamatokat szinkronizálni kell, mivel ebből a blokkolásos üzemmódból csak akkor lépnek tovább, ha az üzenetcsere megtörtént. Tanultuk ezt anno Operációs Rendszerekből.

     A másik üzenetküldési forma (ahogy azt már sejteni lehetett) a nem blokkolásos üzenetküldés. Ilyenkor jön a postás, bedobja a levelet a postaládába, majd továbbmegy. Amikor időm és kedvem lesz, majd kimegyek és ürítem a postaládát (egyenesen a kukába).

     A teljes projekt a következőképpen néz ki :

     Első processzor :

#include <string.h>
#include <xstatus.h>
#include <xparameters.h>
#include <xmbox.h>

#include <mb_interface.h>
#include <stdio.h>
#include "xutil.h"

#define MSGSIZ  1024
const char *role = "CPU0";

char data[];

float   conv_cycles_to_secs (u32 cycles);

u32 *sendmsg = (u32*) data;
u32  recvmsg[MSGSIZ/sizeof(u32)];
char *hello  = "HELO";

int main (void) 
{
    

    XMbox mbox;
    XMbox_Config *cfg;
    int status, i;
    u32 rcvd, sent, nbytes, ts;

    xil_printf ("--------------------------------------------------------------------\r\n");
    xil_printf ("---------------Dual Processor Producer Consumer Demo!---------------\r\n");
    xil_printf ("--------------------------------------------------------------------\r\n");
    xil_printf ("------- CPU0 sends data packets to CPU1 via an XPS Mailbox.---------\r\n");
    xil_printf ("--------------------------------------------------------------------\r\n");

    xil_printf ("(%s)\t: Starts.\r\n", role);
    xil_printf ("(%s)\t: Initializing the mailbox...", role);

    cfg = XMbox_LookupConfig (XPAR_MAILBOX_0_IF_0_DEVICE_ID);

    status = XMbox_CfgInitialize (&mbox, cfg, cfg->BaseAddress);
    if (status != XST_SUCCESS) {
        xil_printf ("failed!\r\n");
        return status;
    }

    xil_printf ("done!\r\n");

    /* First both processors rendezvous with each other. 
       They do this by exchanging HELO messages */

    /* Send the hello */
    xil_printf ("(%s)\t: Sending a HELO.\r\n", role);
    XMbox_WriteBlocking (&mbox, (u32*)hello, 4);
    xil_printf ("(%s)\t: Awaiting a HELO...", role);
    while (1) {
        XMbox_ReadBlocking (&mbox, recvmsg, 4);
        if (memcmp (hello, recvmsg, 4) == 0) 
            break;
    }
    xil_printf ("Got it!\r\n");

    /* Now exchange the data */
    for (i = 0; i < 5; i++) {

        xil_printf ("\r\n");
        xil_printf ("(%s)\t: Sending data packet (%d) -->\r\n", role, i);
        while (nbytes != MSGSIZ) {
            /* Write a message to the mbox */
            status = XMbox_Write (&mbox, sendmsg + (nbytes/sizeof(u32)), 
                                  MSGSIZ - nbytes, &sent);
            if (status != XST_FIFO_NO_ROOM)        
                nbytes += sent;
        }              
        xil_printf ("(%s)\t: Successfully sent %d bytes .\r\n", 
                role, MSGSIZ);
    }

    xil_printf ("(%s)\t: End of Demo.\r\n", role);
    xil_printf ("--------------------------------------------------------------------\r\n");
    return XST_SUCCESS;

}


     Második processzor :

#include <string.h>
#include <xstatus.h>
#include <xparameters.h>
#include <xmbox.h>
#include <mb_interface.h>
#include <stdio.h>

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

#define MSGSIZ  1024


const char *role = "CPU1";

char data[];

u32 *sendmsg = (u32*) data;
u32  recvmsg[MSGSIZ/sizeof(u32)];
char *hello  = "HELO";

int main ()
{
    XMbox mbox;
    XMbox_Config *cfg;
    int status, i;
    u32 rcvd, sent, nbytes, ts;

//    xil_printf ("--------------------------------------------------------------------\r\n");
//    xil_printf ("Dual Processor Producer Consumer Demo!\r\n", role);
//    xil_printf ("--------------------------------------------------------------------\r\n");
//    xil_printf ("Desc -- CPU0 sends data packets to CPU1 via an XPS Mailbox.\r\n");
//    xil_printf ("--------------------------------------------------------------------\r\n");
//
//    xil_printf ("(%s)\t: Starts.\r\n", role);
//    xil_printf ("(%s)\t: Initializing the mailbox...", role);

    cfg = XMbox_LookupConfig (XPAR_MAILBOX_0_IF_1_DEVICE_ID);

    status = XMbox_CfgInitialize (&mbox, cfg, cfg->BaseAddress);
    if (status != XST_SUCCESS) {
//        xil_printf ("failed!\r\n");
        return status;
    }

//    xil_printf ("done!\r\n");

    /* First both processors rendezvous with each other. 
       They do this by exchanging HELO messages */

//    xil_printf ("(%s)\t: Awaiting a HELO...", role);
    while (1) {
        /* Try to recv a hello */
        XMbox_ReadBlocking (&mbox, recvmsg, 4);
        if (memcmp (hello, recvmsg, 4) == 0) 
            break;
    }
//    xil_printf ("Got it!\r\n");
    
    /* Send back a hello */
//    xil_printf ("(%s)\t: Sending back a HELO.\r\n", role);
    XMbox_WriteBlocking (&mbox, (u32*)hello, 4);

    /* Now exchange the data */
    for (i = 0; i < 5; i++) {

//        xil_printf ("\r\n");
//        xil_printf ("(%s)\t: Receiving data packet (%d) -->\r\n", role, i);
        nbytes = 0;
        while (nbytes != MSGSIZ) {
            /* Read a message from the mbox */
            status = XMbox_Read (&mbox, recvmsg + (nbytes/sizeof(u32)), 
                                 MSGSIZ - nbytes, &rcvd);
            if (status != XST_NO_DATA)
                nbytes += rcvd;
        }

//        xil_printf ("(%s)\t: Successfully rcvd %d bytes.\r\n", 
//                role, MSGSIZ);
        
        if (memcmp (recvmsg, data, MSGSIZ)) {
//            xil_printf ("(%s)\t: Error! Rcvd data does not match expected.\r\n", 
//                    role);
            return XST_FAILURE;
        }
 //       else
//            xil_printf ("(%s)\t: Success! Rcvd data does match expected.\r\n", 
//                    role);        
    }

//    xil_printf ("(%s)\t: End of Demo.\r\n", role);
//    xil_printf ("--------------------------------------------------------------------\r\n");
    return XST_SUCCESS; 
}


     Itt fontos megjegyezni, hogy a második processzorban a kiíratások mind ki vannak kommentelve, mivel a soros kommunikációs egységhez való hozzáférés még nincs implementálva. Oda kell majd a mutex, ami arra lesz jó, hogy mindkét proci hozzáférjen a soros eszközhöz anélkül, hogy egymást zavarnák. Ezen kívül azt is fontos megjegyezni, hogy a program nem az én kretivitásom terméke. Sajnos az eredetire mutató linkem már nincs.

     A mutex példát majd a következő bejegyzésben.

0 megjegyzés:

Megjegyzés küldése

Return top