QROC A23 Architecture des ordinateurs

Enic - épreuve du 06 avril 1999 (Christophe TOMBELLE)
2 heures - documents autorisés

I. Matériel (5 points)

Un microprocesseur possède un bus d'adresses 16 bits et un bus de données 8 bits.
Le registre IP contient la valeur 0100, le registre AX contient la valeur 3A42. Dans la mémoire de programme, on a l' instruction suivante :

Adresse         Code machine    Code assembleur
0100            A20220          MOV [2002],AL

Dans la mémoire de données on a les octets suivants :

Adresse Données                 Ascii
2000    00 00 00 00 00 00 00 00 ......

1. Mettre en évidence l'évolution des valeurs sur les bus d'adresses et de données ainsi que l'évolution des signaux de lecture et d'écriture, lors de l'exécution de cette instruction.
 

A0-A15
 

D0-D7
 

RDbarre
 

WRbarre
 

2. Chaque cycle de bus (lecture ou écriture) dure 2 périodes Th de l'horloge du microprocesseur. Sachant qu'il fonctionne à 4 MHz, calculer le temps d'exécution de cette instruction.

3. Représenter la mémoire de données après exécution de cette instruction.

Adresse Données                 Ascii
2000

4. En admettant que ce processeur continue à fonctionner à 40 MHz, des mémoires statiques de 80 ns de temps d'accès seraient-elles capables de tenir le rythme imposé par ce processeur ? Justifier la réponse.

II. Modes d'adressage et structuration des données (5 points)

En complétant le tableau suivant, indiquer l'action des instructions suivantes sur la mémoire et/ou les registres. Afin que les questions soient indépendantes, l'instruction applique son action à la situation initiale (et non à la situation laissée par l'instruction précédente)
 
Situation initiale AX=4282
BX=2000
CX=0000
DX=0000
SI=0004
DI=0002
BP=FF50
SP=FF40
Adresse Données                 Ascii
2000    00 01 02 03 04 05 06 07 ........
...
FF40 00 00 00 00 00 00 00 00 ........
FF48 00 00 00 00 00 00 00 00 ........
FF50 00 00 00 00 00 00 00 00 ........
MOV BX,CX AX=
BX=
CX=
DX=
SI=
DI=
BP=
SP=
Adresse Données                 Ascii
2000    ........
...
FF40    ........
FF48    ........
FF50    ........
MOV [BX],AH AX=
BX=
CX=
DX=
SI=
DI=
BP=
SP=
Adresse Données                 Ascii
2000    ........
...
FF40    ........
FF48    ........
FF50    ........
MOV [2000],CX AX=
BX=
CX=
DX=
SI=
DI=
BP=
SP=
Adresse Données                 Ascii
2000    ........
...
FF40    ........
FF48    ........
FF50    ........
MOV CX,2000 AX=
BX=
CX=
DX=
SI=
DI=
BP=
SP=
Adresse Données                 Ascii
2000    ........
...
FF40    ........
FF48    ........
FF50    ........
MOV BP,SP AX=
BX=
CX=
DX=
SI=
DI=
BP=
SP=
Adresse Données                 Ascii
2000    ........
...
FF40    ........
FF48    ........
FF50    ........
MOV [BP-2],BP AX=
BX=
CX=
DX=
SI=
DI=
BP=
SP=
Adresse Données                 Ascii
2000    ........
...
FF40    ........
FF48    ........
FF50    ........
MOV [BX+SI+2],0 AX=
BX=
CX=
DX=
SI=
DI=
BP=
SP=
Adresse Données                 Ascii
2000    ........
...
FF40    ........
FF48    ........
FF50    ........
MOV [BP+DI],1 AX=
BX=
CX=
DX=
SI=
DI=
BP=
SP=
Adresse Données                 Ascii
2000    ........
...
FF40    ........
FF48    ........
FF50    ........

Dans ce code, les pointeurs sont supposés NEAR (intra-segment). Imaginer le code assembleur généré par un compilateur C pour les deux instructions en caractères gras :

/* type */
struct Entry {
    char *name;
    char *phoneNumber;
};
/* variables globales */
struct Entry directory[100];
struct Entry newEntry;

/* extrait d'une fonction */
    directory[i].name = newEntry.name;
    directory[i].phoneNumber = newEntry.phoneNumber;

III. Structures de contrôle (3 points)

Le code assembleur suivant a été généré par un compilateur C. Imaginer les déclarations et les instructions C qui sont à l'origine de cette génération de code. Pour répondre à la question, utiliser les noms de constante et de variable utilisés en assembleur.

    cmp v1,FALSE
    je  etiq0
    mov bx,offset v3
    mov v2,0
etiq1:
    cmp v2,CONST1
    jge etiq2
    mov si,v2
    add si,si
    mov [bx+si],NULL
    inc v2
    jmp etiq1
etiq2:
    mov v1,FALSE
etiq0:

IV. Passage des arguments (4 points)

La fonction suivante est supposée être un sous-programme NEAR (appel intra-segment). Rien qu'en examinant son en-tête, il est possible de dessiner l'état de la pile qu'elle manipule.

int checkMin( int tab[100], int min )
{
    int i;
    ...
    return min;
}

1. Dessiner le contexte de pile complètement annoté, manipulé par la fonction checkMin. Il n'est pas demandé de traduction en assembleur de l'implantation de la fonction checkMin.

Dans le même programme, on considère la fonction main qui appelle la fonction checkMin.

int main()
{
    int tmp[100];
    int minValue;
    getData( tmp );
    minValue = tmp[0];

    minValue = checkMin( tmp, minValue );

    printf( "Le minimum est %d\n", minValue );
    return 0;
}

2. Imaginer le code généré par un compilateur C pour implanter le comportement de l'instruction minValue = checkMin( tmp, minValue );

V. Parallélisme (3 points)

On cherche à compléter le service de parallélisme étudié dans le TD5 (cf. code de la fonction schedule ci-dessous réalisant un ordonnancement circulaire entre 10 processus) Il s'agit de fournir l'implantation de la procédure createProcess qui initialise le contexte et la pile d'un nouveau processus, afin qu'il participe à l'ordonnancement. Pour fixer les idées, on utilise cette procédure de la façon suivante :

#define MAX_PROC 10

createProcess( 0, proc0, SS_PROC0, 32000 );
createProcess( 1, proc1, SS_PROC1, 32000 );
...
createProcess( 9, proc9, SS_PROC9, 32000 );
start( 0 );

On voit que, dans un premier temps, on initialise le contexte des processus proc0 à proc9 puis une procédure start démarre l'ordonnancement par le processus de numéro 0.

On spécifie createProcess de la façon suivante :
Le paramètre numProc est le numéro de processus.
Le paramètre processBeginAdress est un pointeur far contenant l'adresse de la première instruction du processus.
Le paramètre stackSeg contient la partie segment de l'adresse de début du segment de pile du processus.
Le paramètre stackSize contient la taille du segment de pile.

typedef void Process_type();

void createProcess( int numProc, Process_type far *processBeginAddress, int stackSeg, int stackSize )
{
    // à compléter
}

Les processus proc0 à proc9 sont disciplinés. Ils sont donc supposés contenir :

        pushf
        callf    _schedule

afin de ne pas conserver le processeur indéfiniment.

Question : proposer une implantation pour createProcess.

Annexe

Extrait du TD 5
void far * tab_Proc[MAX_PROC];    // contains far stack pointers for processes
int currentProc = 0;

...
        pushf
        callf   _schedule
...

void schedule() asm {
// save calling process context (flags, CS, IP already stacked)
        push    ax
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        push    bp
        push    es
        push    ds
// load scheduler ds value
        mov     ax,SEG tab_Proc
        mov     ds,ax
// tab_Proc[currentProc] = calling process SS:SP value
        mov     bx,OFFSET tab_Proc
        mov     si,currentProc
        mov     di,si
        add     di,di
        add     di,di
        mov     [bx+di],sp
        mov     ax,ss
        mov     [bx+di+2],ax
// currentProc = (currentProc+1) % MAX_PROC
        inc     si
        cmp     si,MAX_PROC
        jne     fsi0
        xor     si,si
fis0:   mov     currentProc,si
// SS:SP = tab_Proc[currentProc]
        add     si,si
        add     si,si
        mov     sp,[bx+si]
        mov     ax,[bx+si+2]
        mov     ss,ax
// restore new elected process context
        pop     ds
        pop     es
        pop     bp
        pop     di
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        iret
}